#include "HighTemplarGeneralMicroBehaviour.h"
#include "ArchonGeneralMicroBehaviour.h"
#include "Army.h"

HighTemplarGeneralMicroBehaviour::HighTemplarGeneralMicroBehaviour( UnitModel* sub , UnitManager* u )
{
	subject = sub;
	unitManager = u;
	attacking = false;
	moving = false;
	armyEye = Positions::None;
	targettingSystem = new TargetEvaluator(sub);
	currentTarget = NULL;
	targetArmy = NULL;
	just_used_stasis = false;
	MIN_STORM_NEIGHBOURS = 3;
	STORM_CONFIDENCE = 0;
	STORM_CONFIDENCE_THRESHOLD = 2;
	STORM_COOLDOWN = 0;
	STORM_INSPECTION_COOLDOWN = 0;
	id = PROTOSS_GENERAL_HIGHTEMPLAR;
	isMerging = false;
}

bool HighTemplarGeneralMicroBehaviour::execute()
{
		//Broodwar->drawEllipseMap(subject->getPosition().x(), subject->getPosition().y(), 16, 16, BWAPI::Colors::Red, false);

		if(subject->getType() == UnitTypes::Protoss_Archon) {
			subject->clearMicroBehaviour();
			subject->setMicroBehaviour(PROTOSS_GENERAL_ARCHON);
			return true;
		}
		
	if(!isMerging) {
	checkForMergeOpportunity();
	std::vector<UnitModel*> enemiesInRange = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), 300);
	if(subject->getUnit()->getOrder() == BWAPI::Orders::CastPsionicStorm) {
		return true;
	}

	if(subject->getArmyOwner() != NULL) {
		if(subject->getArmyOwner()->isArmyUnderAttack()) {
		if(subject->getArmyOwner()->getCentrePoint().getDistance(subject->getPosition()) > 300) {
			subject->getUnit()->move(subject->getArmyOwner()->getCentrePoint());
			return true;
		}
		}
	}



	if(subject->getUnit()->getEnergy() >= 75 && STORM_COOLDOWN == 0) {
		getBestStormTarget();
		if(currentTarget != NULL) {
		if(subject->getUnit()->useTech(TechTypes::Psionic_Storm, currentTarget->getUnit())) {
			STORM_COOLDOWN = 32;
		}
		}
	}

	if(STORM_COOLDOWN > 0) {
		STORM_COOLDOWN--;
	}
	


	if(subject->getArmyOwner() == NULL ) {
		return false;
	}
	int avgX = 0;
	int avgY = 0;
	int livingMembers = 0;
	std::vector<UnitModel*> forces = subject->getArmyOwner()->getMembers();

	Position avgPos = subject->getArmyOwner()->getCentrePoint();
	if(!subject->getUnit()->isMoving()) {
		ParticleGenerator* p = new ParticleGenerator(128, 256, avgPos);
		std::vector<Position> v = p->generate();
		BWTA::Chokepoint* cp = BWTA::getNearestChokepoint(subject->getPosition());
		int bestDist = 900000;
		Position bestPos = avgPos;
		if(cp->getWidth() < 100) {
		for(std::vector<Position>::const_iterator i = v.begin(); i != v.end(); i++) {
			Position cur = *i;
			if(cur.getDistance(avgPos) <= 128) {
				continue;
			}
			if(cur.getDistance(cp->getCenter()) < 128) {
				continue;
			}
			int dist = cur.getDistance(subject->getPosition());
			if(dist < bestDist) {
				dist = bestDist;
				bestPos = cur;
			}
		}
		}

	subject->getUnit()->move(bestPos);


	}
	
	} else {
		if(!mergeTarget->isAlive() || mergeTarget->getPosition().getDistance(subject->getPosition()) > 512) {
			isMerging = false;
		} else {
			subject->getUnit()->useTech(TechTypes::Archon_Warp, mergeTarget->getUnit());
			mergeTarget->getUnit()->useTech(TechTypes::Archon_Warp, subject->getUnit());
		}
	}
	
	return false;
}

void HighTemplarGeneralMicroBehaviour::nudge()
{

}

void HighTemplarGeneralMicroBehaviour::setTargetArmy( Army* a )
{
	targetArmy = a;
}

void HighTemplarGeneralMicroBehaviour::clearTargetArmy()
{
	targetArmy = NULL;
}

void HighTemplarGeneralMicroBehaviour::getBestStormTarget()
{
	UnitModel* bestTarget = NULL;
	if(currentTarget != NULL) {
		bestTarget = currentTarget;
	}
	
	if(Broodwar->getFrameCount()%8 == 0) {
		int bestNeighbourCount = 0;
		std::vector<UnitModel*> enemiesInRange = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), UnitTypes::Protoss_High_Templar.sightRange()*1.2);
		std::vector<UnitModel*> friendsInRange = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), UnitTypes::Protoss_High_Templar.sightRange()*0.7);

		if(enemiesInRange.empty() || enemiesInRange.size() < 3) {
			currentTarget = NULL;
			return;
		}

		for(std::vector<UnitModel*>::const_iterator itt = friendsInRange.begin(); itt != friendsInRange.end(); itt++) {
			UnitModel* ct = *itt;
			if(ct->getType() == UnitTypes::Protoss_High_Templar) {
				if(ct == subject) {
					continue;
				} else {
					if(ct->getUnit()->getOrder() == BWAPI::Orders::CastPsionicStorm) {
						STORM_COOLDOWN = 64;
						currentTarget = NULL;
						return;
					}
				}
			}
		}
		 

		int bestNeighboursSoFar = 0;
		for(std::vector<UnitModel*>::const_iterator it = enemiesInRange.begin(); it != enemiesInRange.end(); it++) {
			UnitModel* ncur = *it;
			//Broodwar->drawLineMap(ncur->getPosition().x(), ncur->getPosition().y(), subject->getPosition().x(), subject->getPosition().y(), Colors::Green);
			if(ncur->getUnit()->isUnderStorm()) {
				STORM_COOLDOWN = 64;
				currentTarget = NULL;
				return;
			}
			if(!ncur->getUnit()->isVisible() || ncur->isStasised() || ncur->getType().isBuilding() || ncur->getType() == UnitTypes::Terran_Vulture_Spider_Mine || ncur->getType() == UnitTypes::Protoss_Scarab) {
				continue;
			}

			std::vector<UnitModel*> neighbours = unitManager->getAllEnemyUnitsInRange(ncur->getPosition(), 96);
			std::vector<UnitModel*> collatoral = unitManager->getAllFriendlyUnitsInRange(ncur->getPosition(), 96);
			if(collatoral.size() > neighbours.size()) {
				currentTarget = NULL;
				return;
			}

			int neighbourScore = 0;
			int neighbourCount = 0;
			for(std::vector<UnitModel*>::const_iterator itt = neighbours.begin(); itt != neighbours.end(); itt++) {
				UnitModel* cur = *itt;
				if(cur->getUnit()->isUnderStorm()) {
					STORM_COOLDOWN = 32;
					currentTarget = NULL;
					return;
				}
				if(cur->getUnit()->isUnderStorm() || cur->isStasised() || !cur->isAlive() || cur->getType().isBuilding() || cur->getType() == UnitTypes::Terran_Vulture_Spider_Mine || !cur->getUnit()->isVisible()) {
					
				} else {
					if(cur->getType().isWorker()) {
						neighbourScore+=10;
						neighbourCount+=1; // ;)
					}
				if(cur->getType() == UnitTypes::Terran_Siege_Tank_Siege_Mode) {
					neighbourScore+=550;
					neighbourCount+=4; // ;)
				}
				if(cur->getType() == UnitTypes::Terran_Medic) {
					neighbourScore+=55;
					neighbourCount+=1;
				}
				if(cur->getType() == UnitTypes::Terran_Marine) {
					neighbourScore+=45;
					neighbourCount+=1;
				}
				if(cur->getType() == UnitTypes::Protoss_Dragoon) {
					neighbourScore+=50;
					neighbourCount+=2; // ;)
				}
				if(cur->getType() == UnitTypes::Protoss_Zealot) {
					neighbourScore+=25;
					neighbourCount+=1;
				}
				if(cur->getType() == UnitTypes::Terran_Science_Vessel) {
					neighbourScore+=25;
					neighbourCount+=1; // ;)
				}
				if(cur->getType() == UnitTypes::Terran_Battlecruiser) {
					neighbourScore+=55;
					neighbourCount+=1; // ;)
				}
				if(cur->getType() == UnitTypes::Protoss_High_Templar) {
					neighbourScore+=200;
					neighbourCount+=2; // ;)
				}
				if(cur->getType() == UnitTypes::Protoss_Reaver) {
					neighbourScore+=100;
					neighbourCount+=2; // ;)
				}
				if(cur->getType() == UnitTypes::Zerg_Mutalisk) {
					neighbourScore+=125;
					neighbourCount+=3;
				}
				if(cur->getType() == UnitTypes::Zerg_Hydralisk) {
					neighbourScore+=225;
					neighbourCount+=2;
				}
				if(cur->getType() == UnitTypes::Zerg_Zergling) {
					neighbourScore+=25;
					neighbourCount+=1;
				}
				if(cur->getType() == UnitTypes::Terran_Vulture) {
					neighbourScore+=50;
					neighbourCount+=2;
				}		
				if(cur->getType() == UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_Dark_Archon || cur->getType() == UnitTypes::Protoss_Dark_Templar || cur->getType() == UnitTypes::Protoss_Scout || cur->getType() == UnitTypes::Protoss_Corsair) {
					neighbourScore+=50;
					neighbourCount+=1;
				}	
				if(cur->getType() == UnitTypes::Protoss_Carrier) {
					neighbourScore += 100;
					neighbourCount+=3;
				}
				}
			}
		//////Broodwar->sendText("neighbours: %d score: %d", neighbourCount, neighbourScore);
			if(neighbours.empty()) {
				neighbourScore-=1000; // better idea?
			}
			if(neighbourCount > bestNeighbourCount) {
				bestNeighbourCount = neighbourCount;
			}
			neighbourScore = neighbourScore - (collatoral.size()*100); 

			if(bestTarget == NULL) {
				bestTarget = ncur;
				bestNeighboursSoFar = neighbourScore;
			} else {
				if(neighbourScore > bestNeighboursSoFar) {
					bestNeighboursSoFar = neighbourScore;
					bestTarget = ncur;
				}
			}
		}
	
	if(bestTarget != NULL) {
		//Broodwar->drawEllipseMap(bestTarget->getPosition().x(), bestTarget->getPosition().y(), 96, 96, BWAPI::Colors::Red, false);
		if(currentTarget != NULL) {
			bool modifyConfidence = false;
			if(currentTarget->getPosition().getDistance(bestTarget->getPosition()) <= 96) {
				STORM_CONFIDENCE++;
			} else {
				if(STORM_CONFIDENCE <= 0 ) {

				} else {
					STORM_CONFIDENCE--;
				}
			}
		}
		if(bestNeighbourCount < 3) {
				//////Broodwar->sendText("no target, %d", bestNeighbourCount);
			currentTarget = NULL;
		} else {
			//////Broodwar->sendText("got a target!");
			currentTarget = bestTarget;
		}
	}
	}
}

void HighTemplarGeneralMicroBehaviour::checkForMergeOpportunity()
{
	if(isMerging || subject->getUnit()->getOrder() == BWAPI::Orders::CastPsionicStorm) {
		return;
	}
	if(Broodwar->getFrameCount()%256 == 0) {
	bool canMerge = false;

	if(subject->getArmyOwner() != NULL) {
		int goons = subject->getArmyOwner()->countNumTypeInArmy(UnitTypes::Protoss_Dragoon);
		int hts = subject->getArmyOwner()->countNumTypeInArmy(UnitTypes::Protoss_High_Templar);
		if(goons <= 3 && hts >= 2) {
			canMerge = true;
		}
	}

	std::vector<UnitModel*> templars = unitManager->getAllFriendlyUnitsOfType(UnitTypes::Protoss_High_Templar);
	UnitModel* closestTemplar = NULL;
	for(std::vector<UnitModel*>::const_iterator itt = templars.begin(); itt != templars.end(); itt++) {
		UnitModel* cur = *itt;
		if(cur == subject) {
			continue;
		}
		if(cur->getUnit()->isMorphing() || cur->getUnit()->getOrder() == BWAPI::Orders::ArchonWarp || cur->getUnit()->getOrder() == BWAPI::Orders::CompletingArchonsummon) {
			return;
		}
		if(cur->getPosition().getDistance(subject->getPosition()) >= 512) {
			continue;
		} else {
			canMerge = true;
		}
	

		if(closestTemplar == NULL) {
			closestTemplar = cur;
		} else {
			if(cur->getPosition().getDistance(subject->getPosition()) < closestTemplar->getPosition().getDistance(subject->getPosition())){
				closestTemplar = cur;
			}
		}
	}

	if(canMerge) {	
		if(closestTemplar != NULL) {
		bool shouldMerge = false;
		if(subject->getUnit()->getEnergy() <= 50 && closestTemplar->getUnit()->getEnergy() <= 50) {
			shouldMerge = true;
		}
		if(unitManager->countFriendlyUnitsOfType(UnitTypes::Protoss_Archon) <= 3 && subject->getUnit()->getEnergy() <= 100 && closestTemplar->getUnit()->getEnergy() <= 100) {
			shouldMerge = true;
		}
		if(shouldMerge) {
			
				if(subject->getUnit()->useTech(TechTypes::Archon_Warp, closestTemplar->getUnit())){
					isMerging = true;
					mergeTarget = closestTemplar;
					////Broodwar->sendText("merging templars");
				}
			}
		}
	}
}

}