#include "ReaverGeneralMicroBehaviour.h"
#include "BaseModel.h"

ReaverGeneralMicroBehaviour::ReaverGeneralMicroBehaviour( UnitModel* sub , UnitManager* u )
{
	subject = sub;
	unitManager = u;
	attacking = false;
	moving = false;
	targettingSystem = new TargetEvaluator(sub);
	currentTarget = NULL;
	id = PROTOSS_GENERAL_REAVER;
		sftPtr = 0;
}

//************************************
// Method:    execute
// FullName:  ReaverGeneralMicroBehaviour::execute
// Access:    virtual public 
// Returns:   void
// Comments:  none
//************************************
bool ReaverGeneralMicroBehaviour::execute()
{

	buildScarabs();

	if(Broodwar->getFrameCount()%2 == 0 && subject->isUnderThreat()) {
		Position curSafestPoint = subject->findClosestPoint(findSafestNearbyPoints(), BWAPI::Positions::None, -1);
		safestPointSmoothing[sftPtr] = curSafestPoint;
		if(sftPtr >= 4) {
			sftPtr = 0;
		} else {
			sftPtr++;
		}

		int avgX = 0;
		int avgY = 0;
		int over = 0;
		for(int i = 0; i < 5; i++) {
			if(safestPointSmoothing[i] == Positions::None) {
				safestPointSmoothing[i] = subject->getPosition();
			}
				avgX += safestPointSmoothing[i].x();
				avgY += safestPointSmoothing[i].y();
				over++;
			
		}
		safestPoint = Position(avgX/over, avgY/over);



	}

	std::vector<UnitModel*> units = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), UnitTypes::Protoss_Reaver.sightRange()*1.2);
	bool usingGlobalTargetMap = false;
	if(units.empty()) {
		currentTarget = NULL;
	//	//////Broodwar->sendText("units empty!");
		units = unitManager->getEnemyBuildingsInRegionOf(subject->getTilePosition());
		usingGlobalTargetMap = true;
		if(units.empty()) {
			////////Broodwar->sendText("no buildings");
			return false;
		}
	}

	//////////////

	// NEW CODE

	for (vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
	{
		BWAPI::Unit* curUnit = (*i)->getUnit();
		if(!curUnit->getType().isFlyer() && (curUnit->getType() == UnitTypes::Protoss_Zealot || curUnit->getType() == UnitTypes::Terran_Firebat || curUnit->getType() == UnitTypes::Zerg_Zergling || curUnit->getType() == UnitTypes::Zerg_Ultralisk)) {
			if(curUnit->getPosition().getDistance(subject->getPosition()) < 64) {
				if(curUnit->getTarget() == subject->getUnit() || curUnit->getOrderTarget() == subject->getUnit()) {
					if(subject->getUnit()->getGroundWeaponCooldown() == 0) {
						subject->attack(curUnit);
						return true;
					} else {
						subject->getUnit()->move(safestPoint);
						return true;
					}
				}			

			}
		}
	}

	///END NEW CODE


	//////////////
	
	int bestScoreSoFar = 0;
	UnitModel* bestTarget = NULL;
	int bestTarThresh = 0;
	for (vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->getUnit()->isVisible() && !usingGlobalTargetMap) { 
			continue;
		}
		if(cur->getType().isFlyer()  || cur->getUnit()->isLifted()) {
			continue;
		}
		if(subject->getArmyOwner() != NULL){
			if(subject->getArmyOwner()->isAlive()) {
				if(cur->getPosition().getDistance(subject->getArmyOwner()->getCentrePoint()) > 350) {
					continue;
				}
			}
		}

		if(cur->getType() == UnitTypes::Protoss_Photon_Cannon || cur->getType() == UnitTypes::Terran_Bunker || cur->getType() == UnitTypes::Zerg_Sunken_Colony || cur->getType() == UnitTypes::Zerg_Spore_Colony || cur->getType() == UnitTypes::Zerg_Creep_Colony) {
			if(subject->getPosition().getDistance(cur->getPosition()) <= subject->getType().sightRange()*1.1) {
				bestTarget = cur;
				break;
			}
		}
		if(bestTarget == NULL) {
			bestTarget = cur;
		} else {
			int targettingPenalty = 0;
			if(cur->getUnit()->isVisible()) {
				targettingPenalty = unitManager->calculateTargettingPenalty(cur->getUnit(), subject);
			}
			int candidateValue = targettingSystem->calculateValueOf(cur, targettingPenalty);
			std::vector<UnitModel*> enemyAllies = unitManager->getAllEnemyUnitsInRange(cur->getPosition(), 64);

			int splashScore = 0;
			
			for (vector<UnitModel*>::iterator it = enemyAllies.begin(); it != enemyAllies.end(); ++it)
			{
				UnitModel* cA = *it;
				if(cA->getType().isBuilding() && (cA->getType() != UnitTypes::Zerg_Spore_Colony && cA->getType() != UnitTypes::Zerg_Sunken_Colony && cA->getType() != UnitTypes::Protoss_Photon_Cannon && cA->getType() != UnitTypes::Terran_Bunker)) {
					continue;
				}
				if(cA->getType() == UnitTypes::Terran_Marine) {
					splashScore++;
				}
				if(cA->getType() == UnitTypes::Terran_Vulture) {
					splashScore++;
				}
				if(cA->getType() == UnitTypes::Zerg_Zergling) {
					splashScore++;
				}
				if(cA->getType() == UnitTypes::Zerg_Hydralisk) {
					splashScore++;
				}
				if(cA->getType() == UnitTypes::Protoss_Zealot) {
					splashScore++;
				}
				if(cA->getType() == UnitTypes::Protoss_Dragoon) {
					splashScore+=2;
				}
				if(cA->getType() == UnitTypes::Terran_Bunker) {
					splashScore+=4;
				}
				if(cA->getType() == UnitTypes::Protoss_Pylon) {
					splashScore+=2;
				}
				if(cA->getType() == UnitTypes::Protoss_Photon_Cannon) {
					splashScore+=4;
				}
				if(cA->getType().isWorker()) {
					splashScore+=4;
				}
			}

			if(splashScore >= 4) {
				candidateValue += 5000;
			}

			if(currentTarget != NULL) {
				if(cur == currentTarget) {
					candidateValue+=200;
				}
			}

			if(candidateValue > bestScoreSoFar) {
				bestScoreSoFar = candidateValue;
				bestTarget = cur;
				bestTarThresh = splashScore;
			}
		}
	}

	currentTarget = bestTarget;
	if(currentTarget != NULL) {
		if(subject->getUnit()->getGroundWeaponCooldown() == 0) {
			subject->attack(currentTarget);
			unitManager->declareTargetToMap(subject, bestTarget->getUnit());
			return true;
		}
	}


	return false;
}

void ReaverGeneralMicroBehaviour::nudge()
{

}

void ReaverGeneralMicroBehaviour::buildScarabs()
{
	if(subject->getUnit()->getScarabCount() < 10) {
		subject->getUnit()->train(UnitTypes::Protoss_Scarab);
	}
}


std::vector<Position> ReaverGeneralMicroBehaviour::findSafestNearbyPoints()
{
	ParticleGenerator* p = new ParticleGenerator(64, 396, subject->getPosition());
	std::vector<Position> v = p->generate();
	std::vector<Position> filteredPoints;
	std::vector<UnitModel*> enemies = unitManager->getAllEnemyUnitsInRange(subject->getPosition(), 256);

	for(std::vector<Position>::const_iterator i = v.begin(); i != v.end(); i++) {
		Position cur = *i;
		if(cur.getDistance(subject->getPosition()) < 128 || !Broodwar->isWalkable(cur.x()/8, cur.y()/8)) {
			continue;
		}
		bool dangerousPoint = false;
		for(std::vector<UnitModel*>::const_iterator it = enemies.begin(); it != enemies.end(); it++) {
			UnitModel* curEnemy = *it;
			if(cur.getDistance(curEnemy->getPosition()) <= 96) {
				dangerousPoint = true;
				break;
			}

		}
		if(!dangerousPoint) {
			filteredPoints.push_back(cur);
		}

	}

	return filteredPoints;

}