#include "stdafx.h"
#include "SparQtGUI.h"

using namespace detail;

void SparQtGUIBase::onStart()
{
  // This callback takes place in the main StarCraft thread.

  SparObserver::onStart();

  m_threadGUI.start();

  boost::unique_lock<boost::mutex> lock(m_GUIreadyMutex);
  m_GUIreadyCondition.wait(lock);

  onFrame();
}

void SparQtGUIBase::onEnd()
{
  // This callback takes place in the main StarCraft thread.

  SparObserver::onEnd();

  m_threadGUI.closeNow();
  m_threadGUI.wait();
}

void select(const UnitRecord* unitRecord)
{
  BWAPI::UnitType type = unitRecord->getType();
  BWAPI::Position pos = unitRecord->getPosition();
  BWAPI::Broodwar->drawBoxMap(pos.x() - type.dimensionLeft() - 2, pos.y() - type.dimensionUp() - 2, 
                              pos.x() + type.dimensionLeft() + 2, pos.y() + type.dimensionUp() + 2,
                              BWAPI::Colors::Yellow);
}

const Process* retrieveProcess(const size_t processID, const Process* root)
{
  const Process* process = NULL;
  if (root->getID() == processID)
  {
    process = root;
  }
  else
  {
    std::pair<Process::ProcessIterator, Process::ProcessIterator> childProcesses = root->getCurrentChildProcesses();
    for (Process::ProcessIterator it = childProcesses.first; process == NULL && it != childProcesses.second; ++it)
    {
      process = retrieveProcess(processID, *it);
    }
  }
  return process;
}

const UnitRecord* retrieveUnitRecord(const size_t unitRecordID, SparAIContainer* spar)
{
  return spar->getPerceptualState()->getUnitRecord(unitRecordID);
}

void SparQtGUIBase::onFrame()
{
  // This callback takes place in the main StarCraft thread.
  // Data must be either copied or reference-counted since stuff may have been deleted once the
  // GUI thread gets a hold of it.

  if (BWAPI::Broodwar->getFrameCount() % m_refreshNbFrames == 0)
  {
    QApplication::postEvent(m_mainWindow, new UpdateCurrentProcessesEvent(m_spar->getInitialAncestor()));

    QApplication::postEvent(m_mainWindow, new UpdatePerceptualStateEvent(*m_spar->getPerceptualState()));
  }

  {
    //boost::mutex::scoped_lock lock(m_selectedProcessesUnitsMutex);

    m_selectedProcessesUnitsMutex.lock();

    std::pair<UnitsToSelect::ProcessIDIterator, UnitsToSelect::ProcessIDIterator> processesID = m_selectedProcessesUnits.getProcessesID();
    for (; processesID.first != processesID.second; ++processesID.first)
    {
      const Process* process = retrieveProcess(*processesID.first, m_spar);
      if (process != NULL)
      {
        Process::UnitRecordGroup unitsInvolved = process->_getUnitsInvolved();
        for (Process::UnitRecordGroup::const_iterator it = unitsInvolved.begin(); it != unitsInvolved.end(); ++it)
        {
          select(*it);
        }
      }
    }
    std::pair<UnitsToSelect::UnitRecordIDIterator, UnitsToSelect::UnitRecordIDIterator> unitRecordsID = m_selectedProcessesUnits.getUnitRecordsID();
    for (; unitRecordsID.first != unitRecordsID.second; ++unitRecordsID.first)
    {
      const UnitRecord* unitRecord = retrieveUnitRecord(*unitRecordsID.first, m_spar);
      if (unitRecord != NULL)
      {
        select(unitRecord);
      }
    }

    m_selectedProcessesUnitsMutex.unlock();
  }

  if (m_mainWindow->takeSchedulerSnapshot())
  {
    m_mainWindow->setTakeSchedulerSnapshot(false);

    QApplication::postEvent(m_mainWindow, new SchedulerSnapshotEvent(m_spar->getScheduler()));
  }
}