#pragma once
#include "Layer3Process.h"
#include "../../../Layer2Actions/Interface/Actions/AttackMove.h"
#include "../../../Layer2Actions/Interface/Actions/Harass.h"
#include "../../../Layer2Actions/Interface/Actions/Defend.h"
#include "../../../Layer2Actions/Interface/Actions/Scout.h"
#include "../../../../Utils/Process/ProcessContainer.h"

class Region;
//
// Input: gas/mineral ratio
//

class ManageArmyProcess : public Layer3Process
{
private:
  struct UnitPower
  {
    UnitPower()
      : AttackPower(0)
      , HitPointPower(0)
    {}UnitPower(double attackPower, double hitPointPower)
      : AttackPower(attackPower)
      , HitPointPower(hitPointPower)
    {}
    double AttackPower;
    double HitPointPower;
  };

  struct RegionWrapper
  {
    RegionWrapper(Region* region)
      : region(region)
      , lastVisitedFrame(0)
      , fromRegion(NULL)
    {}
    Region* region;
    RegionWrapper* fromRegion;
    int lastVisitedFrame;
  };

public:
  ManageArmyProcess(const Process* parent);

  ~ManageArmyProcess()
  {
    for(stdext::hash_map<Region*, RegionWrapper*>::iterator it = m_regionWrappers.begin(); it != m_regionWrappers.end(); ++it)
    {
      delete (it->second);
    }
  }

  virtual void run();

  void addUnit(BWAPI::Unit* unit);

protected:
  virtual void _output(std::ostream& out) const
  {
    out << "Manage army";
  }

  virtual void onStart();

  Scout* instantiateNewScout(BWAPI::Unit* scout, StaticLocation* location);

  void onAttackMoveEnded(void* data);
  void onScoutArrived(void* data, Scout* action, StaticLocation* arrivedAtLocation, BWAPI::Unit* unit);

  RegionWrapper* getAttackLocation(RegionWrapper* fromRegion, UnitPower armyPower, bool canBeDetected, double groundRatio, double minSuperiorityRatio);
  double getSuperiorityRatio(const UnitPower& ownPower, const UnitPower& ennemyPower) const;
  UnitPower getRegionEnnemyPower(Region* region, bool canBeDetected, double groundOnlyRatio) const;
  UnitPower getUnitPower(BWAPI::UnitType unitType, bool ownUnit, bool canBeDetected, double groundOnlyRatio) const;
  
  BaseLocation* getEnemyMainBaseLocation() const;
  StaticLocation* getNextCorsairHarassLocation(BWAPI::Unit* corsair) const;
  void executeScout(BWAPI::Unit* unit);

  EVENT_HANDLER(ManageArmyProcess, onAttackMoveEnded) m_attackMoveEndedEventHandler;
  EVENT_HANDLER3(ManageArmyProcess, onScoutArrived, Scout*, StaticLocation*,BWAPI::Unit*) m_scoutArrivedEventHandler; 

  stdext::hash_map<Region*, RegionWrapper*> m_regionWrappers;
  RegionWrapper* m_mainRegion;
  RegionWrapper* m_goalRegionAttack;
  RegionWrapper* m_currentRegionAttack;

  // Actions
  ProcessContainer<AttackMove> m_attackAction;
  // Possibly other attack actions...
  ProcessContainer<Defend> m_defendAction;
  // Possibly other defend actions...
  ProcessContainerList<Scout> m_randomScouts;
  ProcessContainerList<Scout> m_enemyBaseScouts;
  int m_lastTriggeredScoutFrame;

  ProcessContainerList<Harass> m_corsairsHarass;

  // Groups
  //PersistentUnitGroup m_highTemplars;

  //PersistentUnitGroup m_attackingObservers;
  //PersistentUnitGroup m_defendingObservers;
  //PersistentUnitGroup m_scoutingObservers;
};
