#include "stdafx.h"
#include "../../BWAPI_Addon.h"
#include "../PerceptualStateUnitData.h"
#include "../UnitRecord/UnitRecord.h"
#include "Tracking.h"

Tracking::Tracking()
  : m_unitDiscoverEventHandler(*this)
{
  m_unitDiscoverID = BWAPI::getUnitDiscoverEvent().subscribe(&m_unitDiscoverEventHandler, NULL);
}

Tracking::~Tracking()
{
  BWAPI::getUnitDiscoverEvent().unsubscribe(m_unitDiscoverID);
}

void Tracking::onUnitDiscover(void*, BWAPI::Unit* unit)
{
  INVARIANT_UNIT_POINTERS_ASSUMPTION;

  PerceptualStateUnitData& unitData = dynamic_cast<PerceptualStateUnitData&>(BWAPI::getUnitData(unit));

  if (unitData.m_unitRecord == NULL)
  {
    unitData.instantiateUnitRecord();
  }
  else if (isIncompatible(unitData.m_unitRecord, unit))
  {
    // The BWAPI::Unit pointer now refers to a unit which cannot be the same as its unit record;
    // this means the original unit was destroyed in the fog of war and the BWAPI::Unit pointer was recycled for the new unit.

    if (!unitData.m_unitRecord->isDestroyed())
      unitData.m_unitRecord->destroy("BWAPI unit is not compatible with its unit record");

    unitData.m_unitRecord = NULL;
    unitData.instantiateUnitRecord();
  }
  else if (unitData.m_unitRecord->isDestroyed())
  {
    // The unit record is still *possibly* wrong

    SPAR_LOG(LogTypes.GENERAL_WARNING, "Unit record \"%s\" was possibly incorrectly flagged as destroyed", toString(unitData.m_unitRecord).c_str());

    unitData.m_unitRecord = NULL;
    unitData.instantiateUnitRecord();
  }

  unitData.m_unitRecord->onUnitDiscover();
}

bool Tracking::isIncompatible(const UnitRecord* unitRecord, BWAPI::Unit* unit) const
{
  // Note that returning false does not mean this is the same unit with 100% certainty

  // TODO: add stuff here like position, hit points, etc.
  return unitRecord->getType() != unit->getType() && !BWAPI::canMorphTo(unitRecord->getType(), unit->getType());
}