#include "stdafx.h"
#include "MotionScoutBehavior.h"
#include "../Move/UnitMove/ThreatAwareUnitMoveBehavior.h"
#include "../Move/UnitMove/NativeUnitMoveBehavior.h"
#include "../../../Layer1FSM.h"
#include "../../../../../../PerceptualState/PerceptualState.h"
#include "../../../../../../PerceptualState/Locations/Static/AutoPopulated/Chokepoint.h"
#include <functional>

MotionScoutBehavior::MotionScoutBehavior(const Process* parent, unsigned int initialPriority, StaticLocation* location, BWAPI::Unit* scoutingUnit, lookahead_t lookahead)
  : ScoutBehaviorT(parent, initialPriority, location, scoutingUnit)
  , ScoutBehavior(parent, initialPriority, location, scoutingUnit)
  , UnitBehavior(parent, initialPriority, scoutingUnit)
  , Behavior(parent, initialPriority)
  , FSM(parent)
  , Process(parent)
  //, m_reachedState(*this)
  , m_goToLocationState(*this)
  , m_states(m_goToLocationState/*, m_reachedState*/)
  , m_lookahead(lookahead)
  , m_scoutArrivedEventRaised(false)
{
}

///////////////////////////////////////////////////
// GoToLocation State
///////////////////////////////////////////////////

BWAPI::Position MotionScoutBehavior::GoToLocation::getNextPositionToScout() const
{
  BWAPI::TilePosition tile = BWAPI::TilePositions::None;
  if (m_success)
    tile = m_context.m_locationToScout->getOldestVisibleTile().first;
  if (tile == BWAPI::TilePositions::None)
    tile = m_context.m_locationToScout->getRandomTile();
  return BWAPI::getCenter(tile);
}

Behavior* MotionScoutBehavior::GoToLocation::createSubBehavior()
{
  const BWAPI::Position nextPositionToScout = getNextPositionToScout();
  assert(nextPositionToScout != BWAPI::TilePositions::None);

  const size_t maxDistance = std::min(DEFAULT_UNIT_MAX_DISTANCE, std::max(0, m_context.m_unit->getPosition().getApproxDistance(nextPositionToScout) - 1));

  const BWAPI::UnitType& type = m_context.m_unit->getType();
  if (!type.isFlyer() && !m_context.m_scoutArrivedEventRaised)
  {
    //TODO: temporary fix to allow probes to reach the base location, since ground pathfinding doesn't work
    UnitMoveBehavior::MoveOptions options = NativeUnitMoveBehavior::getDefaultMoveOptions(
      maxDistance,            // max distance
      2,                      // refresh rate
      30);                    // giving up delay
    return new NativeUnitMoveBehavior(
      &m_context, 
      m_context.getCurrentPriority(), 
      m_context.m_unit, 
      nextPositionToScout, 
      UnitMoveBehavior::getDefaultMoveOptions());
  }
  else
  {
    UnitMoveBehavior::MoveOptions options = ThreatAwareUnitMoveBehavior::getDefaultMoveOptions(
      pathfinding::GeneralThreatEvaluator(m_context.m_unit), 
      pathfinding::ConsiderThreatAsObstacle(m_context.m_unit), 
      m_context.m_lookahead,  // lookahead
      maxDistance,            // max distance
      2,                      // refresh rate
      30);                    // giving up delay
    return new ThreatAwareUnitMoveBehavior(
      &m_context, 
      m_context.getCurrentPriority(), 
      m_context.m_unit, 
      nextPositionToScout, 
      options);
  }
}

void MotionScoutBehavior::GoToLocation::onEnter()
{
  if (!m_context.m_scoutArrivedEventRaised)
  {
    m_frameEvent.activate();
  }
  WrapperState::onEnter();
}

void MotionScoutBehavior::GoToLocation::onExit()
{
  m_frameEvent.deactivate();
  WrapperState::onExit();
}

void MotionScoutBehavior::GoToLocation::onFrame()
{
  if (m_context.m_locationToScout->isInLocation(m_context.m_unit))
  {
    m_context.m_scoutArrivedEvent.raise();
    m_context.m_scoutArrivedEventRaised = true;
    m_frameEvent.deactivate();
  }
}

void MotionScoutBehavior::GoToLocation::onSubBehaviorTerminated()
{
  m_success = (m_subBehavior->getCurrentMode() == Process::Success);
  WrapperState::onSubBehaviorTerminated();
}