#pragma once
#include "../../../../PerceptualState/Locations/Dynamic/UnitCircularLocation.h"
#include "../Conditions/IsIdle.h"
#include "../Conditions/AtLeastOneUnit.h"
#include "../Behaviors/UnitBehavior.h"
#include "../Commands/MoveCommand.h"
#include "../Commands/StopCommand.h"
#include "../../../../Scheduler/SchedulerTaskHelper.h"

/**
 * @brief The AvoidEnemiesBehavior commands a particular unit to flee when enemies are around.
 */
class AvoidEnemiesBehavior : public UnitBehaviorT<AvoidEnemiesBehavior>
{
protected:
  class Idle;
  class Avoiding;
  class ReadyToAvoid;
  friend class Idle;
  friend class Avoiding;
  friend class ReadyToAvoid;

  /**
   * @brief The Idle state is active when no enemies are around.
   */
  class Idle : public BehaviorStateT<AvoidEnemiesBehavior, Idle>
  {
  public:
    Idle(AvoidEnemiesBehavior& behavior);
    void onEnter();
    void onExit() {}

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

    typedef SCHEDULER_EVENT_HANDLER(Idle, onTimer) TimerEvent;

    typedef boost::tuple<
        TimerEvent&
      > Events;
		const Events m_events;
    
    typedef boost::tuple<
        Transition<Idle, IsUnitIdle, NoTransitionAction, ReadyToAvoid>&
      > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //StopCommand m_stopCommand;

    // Transitions
    TimerEvent m_timerEvent;
    Transition<Idle, IsUnitIdle, NoTransitionAction, ReadyToAvoid> m_transitionToReadyState;
  };

  /**
   * @brief The ReadyToAvoid state is waiting for enemy to be detected.
   */
  class ReadyToAvoid : public BehaviorStateT<AvoidEnemiesBehavior, ReadyToAvoid>
  {
  public:
    ReadyToAvoid(AvoidEnemiesBehavior& behavior);
    void onEnter();
    void onExit() {}

    void onTimer();

    typedef SCHEDULER_EVENT_HANDLER(ReadyToAvoid, onTimer) TimerEvent;

    typedef boost::tuple<
        TimerEvent&
      > Events;
		const Events m_events;
    
    typedef boost::tuple<
        Transition<ReadyToAvoid, AtLeastOneUnit, NoTransitionAction, Avoiding, EventHandler1<const std::set<BWAPI::Unit*>&>>&
      > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions

    // Transitions
    TimerEvent m_timerEvent;
    Transition<ReadyToAvoid, AtLeastOneUnit, NoTransitionAction, Avoiding, EventHandler1<const std::set<BWAPI::Unit*>&>> m_transitionToAvoidingState;
  };

  /**
   * @brief The Avoiding state is active when fleeing from enemies.
   */
  class Avoiding : public BehaviorStateT<AvoidEnemiesBehavior, Avoiding>
  {
  public:
    Avoiding(AvoidEnemiesBehavior& behavior);
    void onEnter();
    void onExit() {}

    void onTimer();

    typedef SCHEDULER_EVENT_HANDLER(Avoiding, onTimer) TimerEvent;

    typedef boost::tuple<
        TimerEvent&
      > Events;
		const Events m_events;
    
    typedef boost::tuple<
        Transition<Avoiding, AtLeastOneUnit, NoTransitionAction, Avoiding, EventHandler1<const std::set<BWAPI::Unit*>&>>&,
        Transition<Avoiding, Not<AtLeastOneUnit>, NoTransitionAction, Idle, EventHandler1<const std::set<BWAPI::Unit*>&>>&
      > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //MoveCommand m_moveCommand;

    // Transitions
    TimerEvent m_timerEvent;
    Transition<Avoiding, AtLeastOneUnit, NoTransitionAction, Avoiding, EventHandler1<const std::set<BWAPI::Unit*>&>> m_transitionToSelf;
    Transition<Avoiding, Not<AtLeastOneUnit>, NoTransitionAction, Idle, EventHandler1<const std::set<BWAPI::Unit*>&>> m_transitionToIdle;
  };

public:
  AvoidEnemiesBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* avoidingUnit)
    : UnitBehaviorT(parent, initialPriority, avoidingUnit)
    , UnitBehavior(parent, initialPriority, avoidingUnit)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_idleState(*this), m_avoidingState(*this),m_readyToAvoidState(*this)
    , m_states(m_idleState, m_avoidingState, m_readyToAvoidState)
  {
  }

  typedef boost::tuple<
      Idle&,
      Avoiding&,
      ReadyToAvoid&
    > States;
	const States m_states;

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

  // Arguments

  // Variables
  std::set<BWAPI::Unit*> m_enemyUnits;

  // States
  Idle m_idleState;
  Avoiding m_avoidingState;
  ReadyToAvoid m_readyToAvoidState;
};
