#include "HarassingDarkTemplarBehaviour.h"

HarassingDarkTemplarBehaviour::HarassingDarkTemplarBehaviour( UnitModel* sub , UnitManager* u )
{
	subject = sub;
	unitManager = u;
	attacking = false;
	moving = false;
	currentTarget = NULL;
	id = PROTOSS_HARASSING_DARK_TEMPLAR;
	bestTarget = NULL;
	breachingMainBase = true;
	targetRegion = NULL;
	naturalPos = Positions::None;
	defendingPoint = false;
	subject->setCurrentTaskType(HARASS);
	waitForShuttle = false;
	mainBasePos = Positions::None;
}

bool HarassingDarkTemplarBehaviour::execute()
{
	if(!subject->getUnit()->isCompleted()) {
		return true;
	}
	if(naturalPos == Positions::None && targetRegion == NULL && !waitForShuttle) {
		locateTargetsIndependently();
		return true;
	}

	if(unitManager->getEnemyDetectorsInRange(subject->getPosition(), 256).empty()) {
		findTarget();
	}
	if(currentTarget != NULL) {
	if(!currentTarget->isAlive() || !currentTarget->getUnit()->isVisible() || (currentTarget->getRegion() == targetRegion && !breachingMainBase)) {
		currentTarget = NULL;
	} else {
		if(!hasBeenDetected() && !subject->getUnit()->isAttackFrame() && !subject->getUnit()->isStartingAttack() && !subject->getUnit()->isAttacking()) {
			//Broodwar->drawLineMap(currentTarget->getPosition().x(), currentTarget->getPosition().y(), subject->getPosition().x(), subject->getPosition().y(), Colors::Red);
			bool shouldAttack = true;
			if(subject->getShields() < 25) {
				shouldAttack = false;
				if(currentTarget->getType().isWorker()) {
					shouldAttack = true;
				}
			}
			if(shouldAttack) {
				subject->getUnit()->attack(currentTarget->getUnit());
				unitManager->declareTargetToMap(subject, currentTarget->getUnit());
				return true;
			}
		}
	}
	}
	if(waitForShuttle) {
		return true;
	}
	if(breachingMainBase) {
		breachMainBase();
	}
	if(defendingPoint) {
		defendPoint();
	}


	return false;
}

void HarassingDarkTemplarBehaviour::nudge()
{

}

int HarassingDarkTemplarBehaviour::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(defendingPoint) {
				score += 1000;
				if(candidate->getUnit()->isConstructing()) {
					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 -= 1000;
			}
		}
	}
	
	std::vector<UnitModel*> detectors = unitManager->getEnemyDetectorsInRange(candidate->getPosition(), UnitTypes::Terran_Missile_Turret.sightRange());
	if(detectors.empty()) {
		score+=1000;
	}
	if(breachingMainBase) {
		if(mainBasePos != Positions::None) {
		score+=(1000-BWTA::getNearestChokepoint(mainBasePos)->getCenter().getDistance(candidate->getPosition()));
		}
	}
	if(defendingPoint) {
		score+=(1000-naturalPos.getDistance(candidate->getPosition()));
	}


	return score;
}

void HarassingDarkTemplarBehaviour::findTarget()
{

	std::vector<UnitModel*> units = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), 312);
	if(units.empty()) {
		units = unitManager->getAllEnemyUnitsInRegion(subject->getRegion());
	}
	if(currentTarget != NULL) {
		if(!currentTarget->isAlive()) {
			currentTarget = NULL;
		}
	}
	int bestScoreSoFar = 0;
	bestTarget = NULL;
	bool targetsInRange = false;
	for (vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
	{
		UnitModel* cur = *i;

		if(cur->getUnit()->isLifted() || cur->getType().isFlyer()) { 
			continue;
		}
		if(cur->getUnit()->isVisible() && cur->getUnit()->isLoaded()) {
			continue;
		}
		if(cur->getUnit()->isBeingConstructed() && cur->getType() != UnitTypes::Protoss_Nexus && cur->getType() != UnitTypes::Protoss_Photon_Cannon && cur->getType() != UnitTypes::Terran_Bunker && cur->getType() != UnitTypes::Terran_Missile_Turret) {
			continue;
		}


		//Broodwar->drawLineMap(cur->getPosition().x(), cur->getPosition().y(), subject->getPosition().x(), subject->getPosition().y(), Colors::White);

		if(cur->getPosition().getDistance(subject->getPosition()) < 96 || subject->getUnit()->isInWeaponRange(cur->getUnit())) {
			targetsInRange = true;
		} else {
			if(targetsInRange) {
				continue;
			}
		}

		if(bestTarget == NULL) {
			bestTarget = cur;
		} else {
			int candidateValue = calculateTargetValue(cur);
			if(cur->getType().isWorker()){
				candidateValue += 6000;
			}
			if(cur == currentTarget) {
				candidateValue += 1000;
			}
			if(cur->getType().isDetector() && cur->getUnit()->isBeingConstructed()) {
				candidateValue+=5000;
			}
			if(candidateValue > bestScoreSoFar) {
				bestScoreSoFar = candidateValue;
				bestTarget = cur;
			}
		}
	}
		currentTarget = bestTarget;
		
}

std::vector<Position> HarassingDarkTemplarBehaviour::generateDetectionField(Position pos)
{
	ParticleGenerator* p = new ParticleGenerator(64, 128, pos);
	std::vector<Position> v = p->generate();
	std::vector<Position> filteredPositions;
	for(std::vector<Position>::const_iterator i = v.begin(); i != v.end(); i++){
		Position cur = *i;
		if(!cur.isValid()) {
			cur.makeValid();
		}
		std::vector<UnitModel*> detectors = unitManager->getEnemyDetectorsInRange(cur, UnitTypes::Terran_Missile_Turret.sightRange());
		if(detectors.empty()) {
			if(cur.getDistance(pos) < subject->getType().groundWeapon().maxRange()) {
				filteredPositions.push_back(cur);
			}
		} else {
			
		}
	}
	return filteredPositions;
}

bool HarassingDarkTemplarBehaviour::breachMainBase()
{
	if(targetRegion == NULL || naturalPos == Positions::None){
		return false;
	}
	if(breachingMainBase) {
		if(subject->getRegion() == targetRegion) {
			if(hasBeenDetected()) {
				breachingMainBase = false;
				defendingPoint = true;
				subject->getUnit()->move(naturalPos);
				currentTarget = NULL;
			//	////Broodwar->sendText("abandoning base breach");
				return false;
			}
			
			if(unitManager->getEnemyDetectorsInRange(subject->getPosition(), 256).empty()) {
				
			} else {
				//////Broodwar->sendText("detector sighted! abandoning position!");
				subject->getUnit()->move(naturalPos);
				currentTarget = NULL;
				breachingMainBase = false;
				defendingPoint = true;

				return false;
			}
			
		} else {
			bool shouldDefendBase = false;
			BaseModel* nbm = unitManager->getClosestFriendlyBaseModel(subject->getPosition());
			if(nbm != NULL) {
			if(subject->getRegion() == nbm->getBaseRegion()) {
				if(nbm->isUnderAttack()) {
					shouldDefendBase = true;
				}
			}
			}
			if(!subject->getUnit()->isMoving() && !shouldDefendBase) {
				subject->getUnit()->move(targetRegion->getCenter());
			}
			if(!subject->getUnit()->isMoving() && shouldDefendBase) {
				subject->getUnit()->attack(nbm->getBaseAttackLoc());
			}
		}
	}
	return true;
}

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

void HarassingDarkTemplarBehaviour::attachTargets( Position natPos, Position basePos )
{
	naturalPos = natPos;
	mainBasePos = basePos;
	targetRegion = BWTA::getRegion(basePos);
}

bool HarassingDarkTemplarBehaviour::defendPoint()
{
	if(targetRegion == NULL || naturalPos == Positions::None){
		return false;
	}
	if(!breachingMainBase) {
			if(hasBeenDetected()) {
				subject->getUnit()->move(unitManager->getFriendlyMainBase()->getPosition());
				currentTarget = NULL;
				//////Broodwar->sendText("abandoning position!");
				return false;
			} else {
				
				if(currentTarget == NULL) {
					if(subject->getPosition().getDistance(naturalPos) > 168) {
							subject->getUnit()->move(naturalPos);
							return false;
					}
				}
				
			
			}

	}
	return true;
}

void HarassingDarkTemplarBehaviour::locateTargetsIndependently()
{
	std::set<BWTA::BaseLocation*> bases = BWTA::getBaseLocations();
	BWTA::BaseLocation* nearestBase = NULL;
	TilePosition bestLoc = TilePositions::None;
	TilePosition startLoc = (TilePosition)unitManager->getBelievedEnemyMainBasePosition();
	if(startLoc == Positions::None) {
		return;
	}
	for (std::set<BaseLocation*>::iterator i = bases.begin(); i != bases.end(); ++i)
	{
		BaseLocation* cur = *i;
		if(cur->isStartLocation()) {
			continue;
		}

		if(nearestBase == NULL) {
			nearestBase = cur;
			bestLoc = nearestBase->getTilePosition();
		} else {
			TilePosition curLoc = cur->getTilePosition();
			int distance = BWTA::getGroundDistance(startLoc, curLoc);
			int bestDistance = BWTA::getGroundDistance(startLoc, bestLoc);
			if(distance < bestDistance && distance > 6) {
				nearestBase = cur;
				bestLoc = nearestBase->getTilePosition();
			}
		}
	}
	attachTargets(nearestBase->getPosition(), unitManager->getBelievedEnemyMainBasePosition());
}

void HarassingDarkTemplarBehaviour::setWaitForShuttle( bool s )
{
	waitForShuttle = s;
}
