#pragma once
#include "../Conditions/ReachedDestination.h"
#include "../Commands/MoveCommand.h"
#include "../../../../Scheduler/SchedulerTaskHelper.h"
#include "../Behaviors/General/Scout/ScoutBehavior.h"

/**
 * @brief The GradientDescentScoutBehavior uses gradient-descent (local optimization) methods to 
 *        perform scouting.
 */
class GradientDescentScoutBehavior : public ScoutBehaviorT<GradientDescentScoutBehavior>
{
protected:
  class GoToLocation;
  class Scouting;
  friend class GoToLocation;
  friend class Scouting;

  //State where the scout goes to the requested location
  class GoToLocation : public BehaviorStateT<GradientDescentScoutBehavior, GoToLocation>
  {
  public:
    GoToLocation(GradientDescentScoutBehavior& behavior);
    void onEnter();
    void onExit(){}

    void onTimer()
    {
      m_transitionToScouting.testTransition(boost::make_tuple());
    }

    typedef SCHEDULER_EVENT_HANDLER(GoToLocation, onTimer) TimerEvent;

    typedef boost::tuple<
          TimerEvent&
          > Events;
		Events m_events;
    
		typedef boost::tuple<
          Transition<GoToLocation, UnitReachedLocation, RaiseScoutArrived, Scouting>&
		  > Transitions;
		Transitions m_transitions;

	protected:
    //Variable
    
    // Actions
		//MoveCommand m_moveCommand;

    //temp event and transition
    TimerEvent m_locationReached;
		Transition<GoToLocation, UnitReachedLocation, RaiseScoutArrived, Scouting> m_transitionToScouting;
  };

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

    void onTimer()
    {
      m_transitionToSelf.testTransition(boost::make_tuple());
    }

    typedef SCHEDULER_EVENT_HANDLER(Scouting, onTimer) TimerEvent;

    typedef boost::tuple<
        TimerEvent&
      > Events;
		const Events m_events;
    
    typedef boost::tuple<
        Transition<Scouting, NoCondition, NoTransitionAction, Scouting>&
      > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables
    const int m_maxX;
    const int m_maxY;

    // Actions
    //MoveCommand m_moveCommand;

    // Transitions
    TimerEvent m_newMove;
    Transition<Scouting, NoCondition, NoTransitionAction, Scouting> m_transitionToSelf;

    //Other
    BWAPI::Position getFleeDestination(double fleeX, double fleeY);
  };

public:
  GradientDescentScoutBehavior(const Process* parent, unsigned int initialPriority, StaticLocation* location, BWAPI::Unit* scoutingUnit);

  typedef boost::tuple<
      GoToLocation&,
      Scouting&
    > States;
	const States m_states;

protected:
  virtual void _output(std::ostream& out) const
  {
    out << "GradientDescentScoutBehavior(" << *m_unit << ")";
  }

  virtual void onStart()
  {
    UnitBehaviorT::onStart();
    //m_scoutingState.enter();
    m_goToLocationState.enter();
  }

  // Arguments

  // Variables
  //BWAPI::Position m_enemyCC;
  //BWTA::Region* m_baseRegion;

  // States
  GoToLocation m_goToLocationState;
  Scouting m_scoutingState;
};