#include "stdafx.h"
#include "FocusFireBehavior.h"
#include "../../Layer1FSM.h"
#include "../../../../../PerceptualState/PerceptualState.h"
#include <BWAPI.h>

///////////////////////////////////////////////////
// Engaging state
///////////////////////////////////////////////////

FocusFireBehavior::Engaging::Engaging(FocusFireBehavior& behavior)
  : BehaviorStateT(behavior)
  , m_unitDestroyedEventHandler(*this)
  //, m_attackAction(*this)
  , m_timerEvent(*this, Scheduler::FSM_SCHEDULING_PRIORITY, 10, 10)
	, m_events(m_timerEvent)
  , m_transitions(/*m_transitionToSelf*/)
  /*, m_transitionToSelf(
      *this,
      m_enemyUnitsInLocationEvent,
      NoCondition(), 
      NoTransitionAction(),
      *this)*/
{
}

FocusFireBehavior::Engaging::~Engaging()
{
}

void FocusFireBehavior::Engaging::onEnter()
{
  m_context.m_enemyUnits = Spar->getPerceptualState()->getEnemyUnits(GroupRectangularLocation(m_context.getGroup()));
  for(PersistentUnitGroup::const_iterator it=m_context.getGroup()->begin(); it != m_context.getGroup()->end(); ++it)
  {
	  BWAPI::Unit* unit = *it;
	  DodgeBehavior* newBehavior = new DodgeBehavior(&m_context, m_context.getCurrentPriority() * 2 + 1,unit);
	  newBehavior->start();
  }
}

void FocusFireBehavior::Engaging::onUnitDestroyed(void*)
{
  //if (m_context.m_enemyUnits.size() != 0)
  //{
  //  findTargetAndFire();
  //}
  if (m_context.m_enemyUnits.size() == 0)
    m_context.terminate(BehaviorT::Success);
  else
    findTargetAndFire();
} 

void FocusFireBehavior::Engaging::onTimer()
{
  std::set<BWAPI::Unit*> enemyUnits = Spar->getPerceptualState()->getEnemyUnits(GroupRectangularLocation(m_context.getGroup()));

  assert(&enemyUnits == &m_context.m_enemyUnits);

  if (m_context.m_enemyUnits.size() == 0)
    m_context.terminate(BehaviorT::Success);
  else
    findTargetAndFire();
}

BWAPI::Unit* FocusFireBehavior::Engaging::getWeakest(const std::set<BWAPI::Unit*> &group)
{
  double minHp = boost::numeric::bounds<double>::highest();
  BWAPI::Unit* target = NULL;
  for (std::set<BWAPI::Unit*>::const_iterator it = group.begin(); it != group.end(); ++it)
  {
    BWAPI::Unit* unit = *it;
    const double hp = unit->getShields() + unit->getHitPoints();
    if (hp < minHp)
    {
      minHp = hp;
      target = unit;
    }
  }
  return target;
}

void FocusFireBehavior::Engaging::findTargetAndFire()
{
	static int iteration = 0;
	BWAPI::Position center = m_context.getGroup()->getCenter();

  BWAPI::Unit* nextTarget = getWeakest(m_context.m_enemyUnits);
	if(!nextTarget)
    nextTarget = GroupHelper::getNearest(m_context.m_enemyUnits, center);

	BWAPI::getIndividualUnitDestroyEvent(nextTarget).subscribe(&m_unitDestroyedEventHandler,0);

  Layer1FSM::getInstance().getArbitrator().
      submitCommand(m_context.getGroup(), AttackUnitCommand(*this, nextTarget), Arbitration::ActionImportance(m_context));
}

void FocusFireBehavior::Engaging::onExit()
{
}
