#include "DTDropHarassTask.h"
#include "Overseer.h"
//#include "Windows.h"
#include "HarassingDarkTemplarBehaviour.h"

DTDropHarassTask::DTDropHarassTask( BaseModel* base, Overseer* ov )
{
	TASK_TYPE = HARASS;
	executing = false;
	finished = false;
	initialized = false;
	type = UnitTypes::None;
	overseer = ov;
	targetBase = base;
	trainingRequested = false;
	requestedShuttle = false;
	requestedDT = false;
	atBase = false;
	unloaded = false;
	alphaKills = 0;
	betaKills = 0;
	startFrame = Broodwar->getFrameCount();
	templarAlpha = NULL;
	templarBeta = NULL;
	shuttle = NULL;
}

bool DTDropHarassTask::canInitialize()
{
	////////OutputDebugString(TEXT("initializing dt task!\n"));
	// we can initialize this if we have two dark templars and a shuttle
	// if we don't have these, and they aren't scheduled for production
	// we should schedule them for production at the top of the build queue
	UnitManager* um = overseer->getUnitManager();
	if(um->getBelievedEnemyMainBaseRegion() == NULL) {
		return false;
	}
	bool shuttleFound = false;
	bool templarsFound = false;
	if(um->hasUnit(UnitTypes::Protoss_Shuttle)) {
		////////Broodwar->sendText("shuttle found!");
		
		std::vector<UnitModel*> shuttles = um->getNFreeUnitsOfType(UnitTypes::Protoss_Shuttle, 1);
		if(shuttles.empty()) {

		} else {
			shuttle = shuttles.at(0);
			shuttleFound = true;
			shuttle->setCurrentTaskType(HARASS);
		}
	} else {
		if(!trainingRequested) {
			TrainingTask* shuttleTask = new TrainingTask(overseer->getUnitManager()->getFriendlyMainBase(), UnitTypes::Protoss_Shuttle, overseer);
			overseer->getArbitrator()->stageNewTaskUrgent(shuttleTask);
			requestedShuttle = true;
		}
	}
	 ////////OutputDebugString(TEXT("suspect bit coming up!!\n"));

	if(um->hasUnit(UnitTypes::Protoss_Dark_Templar, 1) && !templarsFound) {
		std::vector<UnitModel*> templars = um->getNFreeUnitsOfType(UnitTypes::Protoss_Dark_Templar, 1);
		templarAlpha = templars.at(0);
			templarAlpha->setCurrentTaskType(HARASS);
			HarassingDarkTemplarBehaviour* tda = (HarassingDarkTemplarBehaviour*)templarAlpha->getMicroBehaviour();
			tda->setWaitForShuttle(true);
	}

	if(um->hasUnit(UnitTypes::Protoss_Dark_Templar, 2)) {
		////////Broodwar->sendText("two dark templar found!");
		std::vector<UnitModel*> templars = um->getNFreeUnitsOfType(UnitTypes::Protoss_Dark_Templar, 2);
		if(templars.empty()) {

		} else {
			 ////////OutputDebugString(TEXT("hmmm!!\n"));
			templarAlpha = templars.at(0);
			templarBeta = templars.at(1);
			templarAlpha->setCurrentTaskType(HARASS);
			templarBeta->setCurrentTaskType(HARASS);

		
				HarassingDarkTemplarBehaviour* tda = (HarassingDarkTemplarBehaviour*)templarAlpha->getMicroBehaviour();
				HarassingDarkTemplarBehaviour* tdb = (HarassingDarkTemplarBehaviour*)templarBeta->getMicroBehaviour();
				tda->setWaitForShuttle(true);
				tdb->setWaitForShuttle(true);
			
	
			templarsFound = true;
		}
	} else {
		if(!trainingRequested) {
			TrainingTask* firstDT = new TrainingTask(overseer->getUnitManager()->getFriendlyMainBase(), UnitTypes::Protoss_Dark_Templar, overseer);
			TrainingTask* secondDT = new TrainingTask(overseer->getUnitManager()->getFriendlyMainBase(), UnitTypes::Protoss_Dark_Templar, overseer);
			overseer->getArbitrator()->stageNewTaskUrgent(firstDT);
			overseer->getArbitrator()->stageNewTaskUrgent(secondDT);
			overseer->getUnitManager()->queueBehaviour(UnitTypes::Protoss_Dark_Templar, PROTOSS_HARASSING_DARK_TEMPLAR);
			overseer->getUnitManager()->queueBehaviour(UnitTypes::Protoss_Dark_Templar, PROTOSS_HARASSING_DARK_TEMPLAR);

			requestedDT = true;
		}
	}

	if(templarAlpha != NULL) {
	if(!templarAlpha->isAlive()) {
		forceFinish();
	}
	}
	if(templarBeta != NULL) {
		if(!templarBeta->isAlive()) {
			forceFinish();
			HarassingDarkTemplarBehaviour* tda = (HarassingDarkTemplarBehaviour*)templarAlpha->getMicroBehaviour();
			tda->setWaitForShuttle(false);
		}
	}
	if(shuttle != NULL) {
		if(!shuttle->isAlive()) {
			forceFinish();
			HarassingDarkTemplarBehaviour* tdb = (HarassingDarkTemplarBehaviour*)templarBeta->getMicroBehaviour();
			tdb->setWaitForShuttle(false);
		}

	}
	if(requestedDT && requestedShuttle) {
		trainingRequested = true;
	}
	if(shuttleFound && templarsFound) {
		if(shuttle->getUnit()->isCompleted()) {
			if(templarAlpha->getUnit()->isCompleted()) {
				if(templarBeta->getUnit()->isCompleted()) {
					initialized = true;
					std::set<BWTA::BaseLocation*> bases = BWTA::getBaseLocations();
					BWTA::BaseLocation* believedNatural = NULL;
					TilePosition bestLoc = TilePositions::None;
					TilePosition startLoc = (TilePosition)overseer->getUnitManager()->getBelievedEnemyMainBaseRegion()->getCenter();
					for (std::set<BaseLocation*>::iterator i = bases.begin(); i != bases.end(); ++i)
					{
						BaseLocation* cur = *i;
						if(cur->isStartLocation()) {
							continue;
						}
						if(cur->isIsland()) {
							continue;
						}
						if(!cur->getRegion()->isReachable(BWTA::getStartLocation(Broodwar->self())->getRegion())) {
							continue;
						}
						if(overseer->getUnitManager()->isBlackListed(cur->getRegion())) {
							continue;
						}

						if(believedNatural == NULL) {
							believedNatural = cur;
							bestLoc = believedNatural->getTilePosition();
						} else {
							
							TilePosition curLoc = cur->getTilePosition();

							int distance = BWTA::getGroundDistance(startLoc, curLoc);
							int bestDistance = BWTA::getGroundDistance(startLoc, bestLoc);
							if(distance < bestDistance && distance > 5) {
								believedNatural = cur;
								bestLoc = believedNatural->getTilePosition();
							}
						}
					}
					HarassingDarkTemplarBehaviour* a = (HarassingDarkTemplarBehaviour*)templarAlpha->getMicroBehaviour();
					HarassingDarkTemplarBehaviour* b = (HarassingDarkTemplarBehaviour*)templarBeta->getMicroBehaviour();
					a->attachTargets(believedNatural->getPosition(), overseer->getUnitManager()->getBelievedEnemyMainBasePosition());
					b->attachTargets(believedNatural->getPosition(), overseer->getUnitManager()->getBelievedEnemyMainBasePosition());
					a->setWaitForShuttle(false);
					b->setWaitForShuttle(false);
					landingZone = believedNatural->getPosition();
				}
			}
		}
	}

	return initialized;
}

bool DTDropHarassTask::execute()
{	
		if(!templarAlpha->isAlive()) {
			if(!templarBeta->isAlive()) {
				forceFinish();
			}
		}
		if(!shuttle->isAlive()) {
			forceFinish();
		}

	if(templarAlpha->getUnit()->isLoaded() && templarBeta->getUnit()->isLoaded()) {
		executing = true;
		//landingZone = findBestLandingZone();
		//shuttle->pathMove((TilePosition)landingZone, PATHFINDING_THREATAWARE_ASTAR_AIR);
		shuttle->getUnit()->move(landingZone);
	//	shuttle->getUnit()->unloadAll(overseer->getUnitManager()->getEnemyBaseModels().at(0)->getSubject()->getTilePosition(),true);
	} else {
		templarAlpha->getUnit()->rightClick(shuttle->getUnit());
		templarBeta->getUnit()->rightClick(shuttle->getUnit());
	}
	return executing;
}

void DTDropHarassTask::monitor()
{
	if(executing) {
		if(!templarAlpha->isAlive() || !templarBeta->isAlive() || !shuttle->isAlive()) {
				forceFinish();
		}
	//Broodwar->drawEllipseMap(landingZone.x(), landingZone.y(), 16, 16, Colors::White, true);
	 ////////OutputDebugString(TEXT("monitoring!! dt task\n"));
	if(shuttle != NULL && shuttle->getUnit()->isCompleted()) {
			 ////////OutputDebugString(TEXT("seeing if we can miove\n"));
		if(unloaded) {
			shuttle->getUnit()->move(overseer->getUnitManager()->getFriendlyMainBase()->getPosition());
			//shuttle->setCurrentTaskType(NO_TASK);
			shuttle = NULL;
	
			finished = true;
			executing = false;
			////Broodwar->sendText("DT Drop Task Finished");
			return;
		}
		 ////////OutputDebugString(TEXT("seeing if we can pick up\n"));
		if(shuttle->isAlive() && !unloaded) {
			 int distance = shuttle->getPosition().getDistance(landingZone);
			 int distanceThresh = 64;
	
			 if(distance < 64) {
		
				 if(templarAlpha->getUnit()->isLoaded()) {
					 shuttle->getUnit()->unload(templarAlpha->getUnit());
				}				 

				if(templarBeta->getUnit()->isLoaded()) {
					shuttle->getUnit()->unload(templarBeta->getUnit());
				}
				if(!templarAlpha->getUnit()->isLoaded() && !templarBeta->getUnit()->isLoaded()) {
					unloaded = true;
					shuttle->pathStop();
				}
			} else {
				if(distance <= 256 && distance > 32) {
					if(shuttle->isFollowingPath()) {
						shuttle->pathStop();
						shuttle->getUnit()->move(landingZone);
					} else {
						shuttle->getUnit()->move(landingZone);
					}
				}
				if(distance > 256) {
					shuttle->getUnit()->move(landingZone);
				}
			}
			 
		}
	} else {
		// here's the code for monitoring the task after the dts are dropped
		if(templarAlpha != NULL && templarBeta != NULL) {
		// terminating condition: templars are dead
		if(!templarBeta->isAlive() && !templarAlpha->isAlive()) {
			////Broodwar->sendText("DT Drop Task Finished");
			finished = true;
			executing = false;
			return;
		}

		}

	}
	}
	
}

bool DTDropHarassTask::isExecuting()
{
	return executing;
}

bool DTDropHarassTask::isFinished()
{
	return finished;
}

bool DTDropHarassTask::isInitialized()
{
	return initialized;
}

BWAPI::UnitType DTDropHarassTask::getBuildType()
{
	return UnitTypes::None;
}

BWAPI::Position DTDropHarassTask::findBestLandingZone()
{
	Position ebl = landingZone;
	if(ebl == Positions::None) {
		return Positions::None;
	}
	BWTA::Region* ebr = BWTA::getRegion(ebl);
	if(ebr == NULL) {
		return Positions::None;
	}
	ParticleGenerator* p = new ParticleGenerator(128, 512, ebl);
	std::vector<Position> v = p->generate();

	int bestScoreSoFar = -10000;
	Position bestPositionSoFar = Positions::None;
	for(std::vector<Position>::const_iterator i = v.begin(); i != v.end(); i++) {
		Position cur = *i;
		if(BWTA::getRegion(cur) != ebr) {
			continue;
		}
		int curScore = 0;
		std::vector<UnitModel*> detectors = overseer->getUnitManager()->getEnemyDetectorsInRange(cur, UnitTypes::Terran_Missile_Turret.sightRange()*1.2);
		curScore -= (800*detectors.size());

		std::vector<UnitModel*> bunkers = overseer->getUnitManager()->getEnemyBuildingsOfTypeInRange(cur, UnitTypes::Terran_Missile_Turret.sightRange()*1.2, UnitTypes::Terran_Bunker);
		curScore -= (200*bunkers.size());

		curScore += 10*(cur.getDistance(BWTA::getNearestChokepoint(cur)->getCenter()));
		
			if(curScore > bestScoreSoFar) {
				bestScoreSoFar = curScore;
				bestPositionSoFar = cur;
			}
		
	}
	//return ebr->getPolygon().getNearestPoint(bestPositionSoFar);
	return bestPositionSoFar;
}
