#pragma once
#include "UnitAttackBehavior.h"
#include "../../../../../Commands/MoveCommand.h"

class DragoonUnitAttackBehavior : public UnitAttackBehaviorT<DragoonUnitAttackBehavior>
{
  class Engaging;
  class Fleeing;
  class Idling;

public:
  DragoonUnitAttackBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* unit);

  bool selectTarget(const std::set<BWAPI::Unit*>& enemies);

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

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

private:
  //BWAPI::Unit* selectTargetImpl(const std::set<BWAPI::Unit*>& enemies);

  BWAPI::Unit* m_target;

  // Engaging state ////////////////////////////////////////////////////////////
  class Engaging : public BehaviorStateT<DragoonUnitAttackBehavior, Engaging>
  {
  public:
    Engaging(DragoonUnitAttackBehavior& behavior);
    void onEnter();
    void onExit();

    void onTimer();

    void targetChanged(BWAPI::Unit* oldTarget);
  private:    
    void onTargetEvaded(void*);

    //AttackUnitCommand m_attackAction;

    typedef Transition<Engaging, NoCondition, NoTransitionAction, Idling> IdlingTransition;
    IdlingTransition m_idlingTransition;

    typedef Transition<Engaging, CompositeCondition<HasCriticalHealth,IsWorthFleeing>, NoTransitionAction, Fleeing> LowHealthTransition;
    LowHealthTransition m_lowHealth;

    typedef SCHEDULER_EVENT_HANDLER(Engaging, onTimer) TimerEvent;
    TimerEvent m_timerEvent;

    BWAPI::OnIndividualUnitEvade::SubscriberID m_targetEvadedId;    
    EVENT_HANDLER(Engaging, onTargetEvaded) m_targetEvadedEventHandler;

  public:
    typedef boost::tuple<
    > Events;
    const Events m_events;

    typedef boost::tuple<
      IdlingTransition&,
      LowHealthTransition&
    > Transitions;
    const Transitions m_transitions;
  };

  // Fleeing state /////////////////////////////////////////////////////////////
  class Fleeing : public BehaviorStateT<DragoonUnitAttackBehavior, Fleeing>
  {
  public:
    Fleeing(DragoonUnitAttackBehavior& behavior);
    void onEnter();
    void onExit();

    void onTimer();

  private:
    //MoveCommand m_moveCommand;

    typedef Transition<Fleeing, Not<IsTargeted>, NoTransitionAction, Idling> NotTargetedTransition;
    NotTargetedTransition m_transition;

    typedef SCHEDULER_EVENT_HANDLER(Fleeing, onTimer) TimerEvent;
    TimerEvent m_timerEvent;

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

    typedef boost::tuple<
      NotTargetedTransition&
    > Transitions;
    const Transitions m_transitions;
  };
  
  // Idling state //////////////////////////////////////////////////////////////
  class Idling : public BehaviorStateT<DragoonUnitAttackBehavior, Idling>
  {
  public:
    Idling(DragoonUnitAttackBehavior& behavior);
    void onEnter() {}
    void onExit() {}

    void onTargetChanged();

  private:
    typedef Transition<Idling, NoCondition, NoTransitionAction, Engaging> EngagingTransition;
    EngagingTransition m_engagingTransition;
    
  public:
    typedef boost::tuple<> Events;
    const Events m_events;

    typedef boost::tuple<
      EngagingTransition&
    > Transitions;
    const Transitions m_transitions;
  };

  // Variables

  // States
  Engaging m_engagingState;
  Fleeing m_fleeingState;
  Idling m_idlingState;

public:
  typedef boost::tuple<
    Engaging&,
    Fleeing&,
    Idling&
  > States;
  const States m_states;
};