#pragma once
#include "../GroupBehavior.h"
#include "../../../../../PerceptualState/PerceptualState.h"

// TODO: Fail when there is no more Nexus

/**
* @brief The GatherMineralsBehavior is a group behavior used to control probes mining minerals.
*/
class GatherMineralsBehavior : public GroupBehaviorT<GatherMineralsBehavior>
{
protected:
  class Mining;
  friend class Mining;

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

    void onTimer();

    void onUnitAddedToGroup(BWAPI::Unit* unit);

    typedef SCHEDULER_EVENT_HANDLER(Mining, onTimer) TimerEvent;

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

    typedef boost::tuple<> Transitions;
    const Transitions m_transitions;

  protected:
    void onNeutralBuildingRemoved(void* data, UnitRecord* crystal, BWAPI::UnitType, BWAPI::Player*);

    // Events
    Event<boost::tuples::tuple<UnitRecord*, BWAPI::UnitType, BWAPI::Player*>>::SubscriberID m_crystalRemovedSubscriberId;
    EVENT_HANDLER3(Mining, onNeutralBuildingRemoved, UnitRecord*, BWAPI::UnitType, BWAPI::Player*) m_crystalRemovedEventHandler;

    TimerEvent m_event;

    // Variables
    BWAPI::Unit* m_target;
    bool m_isAttacking;
    PersistentUnitGroup m_defense;
    // Actions

    // Transitions
  };

public:
  GatherMineralsBehavior(const Process* parent, unsigned int initialPriority, const PersistentUnitGroup* probes, BaseLocation* baseLocation)
    : GroupBehaviorT(parent, initialPriority, probes)
    , GroupBehavior(parent, initialPriority, probes)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_miningState(*this)
    , m_baseLocation(baseLocation)
    , m_lastMineral(NULL)
    , m_states(m_miningState)
  { }

  static const TerminationMode NoMoreMinerals;

  typedef boost::tuple<
    Mining&
  > States;
  const States m_states;

protected:
  virtual void _output(std::ostream& out) const;

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

  virtual void onUnitAddedToGroup(void*, BWAPI::Unit* unit)
  {
    assert(unit->getType() == BWAPI::UnitTypes::Protoss_Probe);
    if(getCurrentState() == &m_miningState)
      m_miningState.onUnitAddedToGroup(unit);
  }

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

  BaseLocation* m_baseLocation;
  BWAPI::Unit* m_lastMineral;

  // States
  Mining m_miningState;
};