#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"
#include "../../../Commands/AttackUnitCommand.h"

class NotNull : public Condition
{
public:
  NotNull(BWAPI::Unit** unit)
    : m_unit(unit)
  {}
  bool evaluate()
  {
	  return (*m_unit) != NULL;
  }

protected:
  BWAPI::Unit** m_unit;

};

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

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

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

    typedef SCHEDULER_EVENT_HANDLER(Moving, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<Moving, NotNull, NoTransitionAction, Safe>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions

    // Transitions
    TimerEvent m_update;
    Transition<Moving, NotNull, NoTransitionAction, Safe> m_transition;
  };

  class Safe : public BehaviorStateT<UnitCarefulAttackBehavior, Safe>
  {
    typedef CompositeCondition<HasCriticalHealth,InDanger> ShouldBeDodging;

  public:
    Safe(UnitCarefulAttackBehavior& 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, ShouldBeDodging, NoTransitionAction, Critical>&
    > Transitions;
		const Transitions m_transitions;

    void orderAttack();

  protected:
    // Variables

    // Actions
    //AttackUnitCommand m_attackAction;

    // Transitions
    TimerEvent m_update;
    Transition<Safe, ShouldBeDodging, NoTransitionAction, Critical> m_transition;
  };

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

    void onTimer()
    {
      m_transitionToSafeState.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, NoCondition, NoTransitionAction, Safe>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //MoveCommand m_moveCommand;

    // Transitions
    TimerEvent m_update;
    Transition<Critical, NoCondition, NoTransitionAction, Safe> m_transitionToSafeState;
  };


public:
  UnitCarefulAttackBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* dodgingUnit, const PersistentUnitGroup* group)
    : UnitBehaviorT(parent, initialPriority, dodgingUnit)
    , UnitBehavior(parent, initialPriority, dodgingUnit)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_movingState(*this)
    , m_safeState(*this)
    , m_criticalState(*this)
    , m_group(group)
    , m_target(NULL)
    , m_states(m_movingState, m_safeState, m_criticalState)
  {
  }

  void setTarget(BWAPI::Unit* target)
  {
    m_target = target;
    if(getCurrentState() == &m_safeState)
    {
      m_safeState.orderAttack();
    }
  }

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

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

  // Actions

  // Arguments

  // Variables
  //std::set<BWAPI::Unit*> m_enemyUnitsCache;
  BWAPI::Unit* m_target;
  const PersistentUnitGroup* m_group;

  // States
  Moving m_movingState;
  Safe m_safeState;
  Critical m_criticalState;
};
