#pragma once
#include "../../Layer1FSM.h"
#include "../../Conditions/ReachedDestination.h"
#include "../../Conditions/BuildingStarted.h"
#include "../../Behaviors/UnitBehavior.h"
#include "../../Behaviors/Utils/FinalState.h"
#include "../../Commands/MoveCommand.h"
#include "../../Commands/BuildCommand.h"
#include "../../Commands/StopCommand.h"
#include "../../../../../Scheduler/SchedulerTaskHelper.h"

/**
* @brief The BuildBehavior builds a building at the specified location using the specified unit.
*/
class BuildBehavior : public UnitBehaviorT<BuildBehavior>
{
protected:
  class Goto;
  class Clear;
  class Build;
  typedef FinalState<BuildBehavior> FinalState;
  friend class Goto;
  friend class Clear;
  friend class Build;
  friend class FinalState;

  class Goto : public BehaviorStateT<BuildBehavior, Goto>
  {
    // Should eventually be replaced by a threat-aware move behavior
  public:
    Goto(BuildBehavior& behavior);
    void onEnter();
    void onExit() {}

    void onTimer();

    typedef SCHEDULER_EVENT_HANDLER(Goto, onTimer) TimerEvent;

    typedef boost::tuple<
      TimerEvent&
    > Events;
    const Events m_events;

    typedef boost::tuple<
      Transition<Goto, UnitReachedPosition, NoTransitionAction, Build>&
    > Transitions;
    const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //MoveCommand m_moveCommand;
    MoveCommand instantiateMoveCommand();

    // Transitions
    TimerEvent m_timerEvent;
    Transition<Goto, UnitReachedPosition, NoTransitionAction, Build> m_transitionToBuildState;
  };

  class Build : public BehaviorStateT<BuildBehavior, Build>
  {
  public:
    Build(BuildBehavior& behavior);
    void onEnter();
    void onExit() {}

    void onTimer();

    typedef SCHEDULER_EVENT_HANDLER(Build, onTimer) TimerEvent;

    typedef boost::tuple<
      TimerEvent&
    > Events;
    const Events m_events;

    typedef boost::tuple<
      Transition<Build, BuildingStarted, NoTransitionAction, FinalState>&
    > Transitions;
    const Transitions m_transitions;
  protected:
    // Variables
    int m_initialFrame;

    // Actions
    //BuildCommand m_buildAction;

    // Transitions
    TimerEvent m_timerEvent;
    Transition<Build, BuildingStarted, NoTransitionAction, FinalState> m_transitionToFinalState;
  };

public:
  BuildBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* buildingUnit, 
    BWAPI::TilePosition buildTile, BWAPI::UnitType buildingType, int nbFramesTimeout = 200);

  BWAPI::Unit* getBuilding() const
  {
    return m_building;
  }

  typedef boost::tuple<
      Goto&,
      Build&,
      FinalState&
    > States;
	const States m_states;

  static const TerminationMode TerminatedNoPower;
  static const TerminationMode TerminatedTimeout;

protected:
  virtual void _output(std::ostream& out) const
  {
    out << "BuildBehavior(" << m_buildingType << ", " << *m_unit << ", " << m_buildTile << ")";
  }

  virtual void onStart()
  {
    UnitBehaviorT::onStart();
    m_gotoState.enter();
  }

  virtual void onEnd()
  {
    if (getCurrentMode() == Process::ExternalEvent)
    {
      Layer1FSM::getInstance().getArbitrator().
        submitCommand(m_unit, StopCommand(*dynamic_cast<BehaviorState*>(getCurrentState())), Arbitration::ActionImportance(*this));
    }
    UnitBehaviorT::onEnd();
  }

  // Variables
  const BWAPI::TilePosition m_buildTile;
  const BWAPI::UnitType m_buildingType;
  const int m_nbFramesTimeout;
  BWAPI::Unit* m_building;

  // States
  Goto m_gotoState;  
  Build m_buildState;
  //Clear m_clearState;
  FinalState m_finalState;
};