#pragma once
#include "Utils/Component.h"
#include "Utils/Event.h"
#include <BWAPI.h>
#include <list>

namespace BWAPI { namespace detail { class Singleton; }}
class UnitManager;

/**
 * @brief Base class for data associated to a single unit.
 */
class UnitData : public virtual Component
{
public:
  /**
   * @brief Constructs a new UnitData instance.
   * @param unit The unit to associated the data to.
   */
  UnitData(BWAPI::Unit* unit)
    : m_unit(unit)
    , m_lastType(unit->getType())
    , m_lastPlayer(unit->getPlayer())
    , m_individualUnitDestroyEvent(*this)
    , m_individualUnitEvadeEvent(*this)
    , m_isDestroyed(false)
  {
  }

  /**
   * @brief UnitData's destructor. Nothing special, as you can see.
   */
  virtual ~UnitData()
  {
  }

  /**
   * @return Whether the unit was the subject of a onUnitDestroy event.
   * @note isDestroyed() implies getUnitRecord()->isDestroyed() but not the other way around.
   */
  bool isDestroyed() const
  {
    return m_isDestroyed;
  }

  DECLARE_EVENT(OnIndividualUnitDestroy);
  OnIndividualUnitDestroy& getIndividualUnitDestroyEvent() const { return m_individualUnitDestroyEvent; }
  DECLARE_EVENT(OnIndividualUnitEvade);
  OnIndividualUnitEvade& getIndividualUnitEvadeEvent() const { return m_individualUnitEvadeEvent; }
  //DECLARE_EVENT(OnIndividualUnitMorph);
  //OnIndividualUnitMorph& getOnIndividualUnitMorphEvent() const { return m_individualUnitMorphEvent; }
  //DECLARE_EVENT(OnIndividualUnitRenegade);
  //OnIndividualUnitRenegade& getIndividualUnitRenegadeEvent() const { return m_individualUnitRenegadeEvent; }

protected:
  friend class UnitManager;
  friend class BWAPI::detail::Singleton;

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

  /**
   * @brief The unit to which this data refers.
   */
  BWAPI::Unit* const m_unit;

private:
  /**
   * @brief The last known type of this unit provided by BWAPI notifications.
   */
  BWAPI::UnitType m_lastType;
  /**
   * @brief The last known player controlling the unit as provided by BWAPI notifications.
   */
  BWAPI::Player* m_lastPlayer;
  /**
   * @brief Whether the unit was the subject of a onUnitDestroy event.
   */
  bool m_isDestroyed;

  /**
   * @brief The position of this unit data in the list.
   */
  std::list<UnitData*>::const_iterator m_posInManager;

  EVENT(OnIndividualUnitDestroy) m_individualUnitDestroyEvent;
  EVENT(OnIndividualUnitEvade) m_individualUnitEvadeEvent;
  //EVENT(OnIndividualUnitMorph) m_individualUnitMorphEvent;
  //EVENT(OnIndividualUnitRenegade) m_individualUnitRenegadeEvent;
};