#include "Synapse.h"
#include "Overseer.h"
#include "TrainingTask.h"


Synapse::Synapse(Overseer* ov)
{
	currentDriveLevel = 0;
	activationThreshold = 0;
	overseer = ov;
	running = false;
	initialized = false;
	rallyLoc = Positions::None;
	RATIO_ID = 0;
	/*
	UnitRatio* dragoonsToZealots = new UnitRatio(UnitTypes::Protoss_Dragoon, UnitTypes::Protoss_Zealot, 2, 1, ov, 0);
	UnitRatio* arbitersToDragoons = new UnitRatio(UnitTypes::Protoss_Arbiter, UnitTypes::Protoss_Dragoon, 2, 10, ov, 0);
	UnitRatio* scoutMaintenance = new UnitRatio(UnitTypes::None, UnitTypes::Protoss_Observer, 0, 3, ov, 0);
	UnitRatio* basesToGateways = new UnitRatio(UnitTypes::Protoss_Nexus, UnitTypes::Protoss_Gateway, 1, 3, ov, 8);
	

	ratios.push_back(dragoonsToZealots);
	ratios.push_back(scoutMaintenance);
	ratios.push_back(basesToGateways);
	ratios.push_back(arbitersToDragoons);
	*/

	temporalSpacingMap[UnitTypes::Protoss_Gateway] = 0;
	temporalSpacingMap[UnitTypes::Protoss_Observer] = 0;

	activationMap[UnitTypes::Protoss_Probe] = true;
	activationMap[UnitTypes::Protoss_Gateway] = true;
	activationMap[UnitTypes::Protoss_Robotics_Facility] = true;
	activationMap[UnitTypes::Protoss_Stargate] = true;



	UNIT_VALUE = 50;
	DRIVE_UNDERCUT = 10;
}

void Synapse::monitor()
{
	////Broodwar->drawTextScreen(32,256, "dragoons: %d zealots: %d", overseer->getUnitManager()->countFriendlyUnits(UnitTypes::Protoss_Dragoon), overseer->getUnitManager()->countFriendlyUnits(UnitTypes::Protoss_Zealot));
	// if we're at the pop cap, lets just not do anything
	if(Broodwar->self()->supplyTotal() == Broodwar->self()->supplyUsed()) {
		return;
	}

	if(temporalSpacingMap[UnitTypes::Protoss_Gateway] > 0) {
		temporalSpacingMap[UnitTypes::Protoss_Gateway] = temporalSpacingMap[UnitTypes::Protoss_Gateway]-1;
	//	////Broodwar->sendText("spc: %d", temporalSpacingMap[UnitTypes::Protoss_Gateway]);
	}
	if(temporalSpacingMap[UnitTypes::Protoss_Observer] > 0) {
		temporalSpacingMap[UnitTypes::Protoss_Observer] = temporalSpacingMap[UnitTypes::Protoss_Observer]-1;
		//	////Broodwar->sendText("spc: %d", temporalSpacingMap[UnitTypes::Protoss_Gateway]);
	}

////	//Broodwar->drawTextScreen(32,32,"current drive: %d:", currentDriveLevel);
//	//Broodwar->drawTextScreen(32,48,"current activation level: %d", activationThreshold);
	if(initialized && running) {

		if(currentDriveLevel >= activationThreshold) {
			instantiateTask();
			int militarySize = overseer->getUnitManager()->getFriendlyMilitaryUnits().size();
			int addition = militarySize*UNIT_VALUE;
			int productionFacilities = overseer->getUnitManager()->countFriendlyBuildings(UnitTypes::Protoss_Gateway);
			int robos = overseer->getUnitManager()->countFriendlyBuildings(UnitTypes::Protoss_Robotics_Facility);
			int stargates = overseer->getUnitManager()->countFriendlyBuildings(UnitTypes::Protoss_Stargate);

			productionFacilities += robos;
			productionFacilities += stargates;

			if(addition > UnitTypes::Protoss_Dragoon.buildTime()/productionFacilities) {
				addition = UnitTypes::Protoss_Dragoon.buildTime()/productionFacilities;
			}
			activationThreshold = baseDriveLevel+(addition);
			return;
		} 
		currentDriveLevel++; 
	}
}

void Synapse::instantiateTask()
{

	// remember these are the PRODUCTION FACILITIES we want to produce units, not the actual units themselves
	if(initialized && running) {
		calculateTaskFor(UnitTypes::Protoss_Gateway);
		calculateTaskFor(UnitTypes::Protoss_Robotics_Facility);
		calculateTaskFor(UnitTypes::Protoss_Stargate);
		calculateTaskFor(UnitTypes::Protoss_Probe);
	}
}

void Synapse::start()
{
	if(!running) {
		if(!initialized) {
			//////Broodwar->sendText("----- SYNAPSE SYSTEM ONLINE -----");
			currentDriveLevel = Broodwar->getFrameCount();
			baseDriveLevel = Broodwar->getFrameCount();
			activationThreshold = Broodwar->getFrameCount();
			initialized = true;
		}
		running = true;
	}
}

bool Synapse::isRunning()
{
	return initialized && running;
}

void Synapse::stop()
{
	running = false;
}

void Synapse::calculateTaskFor( UnitType productionFacility )
{
	if(activationMap[productionFacility] == false) {
		return;
	}
	UnitRatio* taskTarget = NULL;
	for (std::vector<UnitRatio*>::iterator i = ratios.begin(); i != ratios.end(); ++i)
	{
		UnitRatio* cur = *i;
		UnitType rec = cur->getReccomendedUnit();


		// note that this is a rather large hack until we can do this properyl
		if(rec == cur->getSubjects().first) {
			if(cur->getSubjects().first == UnitTypes::Protoss_Dragoon) {
				if(centralManagementMap[cur->getID()] == false) {
					continue;
				}
			}
		}

		if(rec == UnitTypes::None || rec.whatBuilds().first != productionFacility || (rec.isBuilding() && overseer->getArbitrator()->isStagedToBeBuilt(rec))) {
			continue;
		}
		if(rec == UnitTypes::Protoss_Gateway) {
			if(temporalSpacingMap[UnitTypes::Protoss_Gateway] == 0) {

			} else {
				continue;
			}
		}
		if(rec == UnitTypes::Protoss_Observer) {
			if(temporalSpacingMap[UnitTypes::Protoss_Observer] == 0) {

			} else {
				continue;
			}
		}
		// don't consider ratios that concern units we can't yet make
		std::pair<UnitType,UnitType> subjects = cur->getSubjects();
		if(!Broodwar->canMake(NULL, subjects.first) || !Broodwar->canMake(NULL, subjects.second)) {
			continue;
		}


		if(taskTarget == NULL) {
			taskTarget = cur;
		} else {
			if(cur->getMagnitude() > taskTarget->getMagnitude()) {
				taskTarget = cur;
			}
		}

	}
	if(taskTarget == NULL) {
		return;
	}

	UnitType reccomendedUnit = taskTarget->getReccomendedUnit();
	if(reccomendedUnit.isBuilding()) {
		ConstructionTask* newTask = new ConstructionTask(overseer->getUnitManager()->getFriendlyMainBase(), reccomendedUnit, overseer);
		overseer->getArbitrator()->stageNewTask(newTask);
		if(reccomendedUnit == UnitTypes::Protoss_Gateway) {
			temporalSpacingMap[UnitTypes::Protoss_Gateway] = 600;
			temporalSpacingMap[UnitTypes::Protoss_Observer] = 512;
		}

	} else {
		TrainingTask* newTask = new TrainingTask(overseer->getUnitManager()->getFriendlyMainBase(), reccomendedUnit, overseer);
		
		if(reccomendedUnit == UnitTypes::Protoss_Observer) {
			overseer->getUnitManager()->queueBehaviour(UnitTypes::Protoss_Observer, PROTOSS_SCOUTING_OBSERVER);
		}
		if(Broodwar->mapHash().c_str() == "1e983eb6bcfa02ef7d75bd572cb59ad3aab49285") {
				newTask->setRallyLocation(RALLY_NATURAL);
		} else {
			newTask->setRallyLocation(rallyLoc);
		}
			if(reccomendedUnit == UnitTypes::Protoss_Observer || reccomendedUnit == UnitTypes::Protoss_Zealot || reccomendedUnit == UnitTypes::Protoss_Dragoon) {
				overseer->getArbitrator()->stageNewTaskUrgent(newTask);
			} else {
				overseer->getArbitrator()->stageNewTask(newTask);
			}
			currentDriveLevel = baseDriveLevel-DRIVE_UNDERCUT;
	}
}

void Synapse::registerNewRatio( UnitRatio* r )
{
	r->setID(RATIO_ID);
	centralManagementMap[RATIO_ID] = false;
	ratios.push_back(r);
	RATIO_ID++;
}

void Synapse::deactivateFacility( UnitType t )
{
	activationMap[t] = false;
}

void Synapse::activateFacility( UnitType t )
{
	activationMap[t] = true;
}

void Synapse::setRallyPoint( Position p )
{
	rallyLoc = p;
}

void Synapse::clearRallyPoint()
{
	rallyLoc = Positions::None;
}

void Synapse::setCentralManagement( int ratioID, bool status )
{
	centralManagementMap[ratioID] = status;
}

void Synapse::replaceRatioAt( int id, UnitRatio* r )
{
	ratios[id] = r;
}
