#include "ReaverShuttleMicroBehaviour.h"
#include "Army.h"
#include "BaseModel.h"
#include "MapData.h"

ReaverShuttleMicroBehaviour::ReaverShuttleMicroBehaviour( UnitModel* sub , UnitManager* u )
{
	subject = sub;
	unitManager = u;
	attacking = false;
	moving = false;
	targettingSystem = new TargetEvaluator(sub);
	currentTarget = NULL;
	targetArmy = NULL;
	id = PROTOSS_REAVER_CARRYING_SHUTTLE;
	anchor = Positions::None;
	pickUpTarget = NULL;
	pickingUpReaver = false;
	droppingOffReaver = false;
	dropRetries = 0;
}

bool ReaverShuttleMicroBehaviour::execute()
{
	if(targetArmy == NULL) {
		return false;
	}	
	if(subject->isBeingTargetted()) {
		moveSafely();
		return true;
	}
	findReavers();

	if(!reavers.empty()) {
		for (vector<UnitModel*>::iterator i = reavers.begin(); i != reavers.end(); ++i)
		{
			Unit* u = (*i)->getUnit();
			if(dropTimer[u] > 0) {
				dropTimer[u] = dropTimer[u]-1;
				//Broodwar->drawTextMap(u->getPosition().x()+8, u->getPosition().y()-16, "%d", dropTimer[u]);
			}
		}
	}

	if(!pickingUpReaver) {
	findDropTarget();
	if(droppingOffReaver) {
		dropOffReaver();
		return true;
	}
	}
	if(!droppingOffReaver) {
		findPickupTarget();
		if(pickingUpReaver) {
		pickUpReaver();
		return true;
		}
	}


	return moveSafely();
}

void ReaverShuttleMicroBehaviour::nudge()
{

}

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

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

bool ReaverShuttleMicroBehaviour::addReaver( UnitModel* r )
{
	if(reavers.size() < 2 || reavers.empty()) {
		reavers.push_back(r);
		//////Broodwar->sendText("added reaver");
		r->getUnit()->train(UnitTypes::Protoss_Scarab);
		r->getUnit()->train(UnitTypes::Protoss_Scarab);
		r->getUnit()->train(UnitTypes::Protoss_Scarab);
		r->getUnit()->train(UnitTypes::Protoss_Scarab);
		r->getUnit()->train(UnitTypes::Protoss_Scarab);
		r->getUnit()->rightClick(subject->getUnit());
		subject->getUnit()->load(r->getUnit(), true);
		return true;
	}
	return false;
}

void ReaverShuttleMicroBehaviour::findReavers()
{
	std::vector<UnitModel*> units = targetArmy->getMembers();
	reavers.clear();
	int numShuttles = 0;
	for (vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
	{
		if((*i)->isAlive()) {
			if((*i)->getType() == UnitTypes::Protoss_Reaver) {
				reavers.push_back((*i));
			}
			if((*i)->getType() == UnitTypes::Protoss_Shuttle) {
				numShuttles++;
			}
		}
	}
	if(reavers.empty() || reavers.size() < numShuttles) {
		subject->clearMicroBehaviour();
		targetArmy->removeFromArmy(subject);
		subject->clearArmyOwner();
		subject->getUnit()->move(unitManager->getFriendlyMainBase()->getPosition());
	}
}

void ReaverShuttleMicroBehaviour::pickUpReaver()
{
	if(pickingUpReaver) {
	if(pickUpTarget != NULL) {
		if(!pickUpTarget->isLoaded() && (pickUpTarget->getGroundWeaponCooldown() >= 3 || !targetArmy->isArmyUnderAttack())) {
			subject->getUnit()->rightClick(pickUpTarget);
			//pickUpTarget->rightClick(subject->getUnit());
			
		} else {
			pickingUpReaver = false;
			dropTimer[pickUpTarget] = 0;
		}
	}
	}
}

void ReaverShuttleMicroBehaviour::findPickupTarget()
{
	if(subject->getArmyOwner() != NULL) {
		if(subject->getArmyOwner()->countNumTypeInArmy(UnitTypes::Protoss_Dragoon) == 0 && subject->getArmyOwner()->countNumTypeInArmy(UnitTypes::Protoss_Zealot) == 0) {
			subject->getUnit()->unloadAll();
			return;
		}
	}
	if(!reavers.empty() && !pickingUpReaver) {
		for (vector<UnitModel*>::iterator i = reavers.begin(); i != reavers.end(); ++i)
		{
			UnitModel* cur = *i;
			// should pick up the reaver IF it isn't loaded AND
			// IF the army isn't under attack
			// OR IF the reaver has weapon cooldown > 0
			if(cur->getUnit()->isLoaded()) {
				continue;
			}
			if(dropTimer[cur->getUnit()] > 0) {
				continue;
			}
			if(cur->getQualitativeHP() <= 25 || cur->getQualitativeShields() <= 25) {
				continue;
			}
			if(!targetArmy->isArmyUnderAttack()) {
				pickingUpReaver = true;
				pickUpTarget = cur->getUnit();
				return;
			}
			if(cur->getUnit()->getGroundWeaponCooldown() > 0 && cur->isBeingTargetted()) {
				pickingUpReaver = true;
				pickUpTarget = cur->getUnit();
				return;
			}
			if(cur->isBeingTargetted() && cur->getShields() < 5 && cur->getHP() < 50) {
				pickingUpReaver = true;
				pickUpTarget = cur->getUnit();
				return;
			}
		}
	}
}

void ReaverShuttleMicroBehaviour::findDropTarget()
{
	if(targetArmy->isArmyUnderAttack() && !droppingOffReaver) {
		for (vector<UnitModel*>::iterator i = reavers.begin(); i != reavers.end(); ++i)
		{
			if((*i)->getUnit()->isLoaded() && (*i)->getUnit()->getGroundWeaponCooldown() == 0 && (*i)->getUnit()->getScarabCount() > 0 && ((*i)->getShields() >= 50)) {
				// find somewhere to drop him
				droppingOffReaver = true;
				anchor = subject->getPosition();
				dropOffTarget = (*i)->getUnit();
				dropTargetPos = targetArmy->getLastAttacker()->getPosition();
				dropRetries = 0;
				return;
			}
		}
	}
}

void ReaverShuttleMicroBehaviour::dropOffReaver()
{
	if(droppingOffReaver) {
	
		if(dropOffTarget->isLoaded()) {
			if(subject->getPosition().getDistance(dropTargetPos) >= 196) {
				if(subject->getArmyOwner() != NULL) {
					if(!MapData::walkability[dropTargetPos.x()/8][dropTargetPos.y()/8]  || dropTargetPos.getDistance(subject->getArmyOwner()->getCentrePoint()) > 350 || !Broodwar->isBuildable((TilePosition)subject->getPosition())) {
						ParticleGenerator* p = new ParticleGenerator(64, 312, subject->getArmyOwner()->getCentrePoint());
						std::vector<Position> v = p->generate();
						Position bestPointSoFar = Positions::None;
						int bestScoreSoFar = -100000;
						for(std::vector<Position>::const_iterator i = v.begin(); i != v.end(); i++) {
							Position cur = *i;
							if(!cur.isValid()) {
								cur = cur.makeValid();
							}
							if(MapData::walkability[cur.x()/8][cur.y()/8]) {
								dropTargetPos = cur;
								break;
							}
						}

					}
				}
				if(!subject->getUnit()->isMoving()) {
				subject->getUnit()->move(dropTargetPos);
				}

			} else {
			
				if(subject->getUnit()->unload(dropOffTarget)) {

				} else {
						dropRetries++;
						if(dropRetries >= 64) {
							dropTargetPos = subject->getArmyOwner()->getCentrePoint();
							dropRetries = 0;
						}
				}
				
			//	////Broodwar->sendText("trying to drop");
			}
		} 
		if(subject->getPosition().getDistance(dropTargetPos) <= 286) {
			if(!dropOffTarget->isLoaded()) {
				dropTimer[dropOffTarget] = 64;
				droppingOffReaver = false;
				bool shuttleEmpty = false;
				for (vector<UnitModel*>::iterator i = reavers.begin(); i != reavers.end(); ++i)
				{
					if((*i)->getUnit()->isLoaded()) {
						shuttleEmpty = false;
						break;
					} else {
						shuttleEmpty = true;
					}
				}

				if(shuttleEmpty) {
					subject->getUnit()->move(unitManager->getFriendlyMainBase()->getPosition());
				}


			}
		}
	}
}

bool ReaverShuttleMicroBehaviour::moveSafely()
{
	if(subject->getArmyOwner() != NULL) {
		if(subject->getArmyOwner()->getCentrePoint().getDistance(subject->getPosition()) > 300) {
			subject->getUnit()->move(subject->getArmyOwner()->getCentrePoint());
			return true;
		}
	}
	int avgX = 0;
	int avgY = 0;
	int livingMembers = 0;
	std::vector<UnitModel*> forces = targetArmy->getMembers();
	for (std::vector<UnitModel*>::iterator i = forces.begin(); i != forces.end(); ++i)
	{
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		//if(cur->getType() != UnitTypes::Protoss_Dragoon && cur->getType() != UnitTypes::Protoss_Reaver) {
		//	continue;
		//}
		avgX = avgX+cur->getPosition().x();
		avgY = avgY+cur->getPosition().y();
		livingMembers++;
	}

	Position avgPos = Positions::None;
	if(livingMembers == 0) {
		//////Broodwar->sendText("dead army!");
		return false;
	} else {
		avgX = avgX/livingMembers;
		avgY = avgY/livingMembers;
		avgPos = Position(avgX, avgY);
	}

	ParticleGenerator* p = new ParticleGenerator(64, 256, avgPos);
	std::vector<Position> v = p->generate();
	Position bestPointSoFar = Positions::None;
	int bestScoreSoFar = -100000;
	for(std::vector<Position>::const_iterator i = v.begin(); i != v.end(); i++) {
		Position cur = *i;
		if(cur.getDistance(subject->getPosition()) < 128) {
			continue;
		}
		int currentScore = 0;
		if(bestPointSoFar == Positions::None) {
			bestPointSoFar = cur;
		} else {
			// score point 1: the number of enemy units in weapons range of this point
			// ie. it's safety
			std::vector<UnitModel*> enemiesInRange = unitManager->getAllEnemyUnitsInRange(cur, UnitTypes::Protoss_Shuttle.sightRange()*1.2);
			for(std::vector<UnitModel*>::const_iterator it = enemiesInRange.begin(); it != enemiesInRange.end(); it++) {
				UnitModel* ncur = *it;
				if(ncur->getType().isWorker() || ncur->getType() == UnitTypes::Terran_Firebat || ncur->getType() == UnitTypes::Protoss_Zealot || ncur->getType() == UnitTypes::Protoss_Reaver || ncur->getType() == UnitTypes::Zerg_Zergling|| ncur->getType() == UnitTypes::Zerg_Ultralisk || ncur->getType() == UnitTypes::Zerg_Overlord || ncur->getType() == UnitTypes::Zerg_Queen || ncur->getType() == UnitTypes::Protoss_Shuttle || ncur->getType() == UnitTypes::Terran_Medic || ncur->getType() == UnitTypes::Terran_Siege_Tank_Siege_Mode || ncur->getType() == UnitTypes::Terran_Siege_Tank_Tank_Mode) {
					continue;
				}
				currentScore-=50;
			}


			currentScore += (5000-subject->getPosition().getDistance(unitManager->getClosestFriendlyBaseModel(subject->getPosition())->getPosition()));


			if(currentScore > bestScoreSoFar) {
				bestPointSoFar = cur;
				bestScoreSoFar = currentScore;
			}
		}
	}
	if(bestPointSoFar != Positions::None) {
	//	if(Broodwar->getFrameCount()%4 == 0) {
			subject->getUnit()->move(bestPointSoFar);

	//	}
	}

	return true;

}
