#pragma once
#include "Behavior.h"
#include "../../../../BWAPI_Addon.h"

/**
 * @brief A unit behavior outputs commands to a single unit.
 */
class UnitBehavior : public virtual Behavior
{
public:
  /**
   * @brief Constructs a new unit behavior.
   * @param parent The parent of the new behavior.
   * @param initialPriority The initial priority of the new behavior.
   * @param unit The unit associated with this new unit behavior.
   */
  UnitBehavior(const Process* parent, unsigned int initialPriority, BWAPI::Unit* unit)
    : Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
    , m_unitDestroyEventHandler(*this)
    , m_unit(unit)
  {
  }

  /**
   * @return The unit associated with this unit behavior.
   */
  BWAPI::Unit* getUnit() const
  {
    return m_unit;
  }

  /**
   * @brief Termination mode where the unit was destroyed.
   */
  static const TerminationMode UnitDestroyed;

  /////////
  // GUI //
  /////////
  virtual UnitRecordGroup _getUnitsInvolved() const
  {
    return UnitRecordGroup(&m_unit, &m_unit + 1);
  }

protected:
  /**
   * @brief Called when the unit behavior starts.
   *        The unit behavior subscribes to its unit's destruction event.
   */
  virtual void onStart()
  {
    Behavior::onStart();
    //Layer1FSMUnitData& data = dynamic_cast<Layer1FSMUnitData&>(BWAPI::getUnitData(m_unit));
    //data.addBehavior(this);
    m_unitDestroyId = BWAPI::getIndividualUnitDestroyEvent(m_unit).subscribe(&m_unitDestroyEventHandler, NULL);
  }

  /**
   * @brief Called when the unit associated with this behavior is destroyed.
   *        This terminates the unit behavior automatically.
   */
  void onUnitDestroy(void*)
  {
    terminate(UnitDestroyed);
  }

  /**
   * @brief Called when the unit behavior terminates.
   *        The unit behavior unsubscribes from its unit's destruction event.
   */
  virtual void onEnd()
  {
    BWAPI::getIndividualUnitDestroyEvent(m_unit).unsubscribe(m_unitDestroyId);
    Behavior::onEnd();
  }

  /**
   * @brief The unit associated with this behavior. The behavior automatically terminates if this unit gets destroyed.
   */
  BWAPI::Unit* const m_unit;

private:
  EVENT_HANDLER(UnitBehavior, onUnitDestroy) m_unitDestroyEventHandler;
  BWAPI::OnIndividualUnitDestroy::SubscriberID m_unitDestroyId;
};

template <class DerivedBehavior>
class UnitBehaviorT : public virtual UnitBehavior, public BehaviorT<DerivedBehavior>
{
public:
  UnitBehaviorT(const Process* parent, unsigned int initialPriority, BWAPI::Unit* unit)
    : UnitBehavior(parent, initialPriority, unit)
    , BehaviorT(parent, initialPriority)
    , Behavior(parent, initialPriority)
    , FSM(parent)
    , Process(parent)
  {
  }
};
