#include "stdafx.h"
#include "Corsair.h"
#include "../../DecisionMaking/Layer1Reactive/Layer1FSM/Pathfinding.h"
#include "../../PerceptualState/Locations/Static/Shape/RectangularLocation.h"
#include <boost/static_assert.hpp>

void CorsairScenario::onSparStarted(void*)
{
  {
    const std::set<BWAPI::Unit*>& units = BWAPI::Broodwar->self()->getUnits();

    for (std::set<BWAPI::Unit*>::const_iterator it = units.begin();
         it != units.end();
         ++it)
    {
      if ((*it)->getType() == BWAPI::UnitTypes::Protoss_Corsair)
      {
        m_corsair = *it;
      }
    }
  }
  initChallenges();
  
  nextChallenge();
}

std::vector<CorsairScenario::OverlordGroup>::iterator CorsairScenario::findOverlord(BWAPI::Unit * ov, OverlordMap::iterator &subIt)
{
  for(std::vector<OverlordGroup>::iterator it = m_overlords.begin(); it != m_overlords.end(); ++it)
  {
    subIt = it->overlords.find(ov);
    if(subIt != it->overlords.end())
      return it;
  }
  return m_overlords.end();
}

void CorsairScenario::onOverlordDestroyed(void* rawUnit)
{
  if(!m_isEnded)
  {
    BWAPI::Unit * unit = static_cast<BWAPI::Unit *>(rawUnit);

    OverlordMap::iterator subIt;
    std::vector<OverlordGroup>::iterator it = findOverlord(unit, subIt);
    if(it != m_overlords.end())
    {
      BWAPI::getIndividualUnitDestroyEvent(subIt->first).unsubscribe(subIt->second);
      it->overlords.erase(subIt);
      it->count--;
      if(it->count == 0)
      {
        m_current->behavior->externalTerminate();
        m_current->area = 0;
        ++m_current;
        if(m_current != m_overlords.end())
        {
          nextChallenge();
        }
      }
    }
  }
}

void CorsairScenario::onEnd()
{
  m_isEnded = true;
  BWAPI::getUnitDiscoverEvent().unsubscribe(m_unitDetectEventID);
  for(std::vector<OverlordGroup>::iterator it = m_overlords.begin(); it != m_overlords.end(); ++it)
  {
    for(OverlordMap::iterator subIt = it->overlords.begin(); subIt != it->overlords.end(); ++subIt)
    {
      BWAPI::getIndividualUnitDestroyEvent(subIt->first).unsubscribe(subIt->second);
    }
  }
}

void CorsairScenario::nextChallenge()
{
  m_current->behavior = new CorsairHarassmentBehavior(this, 100, m_corsair, m_current->area);
  m_current->behavior->zombifyOnTerminate();
  m_current->behavior->start();
}

void CorsairScenario::onUnitDetected(void*, BWAPI::Unit* unit)
{
  if(unit->getType() == BWAPI::UnitTypes::Zerg_Overlord)
  {
    for(std::vector<OverlordGroup>::iterator it = m_overlords.begin(); it != m_overlords.end(); ++it)
    {
      if(it->area && it->area->isInLocation(unit->getPosition()))
      {
        if(it->overlords.count(unit) == 0)
        {
          it->overlords[unit] = BWAPI::getIndividualUnitDestroyEvent(unit).subscribe(&m_onOverlordDestroyedHandler, unit);
        }
        break;
      }
    }
  }
}

inline std::pair<BWAPI::TilePosition, BWAPI::TilePosition> makeRect(int x1, int y1, int x2, int y2)
{
  typedef BWAPI::TilePosition TP;
  return std::make_pair(TP(x1, y1), TP(x2, y2));
}

void CorsairScenario::initChallenges()
{
  typedef BWAPI::TilePosition TP;
  typedef std::pair<TP, TP> Rect;
  static Rect orders[] = 
    { 
      makeRect(14, 55, 29, 62), 
      makeRect(45, 53, 59, 62), 
      makeRect(5, 37, 24, 49), 
      makeRect(3, 11, 24, 32), 
      makeRect(29, 2, 59, 17),
      makeRect(41, 20, 62, 37)
    };
  static int counts[] = { 1, 1, 2, 1, 4, 4 };

  // check if both arrays have same length
  BOOST_STATIC_ASSERT((sizeof(orders) / sizeof(*orders)) == (sizeof(counts) / sizeof(*counts)));

  for(size_t i = 0; i < array_size(orders); ++i)
  {
    const Rect & r = orders[i];
    RectangularLocation * loc = new RectangularLocation(getCenter(r.first), getCenter(r.second));
    m_overlords.push_back(OverlordGroup(loc, counts[i]));
  }

  m_unitDetectEventID = BWAPI::getUnitDiscoverEvent().subscribe(&m_unitDetectedHandler, 0);
  
  m_current = m_overlords.begin();
}
