#pragma once
#include "../../../Utils/ReferenceCounted.h"
#include "../../../Utils/Component.h"
#include "../../../BWAPI_Addon.h"
#include <BWAPI.h>

class UnitRecord;

class UnitRecordType : public ReferenceCounted, public virtual Component
{
public:
  /**
   * @brief Information saved about a particular unit, before said information becomes unavailable.
   */
  class SavedState : public ReferenceCounted
  {
  public:
    SavedState(UnitRecordType* unitRecordType);

    BWAPI::UnitType getType() const { return m_unitType; }
    BWAPI::Player* getPlayer() const { return m_player; }
    BWAPI::Position getPosition() const { return m_position; }
    BWAPI::TilePosition getTilePosition() const { return m_tilePosition; }
    int getHitPoints() const { return m_hitPoints; }
    int getShields() const { return m_shields; }
    bool isLifted() const { return m_isLifted; }
    bool isCompleted() const { return m_isCompleted; }

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

    /**
     * @note IMPORTANT: if UnitRecord::m_firstSavedPositionInvalidatedFrame != -1, then this means the unit moved and the
     *                  position is thus not valid any more! (only an indication of where the unit was at this particular frame)
     */
    BWAPI::Position m_position;
    BWAPI::TilePosition m_tilePosition;

    BWAPI::UnitType m_unitType;
    BWAPI::Player* m_player;
    int m_hitPoints;
    int m_shields;
    bool m_isLifted;
    bool m_isCompleted;
  };

  UnitRecordType(UnitRecord* unitRecord, BWAPI::UnitType unitType)
    : m_unitRecord(unitRecord)
    , m_unitType(unitType)
  {
  }

  BWAPI::UnitType getType() const { return m_unitType; }

  UnitRecord* getUnitRecord() { return m_unitRecord; }
  const UnitRecord* getUnitRecord() const { return m_unitRecord; }

  virtual void onDestroyed() {}

  virtual void onUnitDiscover() {}

  virtual void onUnitEvade() {}

  virtual SavedState* saveState() 
  {
    return new SavedState(this);
  }

protected:
  friend class UnitRecord;

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

  UnitRecord* const m_unitRecord;

  const BWAPI::UnitType m_unitType;

private:
  UnitRecordType(const UnitRecord& other);
  UnitRecordType & operator=(const UnitRecordType &);
};
