#pragma once
#include "../../../../../../PerceptualState/Locations/Static/StaticLocation.h"
#include "../../UnitBehavior.h"

/**
 * @brief A scout behavior instructs a unit to go to some location (upon which the OnScoutArrived event is raised)
 *        and then to keep exploring the location.
 */
class ScoutBehavior : public virtual UnitBehavior
{
public:
  ScoutBehavior(const Process* parent, unsigned int initialPriority, StaticLocation* location, BWAPI::Unit* scoutingUnit)
    : UnitBehavior(parent, initialPriority, scoutingUnit)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_scoutArrivedEvent(*this)
    , m_locationToScout(*this, location)
  {
  }

  DECLARE_EVENT(OnScoutArrived);                           
  OnScoutArrived& getScoutArrivedEvent() const { return m_scoutArrivedEvent; }

protected:
  class RaiseScoutArrived : public TransitionAction
  {
  public:
    RaiseScoutArrived(ScoutBehavior* behavior)
      : m_behavior(behavior){}

    void execute()
    {
      m_behavior->getScoutArrivedEvent().raise();
    }

  protected:
    ScoutBehavior* const m_behavior;

  private:
    // const member prevent the use of the assigment operator
    RaiseScoutArrived& operator=(const RaiseScoutArrived&);
  };

  /**
   * @brief The location that must be scouted.
   */
  const AutoPtr<StaticLocation> m_locationToScout;

  /**
   * @brief The event to raise when the scout unit gets to the destination.
   */
  EVENT(OnScoutArrived) m_scoutArrivedEvent;
};

/**
 * @brief Base class for scouting behaviors.
 * @tparam DerivedBehavior The most derived scouting behavior class.
 */
template <class DerivedBehavior>
class ScoutBehaviorT : public virtual ScoutBehavior, public UnitBehaviorT<DerivedBehavior>
{
public:
  ScoutBehaviorT(const Process* parent, unsigned int initialPriority, StaticLocation* location, BWAPI::Unit* scoutingUnit)
    : UnitBehaviorT(parent, initialPriority, scoutingUnit)
    , ScoutBehavior(parent, initialPriority, location, scoutingUnit)
    , UnitBehavior(parent, initialPriority, scoutingUnit)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
  {
  }
};