#include "RoamingDarkTemplarMicroBehaviour.h"
#include "BaseModel.h"
#include "Overseer.h"
#include <set>

RoamingDarkTemplarMicroBehaviour::RoamingDarkTemplarMicroBehaviour( UnitModel* sub , UnitManager* u )
{
	unitManager = u;
	subject = sub;
	targetPosition = BWAPI::Positions::None;
	targetCell = NULL;
	//pickNewTarget();
	currentTarget = NULL;
	id = PROTOSS_ROAMING_DARK_TEMPLAR;
	targettingSystem = new TargetEvaluator(sub);
	waiting = false;
	waitCounter = 0;
	pickNewExploreTarget();
}

bool RoamingDarkTemplarMicroBehaviour::execute()
{
	if(!subject->getUnit()->isCompleted()) {
		return true;
	}
	if(waiting) {
	}

	if(!subject->isUnderThreat() && !subject->getUnit()->isMoving()) {
		idleTimer++;
	} else {
		idleTimer = 0;
	}
	if(idleTimer >= 2048) {
		relinquishExploreTarget();
		idleTimer = 0;
	}

	updateBlackList();
	if(hasBeenDetected()){
		if(targetCell != NULL) {
			relinquishExploreTarget();
			currentTarget = NULL;
			subject->pathStop();
			waiting = false;
			waitCounter = 0;
		}

		Position bestEscapePoint = unitManager->getClosestFriendlyBaseModel(subject->getPosition())->getPosition();
		subject->getUnit()->move(bestEscapePoint);
		//Broodwar->drawEllipseMap(subject->getPosition().x(), subject->getPosition().y()-32, 12, 12, BWAPI::Colors::Red, true);

		return true;
	}

	lookForAttackTarget();
	if(currentTarget != NULL) {
		subject->attack(currentTarget);
		waiting = false;
		waitCounter = 0;
		return true;
	}

	if(waitCounter > 0) {
		waitCounter--;
		return true;
	}
	if(waitCounter == 0 && waiting) {
		waiting = false;
		relinquishExploreTarget();
	}
	if(targetCell != NULL) {
		//Broodwar->drawLineMap(subject->getPosition().x(), subject->getPosition().y(), targetPosition.x(), targetPosition.y(), BWAPI::Colors::Yellow);

		if(subject->getPosition().getDistance(targetPosition) <= 256) {
			if(!waiting) {
				waiting = true;
				waitCounter = rand()%128;
				//Broodwar->drawEllipseMap(subject->getPosition().x(), subject->getPosition().y(), 8, 8, BWAPI::Colors::Yellow, true);
				subject->pathStop();
				relinquishExploreTarget();
			}
		} else {
			//	if(!subject->isFollowingPath()) {
				//	subject->pathMove((TilePosition)targetPosition, PATHFINDING_THREATAWARE_ASTAR_GROUND_NO_OBSTACLES);
				//}
		}
	} else {
		pickNewExploreTarget();
	}
	return false;
}

void RoamingDarkTemplarMicroBehaviour::nudge()
{

}

void RoamingDarkTemplarMicroBehaviour::pickNewExploreTarget()
{
	// pick new target
	std::vector<InformationCell*> mapCells = unitManager->getMapInformationSystem()->getMapCells();
	float bestRatio = -1000000;
	InformationCell* bestCell = NULL;
	for (vector<InformationCell*>::iterator i = mapCells.begin(); i != mapCells.end(); ++i)
	{
		InformationCell* cur = *i;

		if(cur->getRegion()->getBaseLocations().empty()) {
			continue;
		}
		if(cur->getRegion() == subject->getRegion()) {
			continue;
		}
		if(unitManager->isRegionOwnedByMe(cur->getRegion())) {
			continue;
		}
		if(isRegionBlackListed(cur->getRegion())) {
			continue;
		}
		if(bestCell == NULL) {
			bestCell = cur;
		} else {
			int distance = cur->getPosition().getDistance(subject->getPosition());
			float qualityValue = (cur->getInformationValue()*0.1)+(rand()%5000);

			if(qualityValue > bestRatio) {
				bestCell = cur;
				bestRatio = qualityValue; 
			}
		}
	}
	targetCell = bestCell;
	if(targetCell == NULL) {
		targetPosition = BWAPI::Positions::None;
		return;
	}
	targetPosition = bestCell->getPosition();
	subject->pathStop();
	waitCounter = 0;
	subject->pathMove((TilePosition)targetPosition, PATHFINDING_THREATAWARE_ASTAR_GROUND_NO_OBSTACLES_DT);
	
}

void RoamingDarkTemplarMicroBehaviour::relinquishExploreTarget()
{
	if(targetCell != NULL) {
		targetCell = NULL;
	}
}

void RoamingDarkTemplarMicroBehaviour::lookForAttackTarget()
{
	
		std::vector<UnitModel*> units = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), 256);
		if(units.empty()) {
			currentTarget = NULL;
			return;
		}
		if(currentTarget != NULL) {
			if(!currentTarget->isAlive() || !currentTarget->getUnit()->isVisible()) {
				currentTarget = NULL;
			}
		}
		int bestScoreSoFar = 0;
		UnitModel* bestTarget = NULL;
		for (vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
		{
			UnitModel* cur = *i;
			if(!cur->isAlive()) {
				continue;
			}
			if(!cur->getUnit()->isVisible()) { 
				continue;
			}
			if(cur->getUnit()->isVisible() && cur->getUnit()->isLoaded()) {
				continue;
			}
			//Broodwar->drawLineMap(cur->getPosition().x(), cur->getPosition().y(), subject->getPosition().x(), subject->getPosition().y(), Colors::White);

			if(bestTarget == NULL) {
				bestTarget = cur;
			} else {
				int candidateValue = calculateTargetValue(cur);

				if(cur->getType().isWorker() && (cur->getUnit()->isCarryingMinerals() || cur->getUnit()->isCarryingGas() || cur->getUnit()->isGatheringGas() || cur->getUnit()->isGatheringMinerals())) {
					candidateValue += 2000;
				}

				if(currentTarget != NULL) {
					if(cur == currentTarget) {
						candidateValue += 1000;
					}
				}
				if(candidateValue > bestScoreSoFar) {
					bestScoreSoFar = candidateValue;
					bestTarget = cur;
				}
			}
		}
		currentTarget = bestTarget;
	
}

bool RoamingDarkTemplarMicroBehaviour::hasBeenDetected()
{
	if(subject->isBeingTargetted()) {
		return true;
	}

	return false;
}

int RoamingDarkTemplarMicroBehaviour::calculateTargetValue( UnitModel* candidate )
{
	int score = unitManager->calculateTargettingPenalty(candidate->getUnit(), subject);
	UnitType t = candidate->getType();

	score += (1000-(subject->getPosition().getDistance(candidate->getPosition())));

	if(currentTarget != NULL && currentTarget->isAlive()) {
		if(candidate == currentTarget) {
			score+=100;
		}
	}
	if(t.isBuilding()) {
		if(t.supplyProvided() || t == UnitTypes::Terran_Barracks || t == UnitTypes::Terran_Factory || t == UnitTypes::Terran_Academy) {
			score += 500;
		}
		if(t.isAddon()) {
			score -=500;
		}
	} else {
		if(t.isWorker()) {
			score+= 100;
			
				if(candidate->getUnit()->isConstructing() || candidate->getUnit()->isMorphing()) {
					score+=5000;
				}

		}
		if(t == UnitTypes::Terran_Vulture | t == UnitTypes::Terran_Siege_Tank_Siege_Mode || t == UnitTypes::Terran_Siege_Tank_Tank_Mode) {
			score -=1000;
			if(t == UnitTypes::Terran_Vulture && candidate->getUnit()->isMoving()) {
				score -= 5000;
			}
		}
	}

	std::vector<UnitModel*> detectors = unitManager->getEnemyDetectorsInRange(candidate->getPosition(), UnitTypes::Terran_Missile_Turret.sightRange());
	if(detectors.empty()) {
		score+=1000;
	}


	return score;
}

void RoamingDarkTemplarMicroBehaviour::updateBlackList()
{
	std::vector<UnitModel*> detectors = unitManager->getEnemyDetectorsInRange(subject->getPosition(), 300);
	for (vector<UnitModel*>::iterator i = detectors.begin(); i != detectors.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
			blacklist.insert((*i));
			
	}
}

bool RoamingDarkTemplarMicroBehaviour::isRegionBlackListed( BWTA::Region* r )
{
	for (set<UnitModel*>::iterator i = blacklist.begin(); i != blacklist.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->isAlive() && cur->getRegion() == r) {
			return true;
		}
		if(unitManager->getOverseer()->getOffenseMonitor()->getConnectedRegions(cur->getRegion()).count(r) != 0) {
			return true;
		}
	}
	return false;
}
