#pragma once
#include "../../../Behaviors/GroupBehavior.h"
#include "../../../Conditions/AllPickedUp.h"
#include "../../../Conditions/ReachedDestination.h"
#include "../../../Commands/MoveCommand.h"
#include "../../../Commands/LoadUnitCommand.h"
#include "../../../../../../Scheduler/SchedulerTaskHelper.h"

template <class UnitGroup>
class PairBroken : public Condition
{
public:
  PairBroken(UnitGroup& units)
    : m_units(units)
  {
  }

  bool evaluate() const
  {
    // Ahem
    return false;
  }

protected:
  UnitGroup& m_units;
private:
  PairBroken & operator=(const PairBroken &);
};

/**
* @brief ReaverShuttleGroupBehavior is a reaver/shuttle group behavior
*/
class ReaverShuttleGroupBehavior : public GroupBehaviorT<ReaverShuttleGroupBehavior>
{
protected:
  class SetPairs;
  class PickUp;
  class SendToTarget;
  class AttackPhase;
  class RemoveUnit;
  friend class SetPairs;
  friend class PickUp;
  friend class SendToTarget;
  friend class AttackPhase;
  friend class RemoveUnit;

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

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

    typedef SCHEDULER_EVENT_HANDLER(SetPairs, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<SetPairs, NoCondition, NoTransitionAction, PickUp>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions

    // Transitions
    TimerEvent m_event;
    Transition<SetPairs, NoCondition, NoTransitionAction, PickUp> m_transitionToPickUpState;
  };

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

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

    typedef SCHEDULER_EVENT_HANDLER(PickUp, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<PickUp, AllPickedUp<std::set<BWAPI::Unit*>>, NoTransitionAction, SendToTarget>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //LoadUnitCommand m_loadUnitCommand;

    // Transitions
    TimerEvent m_event;
    Transition<PickUp, AllPickedUp<std::set<BWAPI::Unit*>>, NoTransitionAction, SendToTarget> m_transitionToSendToTargetState;
  };

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

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

    typedef SCHEDULER_EVENT_HANDLER(SendToTarget, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<SendToTarget, GroupReachedPosition<std::set<BWAPI::Unit*>>, NoTransitionAction, AttackPhase>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions
    //MoveCommand m_moveCommand;

    // Transitions
    TimerEvent m_event;
    Transition<SendToTarget, GroupReachedPosition<std::set<BWAPI::Unit*>>, NoTransitionAction, AttackPhase> m_transitionToAttackPhaseState;
  };

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

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

    typedef SCHEDULER_EVENT_HANDLER(AttackPhase, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<AttackPhase, PairBroken<std::set<BWAPI::Unit*>>, NoTransitionAction, RemoveUnit>&
    > Transitions;
		const Transitions m_transitions;

  protected:
    // Variables

    // Actions

    // Transitions
    TimerEvent m_event;
    Transition<AttackPhase, PairBroken<std::set<BWAPI::Unit*>>, NoTransitionAction, RemoveUnit> m_transitionToRemoveUnitState;
  };

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

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

    typedef SCHEDULER_EVENT_HANDLER(RemoveUnit, onTimer) TimerEvent;

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

    typedef boost::tuple<
      Transition<RemoveUnit, PairBroken<std::set<BWAPI::Unit*>>, NoTransitionAction, RemoveUnit>&
    > Transitions;
		const Transitions m_transitions; 

  protected:
    // Variables

    // Actions

    // Transitions
    TimerEvent m_event;
    Transition<RemoveUnit, PairBroken<std::set<BWAPI::Unit*>>, NoTransitionAction, RemoveUnit> m_transitionToSelf; 
  };


public:
  ReaverShuttleGroupBehavior(const Process* parent, unsigned int initialPriority, const PersistentUnitGroup* reavers, const PersistentUnitGroup* shuttles, BWAPI::Position enemyBase)
    : GroupBehaviorT(parent, initialPriority, shuttles)
    , GroupBehavior(parent, initialPriority, shuttles)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_setPairsState(*this), m_pickUpState(*this), m_sendToTargetState(*this)
    , m_attackPhaseState(*this), m_removeUnitState(*this)
    , m_enemyBase(enemyBase)
    , m_states(m_setPairsState, m_pickUpState, m_sendToTargetState, m_attackPhaseState, m_removeUnitState)
  {
    m_reavers = &a;
    m_shuttles = &b;

    for(PersistentUnitGroup::const_iterator it = reavers->begin();it!=reavers->end();it++){
      m_reavers->insert((*it));
    }
    for(PersistentUnitGroup::const_iterator it = shuttles->begin();it!=shuttles->end();it++){
      m_shuttles->insert((*it));
    }
    //m_reavers = reavers;
    //m_shuttles = shuttles;
    m_pairs = std::map<BWAPI::Unit*,BWAPI::Unit*>();
  }

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

  virtual void onStart()
  {
    GroupBehaviorT::onStart();
    m_setPairsState.enter();
  }

  virtual void onUnitAddedToGroup(void* data, BWAPI::Unit* unit)
  {
    unused(data);
    unused(unit);
  }

  virtual void onUnitRemovedFromGroup(void* data, BWAPI::Unit* unit)
  {
    unused(data);
    unused(unit);
  }

  // Arguments

  // Variables
  BWAPI::Position m_enemyBase;
  std::map<BWAPI::Unit*,BWAPI::Unit*> m_pairs;
public:
  std::set<BWAPI::Unit*>* m_reavers;
  std::set<BWAPI::Unit*>* m_shuttles;
  std::set<BWAPI::Unit*> a;
  std::set<BWAPI::Unit*> b;

  typedef boost::tuple<
      SetPairs&,
      PickUp&,
      SendToTarget&,
      AttackPhase&,
      RemoveUnit&
    > States;
	const States m_states;

protected:
  // States
  SetPairs m_setPairsState;
  PickUp m_pickUpState;
  SendToTarget m_sendToTargetState;
  AttackPhase m_attackPhaseState;
  RemoveUnit m_removeUnitState;
};