#pragma once
#include "../../../../PerceptualState/Locations/Dynamic/UnitCircularLocation.h"
#include "../Behaviors/UnitBehavior.h"
#include "../Conditions/InDanger.h"
#include "../Conditions/HasCriticalHealth.h"
#include "../Conditions/ReachedDestination.h"
#include "../Conditions/AtLeastOneUnit.h"
#include "../Conditions/CompositeCondition.h"
#include "../Commands/MoveCommand.h"

class DodgeBehavior : public UnitBehaviorT<DodgeBehavior>
{
protected:
  class Safe;
  class Critical;
  friend class Safe;
  friend class Critical;

  class Safe : public BehaviorStateT<DodgeBehavior, Safe>
  {
  public:
    Safe(DodgeBehavior& behavior);
    void onEnter();
    void onExit();

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

    typedef SCHEDULER_EVENT_HANDLER(Safe, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<Safe, HasCriticalHealth, NoTransitionAction, Critical>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions

    // Transitions
    TimerEvent m_timerEvent;
    Transition<Safe, HasCriticalHealth, NoTransitionAction, Critical> m_transition;
  };

  class Critical : public BehaviorStateT<DodgeBehavior, Critical>
  {
    typedef CompositeCondition<HasCriticalHealth,InDanger> ShouldBeDodging;

  public:
    Critical(DodgeBehavior& behavior);
    void onEnter();
    void onExit();

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

    typedef SCHEDULER_EVENT_HANDLER(Critical, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<Critical, InDanger, NoTransitionAction, Critical>&,
      Transition<Critical, Not<ShouldBeDodging>, NoTransitionAction, Safe>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //MoveCommand m_moveCommand;

    // Transitions
    TimerEvent m_timerEvent;
    Transition<Critical, InDanger, NoTransitionAction, Critical> m_transitionToSelf;
    Transition<Critical, Not<ShouldBeDodging>, NoTransitionAction, Safe> m_transitionToSafeState;
  };


public:
  DodgeBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* dodgingUnit)
    : UnitBehaviorT(parent, initialPriority, dodgingUnit)
    , UnitBehavior(parent, initialPriority, dodgingUnit)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_safeState(*this)
    , m_criticalState(*this)
    , m_states(m_safeState, m_criticalState)
  {
  }

  typedef boost::tuple<
      Safe&,
      Critical&
    > States;
	const States m_states;

  static BWAPI::Position getSafeDodgePosition(BWAPI::Unit* unit);

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

  // Arguments

  // Variables

  // States
  Safe m_safeState;
  Critical m_criticalState;
};
