#include "stdafx.h"
#include "Observer.h"
#include "../../PerceptualState/Locations/Static/Shape/CoordinatesLocation.h"
#include "../../DecisionMaking/Layer1Reactive/Layer1FSM/Behaviors/General/Move/UnitMove/ThreatAwareUnitMoveBehavior.h"
#include "../../PerceptualState/PerceptualState.h"
#include "../../DecisionMaking/Layer1Reactive/Layer1FSM/Pathfinding.h"
#include "../../DecisionMaking/Layer1Reactive/Layer1FSM/Behaviors/General/Move/UnitMove/UnitMoveBehavior.h"
#include <BWAPI.h>

namespace OSHF
{
  inline Location* MakeLocation(int x, int y)
  {
    return new CoordinatesLocation(BWAPI::Position((x * TILE_SIZE) + (TILE_SIZE / 2), (y * TILE_SIZE) + (TILE_SIZE / 2)));
  }

  void addLocation(LocationsList & pos, const Component & owner)
  {
    typedef AutoPtr<Location> LocationPtr;
    //Insertion des différents point à rejoindre     
    pos.push_back(LocationPtr(owner, MakeLocation(9, 3)));  //Test#1, ligne droite
    pos.push_back(LocationPtr(owner, MakeLocation(63, 11))); //Test#2, Une tourelle
    pos.push_back(LocationPtr(owner, MakeLocation(120, 8))); //Test#3, Un guet-apens de tourelles
    pos.push_back(LocationPtr(owner, MakeLocation(113, 48))); //Test#4, Des marines sans détections
    pos.push_back(LocationPtr(owner, MakeLocation(115, 81))); //Test#5, Des marines, un science vessel en patrouille
    pos.push_back(LocationPtr(owner, MakeLocation(111, 111))); //Test#6, Un science vessel en patrouille qui fonce sur l'observer
    
    pos.push_back(LocationPtr(owner, MakeLocation(10, 116))); //Test#8, Une base ennemie!
  }
} //End namespace OSHF

lookahead_t ObserverScenario::_lookahead[] = {0, 128, 256, 512, 1024};

ObserverScenario::~ObserverScenario()
{
}

void ObserverScenario::onSparStarted(void*)
{
  const int OBSERVER_COUNT = 100;

  const std::set<BWAPI::Unit*>& units = BWAPI::Broodwar->self()->getUnits();

  int i = 0;
  // Scout
  for (std::set<BWAPI::Unit*>::const_iterator it = units.begin();
       it != units.end() && i < OBSERVER_COUNT;
       ++it)
  {
    BWAPI::Unit* unit = (*it);
    if (unit->getType() == BWAPI::UnitTypes::Protoss_Observer){
      OSHF::ObserverState* os = new OSHF::ObserverState(unit, m_pos.begin(), 0, 0); //_lookahead[i]);
      sendNewDestination(os); 
      ++i;
    }
  }
}

void ObserverScenario::onLocationReached(void* rawState)
{
  OSHF::ObserverState* unitState = static_cast<OSHF::ObserverState*>(rawState);
  BWAPI::Unit* unit = unitState->_obs;

  if(!_isEnded && !BWAPI::isDestroyed(unit) && (unit->getType() == BWAPI::UnitTypes::Protoss_Observer))
  {
    sendNewDestination(unitState);
  }
}

void ObserverScenario::onEnd()
{
  _isEnded = true;
  /*for(std::vector<Process*>::iterator itt = _behaviors.begin(); itt != _behaviors.end(); ++itt)
  {
    if((*itt) != 0)
      (*itt)->externalTerminate();
  }*/
  SPAR_LOG(LogTypes.LAYER_1_DECISION, "OnEnd Observer"); 
}

void ObserverScenario::sendNewDestination(OSHF::ObserverState* os)
{
  OSHF::LocationIterator loc = os->_currentPos;
  
  if(loc == m_pos.end())
    return;

  UnitMoveBehavior::MoveOptions options(
    pathfinding::GeneralThreatEvaluator(os->_obs),
    pathfinding::ConsiderThreatAsObstacle(os->_obs), 
    os->_lookahead,         // lookahead
    TILE_SIZE * 2,          // max distance
    4,                      // refresh rate
    150,                    // giving up delay
    5.0,                    // move weight
    true,                   // threat-aware
    false);                 // attack-move
  ThreatAwareUnitMoveBehavior* behavior = new ThreatAwareUnitMoveBehavior(this, 100, os->_obs, (*loc)->getCurrentCenter(), options);
  _behaviors.push_back(behavior);
  OSHF::ObserverState * nos = new OSHF::ObserverState(os->_obs, ++os->_currentPos, ++os->_defi, os->_lookahead);

  delete os;

  behavior->getTerminateEvent().subscribe(&m_onTerminateHandler, nos);

  behavior->zombifyOnTerminate();
  behavior->start();
}

