#include "UnitManager.h"
#include "BaseModel.h"
#include "Overseer.h"
#include "ExpandTask.h"
#include "Heap.h"
#include "MapData.h"
#include "AerialScoutBehaviour.h"
#include "BaseModelConsistencyMonitor.h"
#include "math.h"
//#include "Windows.h"

UnitManager::UnitManager(Overseer* ov) {
	overseer = ov;
	mis = new MapInformationSystem(this);
	//testArmy = new Army(ov);
	synapseCore = new Synapse(ov);
	pathfindingCallsThisFrame = 0;
	PATHFINDING_CALL_LIMIT = 10;
	GLOBAL_EXPANSION_THRESH = 4048;
	GLOBAL_EXPANSION_TIMER = 0;
	setPreferredDTStrat(PROTOSS_ROAMING_DARK_TEMPLAR);
	suspectLoc = Positions::None;
	pathRepo = new PathRepository();
	setUpRegionBlackList();
}

//************************************
// Method:    notifyCreate
// FullName:  UnitManager::notifyCreate
// Access:    public 
// Returns:   nothing
// Parameter: Unit * newUnit
// Comments:  nonef
//************************************
void UnitManager::notifyCreate(BWAPI::Unit* newUnit) {
	// general idea:
	// look to see if we already know about this unit
	// if not, create a new unitmodel to express it

	// we don't care about neutral stuff - like resource fields, critters etc.
	UnitType type = newUnit->getType();
	if((type.isNeutral() || type.isSpecialBuilding() || type.isMineralField())) {
		return;

	}
	if(type.isBuilding() && type.getRace() == BWAPI::Races::Zerg) {
		////Broodwar->sendText("found a %s", type.getName().c_str());
	}
	

	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		
		if((*i)->getUnit()->getID() == newUnit->getID()) {
			if((*i)->getType().isRefinery()  || (*i)->getType() == UnitTypes::Zerg_Spore_Colony || (*i)->getType() == UnitTypes::Zerg_Creep_Colony || (*i)->getType() == UnitTypes::Zerg_Sunken_Colony) {
				(*i)->setAlive(false);
			} else {
				return;
			}
		} 
	}
	
	// if we're here, we know we don't have the unit, so create a new model
	//////////Broodwar->sendText("Added a new unit model");
	UnitModel* newModel = new UnitModel(newUnit, this);
	unitModels.push_back(newModel);

	// also record this in the lookup table
	//unitModelsMap[newUnit] = newModel;
	unitModelsMap.insert(pair<Unit*,UnitModel*>(newUnit, newModel));
	if(type == UnitTypes::Spell_Scanner_Sweep) {
		//////Broodwar->sendText("added model for scanner sweep...!!!!");
	}

	// also alert air units if this was a newly discovered anti-air building
	if(!newModel->isOwnedByPlayer()) {
		UnitType t = newUnit->getType();
		if(t.isBuilding() && newUnit->getTilePosition() != TilePositions::None) {
			if(t == UnitTypes::Terran_Missile_Turret || t == UnitTypes::Terran_Bunker || t == UnitTypes::Protoss_Photon_Cannon || t == UnitTypes::Zerg_Spore_Colony) {
				alertVulnerableUnits(newUnit->getTilePosition());
			}
		}
	}

	// also record this in the list of bases
	if(newUnit->getType().isResourceDepot()) {

		// but first, is there already a base model in this area?
		BaseModel* base = getBaseModelInRegion(newModel->getRegion());
		if(base == NULL) {

		} else {
			if(base->isAlive()) {
				if(newUnit->getType().isResourceDepot()) {
					if(!base->getSubject()->getType().isResourceDepot()) {
						base->setSubject(newModel);
					}
				}
				return;
			} else {

			}
		}
		
		BaseModel* newBaseModel = new BaseModel(newModel, overseer);
		baseModelsMap[newUnit] = newBaseModel;

		if(newUnit->getPlayer() != Broodwar->self()) {
			//////Broodwar->sendText("added enemy base model");

			enemyBaseModels.push_back(newBaseModel);
			if(enemyBaseModels.size() == 1) {	
				//////Broodwar->sendText("found enemy main base");
				newBaseModel->setMainBase();
			}
		} else {
			//////Broodwar->sendText("added friendly base model");

			friendlyBaseModels.push_back(newBaseModel);
			if(friendlyBaseModels.size() == 1) {	
				//////Broodwar->sendText("found main base");
				newBaseModel->setMainBase();
			}
		}
	}
}

//************************************
// Method:    notifyDestroy
// FullName:  UnitManager::notifyDestroy
// Access:    public 
// Returns:   nothing
// Parameter: Unit * deadUnit
// Comments:  none
//************************************
void UnitManager::notifyDestroy(BWAPI::Unit* deadUnit) {
	// general idea:
	// look to see if we already know about this unit
	// if we do, remove it from our memory

	UnitType type = deadUnit->getType();
	if((type.isNeutral() || type.isSpecialBuilding() || type.isMineralField())) {
		return;
	}

	//////Broodwar->sendText("a %s was destroyed", deadUnit->getType().getName().c_str());

	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{	
		if((*i)->getUnit() == deadUnit) {

			// if this was a base, remove it from our list of base models
			//if((*i)->getUnit()->getType().isResourceDepot()) {

				// update friendly base models
				//for (vector<BaseModel*>::iterator k = friendlyBaseModels.begin(); k != friendlyBaseModels.end(); ++k)
				//{
				//	if((*k)->getSubject() == (*i)) {
						//////Broodwar->sendText("destroyed friendly base model");
						//	k = friendlyBaseModels.erase(k);
						//(*k)->getSubject()->setAlive(false);
				//		break;
				//	}
			//	}
			
				//for (vector<BaseModel*>::iterator k = enemyBaseModels.begin(); k != enemyBaseModels.end(); ++k)
				//{
				//	if((*k)->getSubject() == (*i)) {
						//k = enemyBaseModels.erase(k);
						//(*k)->getSubject()->setAlive(false);
					//	break;
					//}
				//}
			//}
			if((*i)->getType().isBuilding() && (*i)->isOwnedByPlayer()) {
				overseer->getBuildingPlacer()->freeTiles((*i)->getTilePosition(), (*i)->getType().tileWidth(), (*i)->getType().tileHeight());
			}
			
			(*i)->setAlive(false);

			if((*i)->getType().isRefinery()) {
				////Broodwar->sendText("erased a refinery");
			}
		}
	}
}

//************************************
// Method:    getAllUnits
// FullName:  UnitManager::getAllUnits
// Access:    public 
// Returns:   vector<UnitModel*>
// Comments:  none
//************************************
vector<UnitModel*> UnitManager::getAllUnits()
{
	return unitModels;
}

//************************************
// Method:    updateModel
// FullName:  UnitManager::updateModel
// Access:    public 
// Returns:   void
// Comments:  Keeps the model up-to-date in terms of remembering HP and positions of units we know about. 
//			  when applied to enemy units, maintains a belief space.
//************************************
void UnitManager::updateModel()
{
	if(Broodwar->getFrameCount() < 24) {
		return;
	}

	if(suspectLoc != Positions::None) {
		Broodwar->drawCircleMap(suspectLoc.x(), suspectLoc.y(), 32, BWAPI::Colors::Blue, true);
	}

	// firstly, get all units that we can see right now
	std::set<BWAPI::Unit*> gameUnits = Broodwar->getAllUnits();
	for (set<BWAPI::Unit*>::iterator i = gameUnits.begin(); i != gameUnits.end(); ++i) {
		// get the model of this unit
		UnitModel* model = unitModelsMap[(*i)];
		if(model != NULL) { // at the start, before the initial population is detected, we might get errors so we need to do this
			BWAPI::Unit* gameUnit = (*i);
			if(gameUnit->getType() == UnitTypes::Resource_Vespene_Geyser) {
				model->setAlive(false);
			}

			if(model->getType().isRefinery() && !model->getUnit()->getType().isRefinery()) {
				model->setAlive(false);
			}


			if(!model->isAlive()) {
				continue;
			}
			
			if(!model->isOwnedByPlayer()) {
				//Broodwar->drawTextMap(model->getPosition().x(), model->getPosition().y()-16, "%d", getNumFriendlyUnitsAttacking(model));
			} 
			//model->drawDebuggingInformation();
			if(!gameUnit->isVisible()) {
				continue;
			}
			// now we can start updating data
			model->setLastKnownHitPointsAndShields(gameUnit->getHitPoints(), gameUnit->getShields());

			if(model->getHP() <= 0) {
				model->setAlive(false);
			}
			if(Broodwar->getFrameCount()%24==0) {
				if(model->getType().isBuilding()) {
					
					model->setLastKnownRegion(BWTA::getRegion(model->getPosition()));

				} else {
					if(BWTA::getNearestChokepoint(model->getPosition())->getCenter().getDistance(model->getPosition()) > 64) {
						model->setLastKnownRegion(BWTA::getRegion(model->getPosition())); // causing crashes?
					}
				}

				BaseModel* br = getBaseModelInRegion(model->getRegion());
					if(br == NULL) {
						if(model->getType().isBuilding() || model->getType().isWorker()) {
							model->setBaseOwner(overseer->getUnitManager()->getClosestFriendlyBaseModel(model->getPosition()));
						}
					} else {
						model->setBaseOwner(br);
					}
					
			

			}

			
			if(Broodwar->getFrameCount()%64==0) {
				if(model->getType().isBuilding()) {

					std::vector<UnitModel*> unitsOnTile = getAllUnitsInRange(model->getPosition(), 64);

					if(unitsOnTile.empty()) {
						model->setAlive(false);
					} else {
						bool found = false;
						for(std::vector<UnitModel*>::const_iterator it = unitsOnTile.begin(); it != unitsOnTile.end(); it++) {
							UnitModel* c = *it;
							if(c->getType() == model->getType()) {
								found = true;
								break;
							}
							if(c->getType() == UnitTypes::Resource_Vespene_Geyser) {
								found = false;
								break;
							}
						}
						if(!found) {
							model->setAlive(false);
						}
					}
				}
			}

			if(Broodwar->getFrameCount()%4==0) {
				model->setLastKnownPosition(gameUnit->getPosition());
				model->setLastKnownTilePosition(gameUnit->getTilePosition());
				model->setLastKnownUnitType(gameUnit->getType());
				model->setUnderThreat(model->checkUnderThreat());
				
				model->setLastKnownStasisStatus(gameUnit->isStasised());

				model->executeMicroBehaviour();
			}
		}

	}

	if(Broodwar->getFrameCount()>64) {
		// next update all of the base models
		//if(Broodwar->getFrameCount()%2 == 0) {
		for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i) {
			BaseModel* base = (*i);
			base->updateBaseModel(unitModels);
		}
		for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i) {
			BaseModel* base = (*i);
			base->updateBaseModel(unitModels);
		}

		//}
		mis->update();
		mis->drawMap();


		for(vector<Army*>::iterator i = activeArmies.begin(); i!= activeArmies.end(); ++i) {
			Army* c = *i;
		if(c->isAlive()) c->monitor();
			
		}


		if(hasBuildingComplete(UnitTypes::Protoss_Gateway) && hasBuildingComplete(UnitTypes::Protoss_Cybernetics_Core)) {
			if(synapseCore->isRunning()) {
				synapseCore->monitor();
			}
		}

		if(Broodwar->getFrameCount()%64 ==0) {
			marshallIdleMilitaryUnits();
		}

		manageExpansions();

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


	}

}

//************************************
// Method:    drawBeliefs
// FullName:  UnitManager::drawBeliefs
// Access:    public 
// Returns:   void
// Comments:  none
//************************************
void UnitManager::drawBeliefs()
{
	BWTA::Region* r = getBelievedEnemyMainBaseRegion();
	if(r != NULL) {
	//Broodwar->drawEllipseMap(r->getCenter().x(), r->getCenter().y()-64, 32, 32, BWAPI::Colors::White, true);
	}
	/*
	std::set<Unit*> allUnits = Broodwar->getAllUnits();
	for(std::set<Unit*>::const_iterator i = allUnits.begin(); i != allUnits.end(); ++i) {
	Unit* curMin = *i;
	std::stringstream sstr;
	sstr << curMin->getType().getName().c_str();
	const std::string result = sstr.str();
	////Broodwar->drawTextMap(curMin->getInitialPosition().x(), curMin->getInitialPosition().y()+32, result.c_str());
	}


	// draw all the units with HP indicators etc.
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{	if(!(*i)->isAlive()) { continue; }
	UnitModel* unit = *i;

	// convert hp to string
	std::stringstream sstr;
	if(unit->isOwnedByPlayer()) {
	sstr << '\x07';
	} else {
	sstr << '\x08';
	}
	sstr << unit->getQualitativeHP();
	const std::string result = sstr.str();
	////Broodwar->drawTextMap(unit->getPosition().x(), unit->getPosition().y(), result.c_str());
	}
	*/
	// draw all the base locations
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* base = *i;
		base->drawBaseModel();
	}
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* base = *i;
		base->drawBaseModel();
	}
	/*
	if(Broodwar->getFrameCount() > 64) {
	std::set<BWTA::BaseLocation*> regions = BWTA::getBaseLocations();

	for (set<BWTA::BaseLocation*>::iterator i = regions.begin(); i != regions.end(); ++i)
	{
	BWTA::BaseLocation* cur = *i;
	Position centre = cur->getRegion()->getCenter();
	if(knownBaseInRegion(centre)) {
	//Broodwar->drawCircleMap(centre.x(), centre.y(), 64, BWAPI::Colors::Red, true);
	} else {
	//Broodwar->drawCircleMap(centre.x(), centre.y(), 64, BWAPI::Colors::Green, true);
	}
	}

	}
	*/
}

//************************************
// Method:    getAllBaseModels
// FullName:  UnitManager::getAllBaseModels
// Access:    public 
// Returns:   vector<BaseModel*>
// Comments:  returns all the base models we know about
//************************************
vector<BaseModel*> UnitManager::getFriendlyBaseModels()
{
	return friendlyBaseModels;
}

//************************************
// Method:    getUnitModelFromMap
// FullName:  UnitManager::getUnitModelFromMap
// Access:    public 
// Returns:   UnitModel*
// Parameter: Unit * u
// Comments:  none
//************************************
UnitModel* UnitManager::getUnitModelFromMap( Unit* u )
{
	std::map<Unit*, UnitModel*>::const_iterator k = unitModelsMap.find(u);
	if(k == unitModelsMap.end()) {
		return NULL;
	}
	return (*k).second;
}

//************************************
// Method:    getAllUnitsOfType
// FullName:  UnitManager::getAllUnitsOfType
// Access:    public 
// Returns:   vector<UnitModel*>
// Parameter: UnitType t
// Comments:  none
//************************************
vector<UnitModel*> UnitManager::getAllFriendlyUnitsOfType( UnitType t )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType() == t && cur->isOwnedByPlayer()) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getAllEnemyUnitsOfType( UnitType t )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType() == t && !cur->isOwnedByPlayer()) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}



//************************************
// Method:    getEnemyBaseModels
// FullName:  UnitManager::getEnemyBaseModels
// Access:    public 
// Returns:   vector<BaseModel*>
// Comments:  none
//************************************
vector<BaseModel*> UnitManager::getEnemyBaseModels()
{
	return enemyBaseModels;
}

bool UnitManager::hasBuildingComplete( UnitType t )
{
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* base = *i;
		if(base->hasBuildingComplete(t)) {
			return true;
		}
	}
	return false;
}

bool UnitManager::hasBuildingUnderConstruction( UnitType t )
{
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* base = *i;
		if(base->hasBuildingUnderConstruction(t)) {
			return true;
		}
	}
	return false;
}


//************************************
// Method:    getBaseModelFromMap
// FullName:  UnitManager::getBaseModelFromMap
// Access:    public 
// Returns:   BaseModel*
// Parameter: Unit * u
// Comments:  none
//************************************
BaseModel* UnitManager::getBaseModelFromMap( Unit* u )
{
	return baseModelsMap[u];
}

//************************************
// Method:    getFriendlyMilitaryUnits
// FullName:  UnitManager::getFriendlyMilitaryUnits
// Access:    public 
// Returns:   vector<UnitModel*>
// Comments:  none
//************************************
vector<UnitModel*> UnitManager::getFriendlyMilitaryUnits()
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{	if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer() && (cur->getType() == UnitTypes::Protoss_High_Templar || cur->getType() == UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_Dragoon|| cur->getType() == UnitTypes::Protoss_Zealot|| cur->getType() == UnitTypes::Protoss_Reaver)) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getEnemyMilitaryUnits()
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(!cur->isOwnedByPlayer() && cur->getType().canAttack() && !cur->getType().isBuilding() && !cur->isOwnedByPlayer() && !cur->getType().isWorker()) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}


vector<UnitModel*> UnitManager::getEnemyMilitaryUnitsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		UnitModel* cur = *i;
		if(!cur->isOwnedByPlayer() && !cur->getType().isWorker() && !cur->getType().isBuilding() && cur->getType() != UnitTypes::Terran_Medic) {
			if(cur->getPosition().getDistance(p) < range) {
				requestedCohort.push_back(cur);
			}

		}
	}
	return requestedCohort;
}



MapInformationSystem* UnitManager::getMapInformationSystem()
{
	return mis;
}

Army* UnitManager::grabArmy()
{
	Army* newArmy = new Army(overseer);
	int numShuttles = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		if(!(*i)->isOwnedByPlayer()) { continue;}
		if(!(*i)->getUnit()->isCompleted()) { continue; }
		if((*i)->getCurrentTaskType() == HARASS) { continue; }
		UnitModel* cur = *i;
		if(cur->getType() == UnitTypes::Protoss_High_Templar || cur->getType() == UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_Shuttle || cur->getType() == UnitTypes::Protoss_Observer || cur->getType() == UnitTypes::Protoss_Zealot || cur->getType() == UnitTypes::Protoss_Dragoon || cur->getType() == UnitTypes::Protoss_Arbiter|| cur->getType() == UnitTypes::Protoss_Dark_Templar) {
			newArmy->addToArmy(cur);
			if(cur->getType() == UnitTypes::Protoss_Shuttle) {
				numShuttles++;
			}
			if(cur->getType() == UnitTypes::Protoss_Dragoon) {
				cur->setMicroBehaviour(PROTOSS_ARC_DRAGOON);
			}
			if(cur->getType() == UnitTypes::Protoss_Observer) {
				AerialScoutBehaviour* a = (AerialScoutBehaviour*)cur->getMicroBehaviour();
				a->relinquishExploreTarget();
				cur->clearMicroBehaviour();
			}
		}
	}
	int numReavers = 0;
	if(numShuttles != 0) {
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		if(!(*i)->isOwnedByPlayer()) { continue;}
		if(!(*i)->getUnit()->isCompleted()) { continue; }
		if((*i)->getCurrentTaskType() == HARASS) { continue; }
		UnitModel* cur = *i;
		if(cur->getType() == UnitTypes::Protoss_Reaver && numReavers < 2) {
			newArmy->addToArmy(cur);
			numReavers++;
		}
		if(numReavers >= 2*numShuttles) {
			break;
		}
	}
	if(numReavers != 0) {
		while(numShuttles > numReavers*2) {
			newArmy->removeFromArmy(UnitTypes::Protoss_Shuttle);
			numShuttles--;
		}
	}

	}
	if(numShuttles == 0) {
		for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
		{
			if(!(*i)->isAlive()) { continue; }
			if(!(*i)->isOwnedByPlayer()) { continue;}
			if(!(*i)->getUnit()->isCompleted()) { continue; }
			if((*i)->getCurrentTaskType() == HARASS) { continue; }
			UnitModel* cur = *i;
			if(cur->getType() == UnitTypes::Protoss_Reaver && numReavers < 2) {
				newArmy->addToArmy(cur);
				numReavers++;
			}
			if(numReavers >= 3) {
				break;
			}
		}
	}

	if(getEnemyBaseModels().empty()) {
		////Broodwar->sendText("no known enemy bases");
	} else {
		newArmy->initialize();
	//	newArmy->setTarget(getEnemyMainBase()->getSubject()->getRegion());
		newArmy->formUp();
		activeArmies.push_back(newArmy);

		return newArmy;
	}
	return NULL;	
}

Army* UnitManager::grabArmy( int armyCalibration )
{
	Army* newArmy = new Army(overseer);
	int numAdded = 0;

	int numArbiters = 0;
	int numObservers = 0;

	int numShuttles = 0;
	int numReavers = 0;

	int MAX_ARBITERS = 2;
	int MAX_OBSERVERS = 1;
	int MAX_SHUTTLES = 2;
	int MAX_REAVERS = 4;

	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		if(!(*i)->isOwnedByPlayer()) { continue;}
		if(!(*i)->getUnit()->isCompleted()) { continue; }
		if((*i)->getArmyOwner() != NULL) { continue; }


		UnitModel* cur = *i;
		if(cur->getType() == UnitTypes::Protoss_Archon || cur->getType() == UnitTypes::Protoss_High_Templar || cur->getType() == UnitTypes::Protoss_Shuttle || cur->getType() == UnitTypes::Protoss_Observer || cur->getType() == UnitTypes::Protoss_Zealot || cur->getType() == UnitTypes::Protoss_Dragoon || cur->getType() == UnitTypes::Protoss_Arbiter) {

			if(cur->getType() == UnitTypes::Protoss_Arbiter) {
				if(numArbiters < MAX_ARBITERS) {
					numArbiters++;
				} else {
					continue;
				}
			}

			if(cur->getType() == UnitTypes::Protoss_Shuttle) {
				numShuttles++;
				if(numShuttles > MAX_SHUTTLES) {
					continue;
				}
			} 
			

			if(cur->getType() == UnitTypes::Protoss_Observer) {
				if(numObservers < MAX_OBSERVERS) {
					numObservers++;
					if(cur->getMicroBehaviour() != NULL) {
						AerialScoutBehaviour* a = (AerialScoutBehaviour*)cur->getMicroBehaviour();
						a->relinquishExploreTarget();
						cur->clearMicroBehaviour();
					}
				} else {
					continue;
				}
			} 
			newArmy->addToArmy(cur);

		
			if(numAdded < armyCalibration) {
				if(cur->getType() != UnitTypes::Protoss_Shuttle && cur->getType() != UnitTypes::Protoss_Arbiter && cur->getType() != UnitTypes::Protoss_Observer) {
					numAdded++;
				}
			} else {
				////Broodwar->sendText("found: %d units!", numAdded);
				break;
			}			
		}
	}

	if(numShuttles != 0) {
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		if(!(*i)->isOwnedByPlayer()) { continue;}
		if(!(*i)->getUnit()->isCompleted()) { continue; }
		UnitModel* cur = *i;
		if(cur->getType() == UnitTypes::Protoss_Reaver) {

			if(numReavers < numShuttles*2) {
				newArmy->addToArmy(cur);
				numReavers++;
				if(numReavers == MAX_REAVERS) {
					break;
				}
			} else {
				break;
			}
		}
	}
	while(numReavers > numShuttles*2) {
		newArmy->removeFromArmy(UnitTypes::Protoss_Reaver);
		numReavers--;
	}


	}


	//if(numReavers == 0 && numShuttles != 0) {
//		newArmy->removeFromArmy(UnitTypes::Protoss_Shuttle);
//	}

		//newArmy->setTarget(getEnemyMainBase()->getSubject()->getRegion());
		newArmy->initialize();
		newArmy->formUp();
		activeArmies.push_back(newArmy);
		return newArmy;
	
}

void UnitManager::testFormArmy()
{
	////testArmy->reform();
}

vector<UnitModel*> UnitManager::getEnemyBuildings()
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType().isBuilding() && !cur->isOwnedByPlayer()) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getFriendlyBuildings()
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType().isBuilding() && cur->isOwnedByPlayer()) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}

void UnitManager::testMoveArmy()
{
	//testArmy->nextWayPoint();
}

map<UnitType,std::stack<int>> UnitManager::getPendingBehaviours()
{
	return pendingBehavioursStack;
}

void UnitManager::queueBehaviour( UnitType u, int behaviourID )
{
	pendingBehavioursStack[u].push(behaviourID);
}

void UnitManager::dequeueBehaviour( UnitType u )
{
	if(!pendingBehavioursStack[u].empty()) {
		pendingBehavioursStack[u].pop();
	}
}

bool UnitManager::hasUnit( UnitType t )
{
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType() == t && cur->isOwnedByPlayer()) {
		return true;
	}
	}
	return false;
}

bool UnitManager::hasUnit( UnitType t, int num )
{
	int found = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType() == t && cur->isOwnedByPlayer()) {
		found++;
	}
	}
	return found >= num;
}

vector<UnitModel*> UnitManager::getNFreeUnitsOfType( UnitType r, int n )
{
	std::vector<UnitModel*> units;
	int found = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType() == r && cur->isOwnedByPlayer()) {

		if(found < n || n == -1) {
			units.push_back(cur);
			found++;
		} else {
			break;
		}

	}
	}
	if(n > 0 && units.size() != n) {
		units.clear();
	}
	return units;
}

bool UnitManager::knownBaseInRegion( Position p )
{
	BWTA::Region* reg = BWTA::getRegion(p);

	for (vector<BaseModel*>::iterator it = enemyBaseModels.begin(); it != enemyBaseModels.end(); ++it)
	{
		BaseModel* cur = *it;
		if(cur->isAlive()) {
			if(reg == cur->getBaseRegion()) {
				return true;
			}
		}
	}

	// note: this method is a bit of a hack. there are more robust ways of doing this later.
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
			if(reg == cur->getBaseRegion()) {
				return true;
			}
		}
	}

	// finally, lets see if we're attempting to expand to this base
	std::deque<TaskBase*> tasks = overseer->getArbitrator()->getActiveTasks();

	for (deque<TaskBase*>::iterator itt = tasks.begin(); itt != tasks.end(); ++itt)
	{
		TaskBase* cur = *itt;
		if(cur->getTaskType() == EXPAND && cur->isInitialized()) {
			ExpandTask* ex = (ExpandTask*)cur;
			if(BWTA::getRegion(ex->getTargetPosition()) == reg) {
				return true;
			}
		}
	}

	return false;


}

void UnitManager::initialize()
{
	std::set<BWTA::Region*> regions = BWTA::getRegions();

	for (set<BWTA::Region*>::iterator i = regions.begin(); i != regions.end(); ++i)
	{
		BWTA::Region* cur = *i;
		//knownBaseModelsMap[cur] = NULL;
		//////Broodwar->sendText("set region to null base model");
	}
}


//************************************
// Method:    AstarSearchPath
// FullName:  UnitManager::AstarSearchPath
// Access:    public 
// Returns:   std::vector<BWAPI::TilePosition>
// Parameter: BWAPI::TilePosition start
// Parameter: BWAPI::TilePosition end
// Comments:  Adapted from A-Star mechanism present in BWTA lib http://code.google.com/p/bwta/
//************************************
std::vector<BWAPI::TilePosition> UnitManager::AstarSearchPath(BWAPI::TilePosition start, BWAPI::TilePosition end, int granularity)
{

	BWTA::Heap<BWAPI::TilePosition,int> openTiles(true);
	std::map<BWAPI::TilePosition,int> gmap;
	std::map<BWAPI::TilePosition,BWAPI::TilePosition> parent;
	std::set<BWAPI::TilePosition> closedTiles;
	openTiles.push(std::make_pair(start,0));
	gmap[start]=0;
	parent[start]=start;
	while(!openTiles.empty())
	{
		BWAPI::TilePosition p=openTiles.top().first;
		if (p.getDistance(end) <= granularity)
		{
			std::vector<BWAPI::TilePosition> reverse_path;
			while(p!=parent[p])
			{
				reverse_path.push_back(p);
				p=parent[p];
			}
			reverse_path.push_back(start);
			std::vector<BWAPI::TilePosition> path;
			for(int i=reverse_path.size()-1;i>=0;i--)
				path.push_back(reverse_path[i]);
			return path;
		}
		int fvalue=openTiles.top().second;
		int gvalue=gmap[p];
		openTiles.pop();
		closedTiles.insert(p);
		int minx=max(p.x()-granularity,0);
		int maxx=min(p.x()+granularity,BWAPI::Broodwar->mapWidth()-granularity);
		int miny=max(p.y()-granularity,0);
		int maxy=min(p.y()+granularity,BWAPI::Broodwar->mapHeight()-granularity);
		int granularityConstant = granularity/2;
		if(granularity == 1) {
			granularityConstant = 1;
		}
		for(int x=minx;x<=maxx;x+=granularityConstant)
			for(int y=miny;y<=maxy;y+=granularityConstant)
			{
				if (!MapData::lowResWalkability[x][y]) continue;
				if (p.x() != x && p.y() != y && !MapData::walkability[p.x()][y] && !MapData::walkability[x][p.y()]) continue;



				BWAPI::TilePosition t(x,y);
				if (closedTiles.find(t)!=closedTiles.end()) continue;


				TilePosition pos = TilePosition(p.x(), p.y());
				bool cont = false;
				std::set<Unit*> mins = Broodwar->getStaticMinerals();

				for(std::set<Unit*>::const_iterator i = mins.begin(); i != mins.end(); ++i) {
					Unit* curMin = *i;
					//if(curMin->get) {
					Position initPos = curMin->getInitialPosition();
					if(initPos.getDistance((Position)pos) < 128) {
						if(BWTA::getNearestBaseLocation(initPos)->getPosition().getDistance(initPos) > 100) {
							cont = true;
							break;
						}
					}
				}
				if(cont) {
					continue;
				}


				int g=gvalue+10;
				if (x!=p.x() && y!=p.y()) g+=4;
				int dx=abs(x-end.x());
				int dy=abs(y-end.y());

				int h=abs(dx-dy)*10+min(dx,dy)*14;


				int f=g+h;
				if (gmap.find(t)==gmap.end() || g<gmap.find(t)->second)
				{
					gmap[t]=g;
					openTiles.set(t,f);
					parent[t]=p;
				}
			}
	}
	std::vector<BWAPI::TilePosition> nopath;
	return nopath;
}


std::vector<BWAPI::TilePosition> UnitManager::threatAwareAstarSearchPathGround( BWAPI::TilePosition start, BWAPI::TilePosition end )
{
	if(pathfindingCallsThisFrame >= PATHFINDING_CALL_LIMIT) {
		std::vector<BWAPI::TilePosition> nopath;
		return nopath;
	} else {
		pathfindingCallsThisFrame++;
	}
	BWTA::Heap<BWAPI::TilePosition,int> openTiles(true);
	std::map<BWAPI::TilePosition,int> gmap;
	std::map<BWAPI::TilePosition,BWAPI::TilePosition> parent;
	std::set<BWAPI::TilePosition> closedTiles;
	openTiles.push(std::make_pair(start,0));
	gmap[start]=0;
	parent[start]=start;
	while(!openTiles.empty())
	{
		BWAPI::TilePosition p=openTiles.top().first;
		if (p==end)
		{
			std::vector<BWAPI::TilePosition> reverse_path;
			while(p!=parent[p])
			{
				reverse_path.push_back(p);
				p=parent[p];
			}
			reverse_path.push_back(start);
			std::vector<BWAPI::TilePosition> path;
			for(int i=reverse_path.size()-1;i>=0;i--)
				path.push_back(reverse_path[i]);
			return path;
		}
		int fvalue=openTiles.top().second;
		int gvalue=gmap[p];
		openTiles.pop();
		closedTiles.insert(p);
		int minx=max(p.x()-1,0);
		int maxx=min(p.x()+1,BWAPI::Broodwar->mapWidth()-1);
		int miny=max(p.y()-1,0);
		int maxy=min(p.y()+1,BWAPI::Broodwar->mapHeight()-1);
		for(int x=minx;x<=maxx;x++)
			for(int y=miny;y<=maxy;y++)
			{
				if (!MapData::lowResWalkability[x][y]) continue;
				if (p.x() != x && p.y() != y && !MapData::buildability[p.x()][y] && !MapData::buildability[x][p.y()]) continue;
				BWAPI::TilePosition t(x,y);
				if (closedTiles.find(t)!=closedTiles.end()) continue;

				int g=gvalue+10;
				if (x!=p.x() && y!=p.y()) g+=4;
				int dx=abs(x-end.x());
				int dy=abs(y-end.y());

				int h=abs(dx-dy)*10+min(dx,dy)*14;
				int f=g;
				// better way to do this: put it in a map
				for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
				{if(!(*i)->isAlive()) { continue; }
				UnitModel* cur = *i;
				//if(!cur->isOwnedByPlayer()) {
				Position pd = (Position)p;
				if(cur->getType() == UnitTypes::Protoss_Photon_Cannon) {
					if(pd.getDistance(cur->getPosition()) <= UnitTypes::Protoss_Photon_Cannon.groundWeapon().maxRange()) {
						f = g+(100000-pd.getDistance(cur->getPosition()));
						g = 100000-pd.getDistance(cur->getPosition());
					}
				}
				if(cur->getType() == UnitTypes::Terran_Bunker) {
					if(pd.getDistance(cur->getPosition()) <= UnitTypes::Terran_Marine.groundWeapon().maxRange()+164) {
						f = g+(100000-pd.getDistance(cur->getPosition()));
						g = 100000-pd.getDistance(cur->getPosition());
					}
				}
				//}
				}


				if ((gmap.find(t)==gmap.end() || g<gmap.find(t)->second))
				{
					gmap[t]=g;
					openTiles.set(t,f);
					parent[t]=p;
				}
			}
	}
	std::vector<BWAPI::TilePosition> nopath;
	return nopath;
}

std::vector<BWAPI::TilePosition> UnitManager::threatAwareAstarSearchPathAir(BWAPI::TilePosition start, BWAPI::TilePosition end) {
	return threatAwareAstarSearchPathAir(start, end, 2);
}

std::vector<BWAPI::TilePosition> UnitManager::threatAwareAstarSearchPathAir( BWAPI::TilePosition start, BWAPI::TilePosition end, int granularity )
{
	BWTA::Heap<BWAPI::TilePosition,int> openTiles(true);
	std::map<BWAPI::TilePosition,int> gmap;
	std::map<BWAPI::TilePosition,BWAPI::TilePosition> parent;
	std::set<BWAPI::TilePosition> closedTiles;
	openTiles.push(std::make_pair(start,0));
	gmap[start]=0;
	parent[start]=start;
	int GRAIN = granularity;
	std::vector<UnitModel*> cans = getAllEnemyUnitsOfType(UnitTypes::Protoss_Photon_Cannon);
	std::vector<UnitModel*> bks = getAllEnemyUnitsOfType(UnitTypes::Terran_Bunker);
	std::vector<UnitModel*> trt = getAllEnemyUnitsOfType(UnitTypes::Terran_Missile_Turret);
	std::vector<UnitModel*> spc = getAllEnemyUnitsOfType(UnitTypes::Zerg_Spore_Colony);
	cans.insert(cans.end(), bks.begin(), bks.end());
	cans.insert(cans.end(), trt.begin(), trt.end());
	cans.insert(cans.end(), spc.begin(), spc.end());
	while(!openTiles.empty())
	{
		BWAPI::TilePosition p=openTiles.top().first;
		if (p.getDistance(end) <= GRAIN*2)
		{
			std::vector<BWAPI::TilePosition> reverse_path;
			while(p!=parent[p])
			{
				reverse_path.push_back(p);
				p=parent[p];
			}
			reverse_path.push_back(start);
			std::vector<BWAPI::TilePosition> path;
			for(int i=reverse_path.size()-1;i>=0;i--)
				path.push_back(reverse_path[i]);
			return path;
		}
		int fvalue=openTiles.top().second;
		int gvalue=gmap[p];
		openTiles.pop();
		closedTiles.insert(p);
		int minx=max(p.x()-GRAIN,0);
		int maxx=min(p.x()+GRAIN,BWAPI::Broodwar->mapWidth()-GRAIN);
		int miny=max(p.y()-GRAIN,0);
		int maxy=min(p.y()+GRAIN,BWAPI::Broodwar->mapHeight()-GRAIN);
		for(int x=minx;x<=maxx;x+=GRAIN)
			for(int y=miny;y<=maxy;y+=GRAIN)
			{
				//if (!MapData::lowResWalkability[x][y]) continue;
				//if (p.x() != x && p.y() != y && !MapData::walkability[p.x()][y] && !MapData::walkability[x][p.y()]) continue;



				BWAPI::TilePosition t(x,y);
				if(!t.isValid()) {
					t = t.makeValid();
				}
				if (closedTiles.find(t)!=closedTiles.end()) continue;


				


				int g=1+0.1*(gvalue-1);
				if (x!=p.x() && y!=p.y()) g+=4;
				int dx=abs(x-end.x());
				int dy=abs(y-end.y());

				int h=abs(dx-dy)*10+min(dx,dy)*14;


				TilePosition pos = TilePosition(p.x(), p.y());
				bool cont = false;




				for(std::vector<UnitModel*>::const_iterator i = cans.begin(); i != cans.end(); ++i) {
					UnitModel* cur = *i;
					//if(curMin->get) {
					Position initPos = cur->getPosition();
					if(initPos.getDistance((Position)pos) <= UnitTypes::Protoss_Photon_Cannon.sightRange()*1.) {
						//if(BWTA::getNearestBaseLocation(initPos)->getPosition().getDistance(initPos) > 100) {
						//cont = true;
						//break;
						//}
						g+=1000;
					}
				}
				if(cont) {
					continue;
				}


				int f=g;
				if (gmap.find(t)==gmap.end() || g<gmap.find(t)->second)
				{
					gmap[t]=g;
					openTiles.set(t,f);
					parent[t]=p;
				}
			}
	}
	std::vector<BWAPI::TilePosition> nopath;
	return nopath;
}

vector<UnitModel*> UnitManager::getEnemyBuildingsInRegionOf( TilePosition p )
{
	BWTA::Region* startRegion = BWTA::getRegion(p);
	std::vector<UnitModel*> units;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive() || (*i)->getType() == UnitTypes::Resource_Vespene_Geyser) { continue; }
	UnitModel* cur = *i;
	if(cur->getType().isBuilding() && !cur->isOwnedByPlayer()) {
		if(BWTA::getRegion(cur->getTilePosition()) == startRegion) {
			units.push_back(cur);
		}
	}
	}
	return units;

}

vector<UnitModel*> UnitManager::getAllEnemyUnitsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive() || (*i)->getType() == UnitTypes::Resource_Vespene_Geyser || (*i)->getUnit()->getPlayer() != Broodwar->enemy()) { continue; }
	UnitModel* cur = *i;
	if(!cur->isOwnedByPlayer()) {
		if(cur->getPosition().getApproxDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

Synapse* UnitManager::getSynapse()
{
	return synapseCore;
}

int UnitManager::countFriendlyBuildings( UnitType t )
{
	std::vector<UnitModel*> requestedCohort;
	int c = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer() && cur->getType().isBuilding()) {
		if(cur->getType() == t) {
			c++;
		}
	}
	}
	return c;
}

void UnitManager::requestDefense( TilePosition t )
{
	//////Broodwar->sendText("------ requesting defense ------");
	GuardTask* g = new GuardTask(t, overseer);
	overseer->getArbitrator()->stageNewTaskUrgent(g);
}

void UnitManager::requestDefense( TilePosition t, int priority )
{
	//////Broodwar->sendText("------ requesting defense with priority: %d------", priority);
	GuardTask* g = new GuardTask(t, overseer, priority);
	overseer->getArbitrator()->stageNewTask(g);
}

void UnitManager::requestDefense( Unit* t, int priority )
{
	//////Broodwar->sendText("------ requesting defense with priority: %d------", priority);
	GuardTask* g = new GuardTask(t, overseer, priority);
	overseer->getArbitrator()->stageNewTask(g);
}


void UnitManager::requestDefense( TilePosition t, int priority, bool guardChoke )
{
	//////Broodwar->sendText("------ requesting defense with priority: %d------", priority);
	GuardTask* g = new GuardTask(t, overseer, priority, guardChoke);
	overseer->getArbitrator()->stageNewTask(g);
}

void UnitManager::requestDefense( std::vector<TilePosition> path, int priority )
{
	GuardTask* g = new GuardTask(path, overseer, priority);
	overseer->getArbitrator()->stageNewTask(g);
}


void UnitManager::alertVulnerableUnits(TilePosition t)
{
	//////Broodwar->sendText("alerting air units");
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isAlive() && cur->getUnit()->isCompleted() && cur->isOwnedByPlayer() && (cur->getType().isFlyer() && cur->isFollowingPath()))  {
		cur->promptPathReplan(t);
	}
	}
}

std::vector<BWAPI::TilePosition> UnitManager::threatAwareAstarSearchPathGroundAvoidUnits( BWAPI::TilePosition start, BWAPI::TilePosition end )
{
	if(pathfindingCallsThisFrame >= PATHFINDING_CALL_LIMIT) {
		std::vector<BWAPI::TilePosition> nopath;
		return nopath;
	} else {
		pathfindingCallsThisFrame++;
	}
	BWTA::Heap<BWAPI::TilePosition,int> openTiles(true);
	std::map<BWAPI::TilePosition,int> gmap;
	std::map<BWAPI::TilePosition,BWAPI::TilePosition> parent;
	std::set<BWAPI::TilePosition> closedTiles;
	int AVOIDANCE_RANGE = 32;
	int PLAN_GRANULARITY = 1;

	openTiles.push(std::make_pair(start,0));
	gmap[start]=0;
	parent[start]=start;
	while(!openTiles.empty())
	{
		BWAPI::TilePosition p=openTiles.top().first;
		if (p==end)
		{
			std::vector<BWAPI::TilePosition> reverse_path;
			while(p!=parent[p])
			{
				reverse_path.push_back(p);
				p=parent[p];
			}
			reverse_path.push_back(start);
			std::vector<BWAPI::TilePosition> path;
			for(int i=reverse_path.size()-1;i>=0;i--)
				path.push_back(reverse_path[i]);
			return path;
		}
		int fvalue=openTiles.top().second;
		int gvalue=gmap[p];
		openTiles.pop();
		closedTiles.insert(p);
		int minx=max(p.x()-PLAN_GRANULARITY ,0);
		int maxx=min(p.x()+PLAN_GRANULARITY ,BWAPI::Broodwar->mapWidth()-PLAN_GRANULARITY );
		int miny=max(p.y()-PLAN_GRANULARITY ,0);
		int maxy=min(p.y()+PLAN_GRANULARITY ,BWAPI::Broodwar->mapHeight()-PLAN_GRANULARITY );
		for(int x=minx;x<=maxx;x+=(PLAN_GRANULARITY))
			for(int y=miny;y<=maxy;y+=(PLAN_GRANULARITY) )
			{
				if (!MapData::lowResWalkability[x][y]) continue;
				if (p.x() != x && p.y() != y && !MapData::buildability[p.x()][y] && !MapData::buildability[x][p.y()]) continue;
				BWAPI::TilePosition t(x,y);
				if (closedTiles.find(t)!=closedTiles.end()) continue;

				int g=gvalue+10;
				if (x!=p.x() && y!=p.y()) g+=4;
				int dx=abs(x-end.x());
				int dy=abs(y-end.y());

				int h=abs(dx-dy)*10+min(dx,dy)*14;

				// better way to do this: put it in a map
				for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
				{if(!(*i)->isAlive()) { continue; }
				UnitModel* cur = *i;
				if(cur->getType().isBuilding()) {
					continue;
				}
				Position pd = (Position)p;
				if(pd.getDistance(cur->getPosition()) <= AVOIDANCE_RANGE) {
					g = g+1000;
				}
				}
				int f=g;

				if ((gmap.find(t)==gmap.end() || g<gmap.find(t)->second))
				{
					gmap[t]=g;
					openTiles.set(t,f);
					parent[t]=p;
				}
			}
	}
	std::vector<BWAPI::TilePosition> nopath;
	return nopath;
}

int UnitManager::calculateTargettingPenalty(Unit* target, UnitModel* attacker) 
{
	std::set<UnitModel*> attackingUnits = globalTargettingMap[unitModelsMap[target]];
	UnitModel* targetModel = unitModelsMap[target];

	// can occurr in rare cases
	if(targetModel == NULL) {
		return 0;
	}
	int tarScore = 0;
	if(attackingUnits.size() >= 5) {
		tarScore -= 1000;
	}

	
	float damageToBeDone = 0;
	for(std::set<UnitModel*>::const_iterator i = attackingUnits.begin(); i != attackingUnits.end(); i++) {
		UnitModel* cur = *i;
		if(!cur->isAlive()) {
			continue;
		}
		float damageToAdd = cur->getType().groundWeapon().damageAmount();
		if(cur->getType() == UnitTypes::Protoss_Zealot) {
			damageToAdd *= 2.0;
			
			// encourage zealots to attack things other zealots are attacking
			if(attacker->getType() == UnitTypes::Protoss_Zealot) {
				if(cur->getType() == UnitTypes::Protoss_Zealot) {
					if(attacker->getUnit()->isInWeaponRange(target)) {
						tarScore += 2000;
					}
				}
			}
		}
		damageToBeDone += damageToAdd;
	}
	

	// will screw up if fighting protoss - fix that later
	if((targetModel->getHP()+targetModel->getShields())-((damageToBeDone)+attacker->getType().groundWeapon().damageAmount()) <= 0) {
		return -2000;
	} else {
		if(targetModel->getType() == UnitTypes::Protoss_Photon_Cannon || targetModel->getType() == UnitTypes::Terran_Bunker || targetModel->getType() == UnitTypes::Zerg_Creep_Colony || targetModel->getType() == UnitTypes::Zerg_Sunken_Colony || targetModel->getType() == UnitTypes::Zerg_Spore_Colony) {
			return 2000+tarScore;
		} else {
			return 2000+tarScore;
		}
	}

}

vector<UnitModel*> UnitManager::getFriendlyMilitaryUnitsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer()) {
		if(cur->getPosition().getDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getAllEnemyUnitsInRegion( BWTA::Region* r )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(!cur->isOwnedByPlayer()) {
		if(cur->getRegion() == r) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getAllEnemyUnitsNotInRegion( BWTA::Region* r )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(!cur->isOwnedByPlayer()) {
		if(cur->getRegion() != r) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getAllEnemyUnitsOfTypeInRegion( UnitType t, BWTA::Region* r )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(!cur->isOwnedByPlayer()) {
		if(cur->getRegion() == r && cur->getType() == t) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

void UnitManager::marshallIdleMilitaryUnits()
{
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	UnitType ct = cur->getType();
	if(!cur->isOwnedByPlayer() || !cur->getUnit()->isCompleted() || cur->isFollowingPath()) {
		continue;
	}
	if(cur->getArmyOwner() != NULL || (cur->getArmyOwner() != NULL && cur->getArmyOwner()->isAlive())) {
		continue;
	}
	
	if(ct == UnitTypes::Protoss_Dark_Templar || ct == UnitTypes::Protoss_Probe || ct == UnitTypes::Protoss_Observer || ct.isBuilding()) {
		continue;
	}

	if(cur->getUnit()->isMoving() || cur->getCurrentTaskType() != NO_TASK || cur->getUnit()->isAttacking() || cur->getUnit()->isStartingAttack()) {
		continue;
	}
	if(isRegionOwnedByMe(cur->getRegion())) {
		continue;
	}

	if(BWTA::getNearestChokepoint(getFriendlyMainBase()->getPosition())->getCenter().getDistance(cur->getPosition()) <= 128) {
		continue;
	}
	

	
		cur->getUnit()->move(this->getClosestFriendlyBaseModel(cur->getPosition())->getPosition());
	

	}

}

bool UnitManager::isRegionOwnedByMe( BWTA::Region* r )
{
	if(r == NULL) {
		return true;
	}
	for (std::vector<BaseModel*>::iterator it = friendlyBaseModels.begin(); it != friendlyBaseModels.end(); ++it)
	{
		BaseModel* cur = *it;
		if(cur->getSubject()->getRegion() == r) {
			return true;
		}
	}
	std::vector<BaseModel*> bases = overseer->getUnitManager()->getFriendlyBaseModels();

	for (vector<BaseModel*>::iterator i = bases.begin(); i != bases.end(); ++i) {
		BaseModel* base = (*i);
		BuildOrderTemplate* bot = base->getBuildOrder();
		if(bot != NULL) {
			std::deque<TaskBase*> tasks = bot->getPrimeOrder();

			for (deque<TaskBase*>::iterator it = tasks.begin(); it != tasks.end(); ++it)
			{
				TaskBase* t = *it;
				if(t->getBuildType() == UnitTypes::Protoss_Nexus) {
					if(BWTA::getRegion(t->getTargetPos()) == r) {
						return true;
					}
				}
			}
		}
	}

	std::deque<TaskBase*> staged = overseer->getArbitrator()->getActiveTasks();

		for (deque<TaskBase*>::iterator it = staged.begin(); it != staged.end(); ++it)
		{
			TaskBase* t = *it;
			if(t->getBuildType() == UnitTypes::Protoss_Nexus) {
				if(BWTA::getRegion(t->getTargetPos()) == r) {
					return true;
				}
			}
		}


	return false;

}

BaseModel* UnitManager::getFriendlyMainBase()
{
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isMainBase()) {
			return cur;
		}
	}
	return NULL;
}

BaseModel* UnitManager::getEnemyMainBase()
{
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isMainBase()) {
			return cur;
		}
	}
	// else lets just return whatever we know about
	if(!enemyBaseModels.empty()) {
		return *enemyBaseModels.begin();
	}
	return NULL;
}

vector<UnitModel*> UnitManager::getEnemyDetectorsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;

	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;

	// we assume bunkers are detectors, due to the presence of comsat stations, they might as well be.
	if(!cur->isOwnedByPlayer() && (cur->getType().isDetector())) {
		if(cur->getUnit()->isVisible()) {
			if(cur->getUnit()->isBeingConstructed()) {
				continue;
			}
			if(cur->getType().requiresPsi() && cur->getUnit()->isUnpowered()) {
				continue;
			}
		}
		if(cur->getPosition().getDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}
	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getEnemyBuildingsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;

	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;

	// we assume bunkers are detectors, due to the presence of comsat stations, they might as well be.
	if(!cur->isOwnedByPlayer()) {
		if(cur->getUnit()->isVisible()) {
			if(cur->getUnit()->isBeingConstructed()) {
				continue;
			}
		}
		if(cur->getPosition().getDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}
	}
	}
	return requestedCohort;
}

vector<UnitModel*> UnitManager::getEnemyBuildingsOfTypeInRange( Position p, int range, UnitType t )
{
	std::vector<UnitModel*> requestedCohort;

	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType() != t) {
		continue;
	}
	if(!cur->isOwnedByPlayer()) {
		if(cur->getUnit()->isVisible()) {
			if(cur->getUnit()->isBeingConstructed()) {
				continue;
			}
		}

		if(cur->getPosition().getDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}
	}
	}
	return requestedCohort;
}

int UnitManager::countFriendlyUnits( UnitType t )
{
	std::vector<UnitModel*> requestedCohort;
	int c = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer()) {
		if(cur->getType() == t) {
			c++;
		}
	}
	}
	return c;
}

void UnitManager::manageExpansions()
{
	if(Broodwar->getFrameCount()%128 == 0 && Broodwar->getFrameCount() > 256) {
		if(overseer->getArbitrator()->isStagedToBeBuilt(UnitTypes::Protoss_Nexus)) {
			return;
		}
		if(countProductiveBases() >= 3) {
			return;
		}
		if(GLOBAL_EXPANSION_TIMER > 0) {
			return;
		}


		for(std::vector<BaseModel*>::const_iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); i++) {
			BaseModel* cur = *i;
			if(cur->hasSpawnedExpansion() || !cur->isAlive()) {
				continue;
			}
			std::set<Unit*> mins = cur->getBaseMinerals();
			if( cur->getCurMineralsLeft() <= cur->getStartMinerals()*0.15) {
				////Broodwar->sendText("%f is less than %d", cur->getStartMinerals()*0.15, cur->getCurMineralsLeft());
				BuildOrderTemplate* ebo = new BuildOrderTemplate(overseer);
				ebo->setTargetMineralWorkers(21);
				ebo->setTargetGasWorkers(3);

				ebo->addToOpeningSequence(UnitTypes::Protoss_Pylon);
				ebo->addToOpeningSequence(UnitTypes::Protoss_Photon_Cannon);
				ebo->addToOpeningSequence(UnitTypes::Protoss_Photon_Cannon);	
				ebo->addToOpeningSequence(UnitTypes::Protoss_Photon_Cannon);
				ebo->addToOpeningSequence(UnitTypes::Protoss_Assimilator);
				ebo->setTargetParent(cur);
				if(cur->getBuildOrder() != NULL) {
					cur->getBuildOrder()->addToOpeningSequenceUrgent(UnitTypes::Protoss_Nexus, ebo);
					cur->setSpawned(true);
					GLOBAL_EXPANSION_TIMER = GLOBAL_EXPANSION_THRESH;
					if(cur->isMainBase()) {
						////Broodwar->sendText("expanding from main base!");
					}
					return;
				} else {
					////Broodwar->sendText("null build order?");
				}
			}
		}
	}
}

vector<UnitModel*> UnitManager::getAllFriendlyUnitsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer()) {
		if(cur->getPosition().getDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

void UnitManager::declareTargetToMap(UnitModel* attacker, Unit* target)
{
	for(std::map<UnitModel*,std::set<UnitModel*>>::iterator i = globalTargettingMap.begin(); i != globalTargettingMap.end(); i++) {
		UnitModel* target = (*i).first;
		std::set<UnitModel*> attackers = (*i).second;

		std::set<UnitModel*>::iterator atr = attackers.find(attacker);
		std::set<UnitModel*> replacement;
		for(std::set<UnitModel*>::iterator it = attackers.begin(); it != attackers.end(); it++) {
			UnitModel* cur = *it;
			if(cur == attacker) {

			} else {
				replacement.insert(cur);
			}
		}

		globalTargettingMap[target].clear();
		globalTargettingMap[target] = replacement;


	}
	
	globalTargettingMap[unitModelsMap[target]].insert(attacker);

}

BWAPI::Position UnitManager::getBelievedEnemyMainBasePosition()
{
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
			return cur->getPosition();
		}
	}

	// else, if we're on a two-player map, we already know where they'll be
	if(BWTA::getStartLocations().size() == 2) {
		for (set<TilePosition>::iterator i = Broodwar->getStartLocations().begin(); i != Broodwar->getStartLocations().end(); ++i)
		{
			if((*i) == Broodwar->self()->getStartLocation()) {

			} else {
				return (Position)(*i);
			}
		}
	}
	return Positions::None;
}


BWTA::Region* UnitManager::getBelievedEnemyMainBaseRegion()
{
	int bval = 500000000;
	std::set<BWTA::Region*> regions = BWTA::getRegions();
	BWTA::Region* bestBase = NULL;
	for (std::set<BWTA::Region*>::iterator i = regions.begin(); i != regions.end(); ++i)
	{
		BWTA::Region* cur = *i;
		if(cur->getBaseLocations().empty()) {
			continue;
		}
		BaseModel* base = getBaseModelInRegion(cur);
		bool clearToAttack = false;
		if(base != NULL) {
			if(!base->isFriendlyBase() && base->isAlive()) {
					clearToAttack = true;
			}
		} else {
			clearToAttack = true;
		}

		if(clearToAttack) {
			int cval = valueRegion(cur);
			if(cval != 0) {
				if(cval < bval) {
					bval = cval;
					bestBase = cur;
				}
			}
		}


	}

	if(bestBase != NULL) {
		return bestBase;
	}

	// else, if we're on a two-player map, we already know where they'll be
	if(BWTA::getStartLocations().size() == 2) {
		for (set<TilePosition>::iterator i = Broodwar->getStartLocations().begin(); i != Broodwar->getStartLocations().end(); ++i)
		{
			if((*i) == Broodwar->self()->getStartLocation()) {

			} else {
				// but wait, we don't want to say the enemy base is here if we KNOW we've seen it already
				// AND it's been destroyed
				BaseModel* bm = overseer->getUnitManager()->getEnemyBaseModelInRegion(BWTA::getRegion((*i)));
				if(bm != NULL) {
					if(!bm->isAlive()) {
						continue;
					}
				} else {
					return BWTA::getRegion((*i));
				}
			}
		}
	}

	if(suspectLoc != Positions::None) {
		return BWTA::getRegion(suspectLoc);
	}

	return NULL;
}

int UnitManager::countFriendlyBuildingsInRange( UnitType t, Position p, int range )
{

	int c = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer() && cur->getType().isBuilding()) {

		if(cur->getType() == t) {
			if(cur->getPosition().getDistance(p) <= range) {
				c++;
			}
		}

	}
	}
	return c;
}

int UnitManager::valueRegion( BWTA::Region* r )
{
	std::vector<UnitModel*> units;
	int val = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType().isBuilding() && !cur->isOwnedByPlayer()) {
		if(cur->getRegion() == r) {
			val += cur->getType().mineralPrice();
		}
	}
	}
	return val;
}

vector<UnitModel*> UnitManager::getAllEnemyBuildingsInRegion( BWTA::Region* r )
{

	std::vector<UnitModel*> units;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getType().isBuilding() && !cur->isOwnedByPlayer()) {
		if(cur->getRegion() == r) {
			units.push_back(cur);
		}
	}
	}
	return units;
}

void UnitManager::flushMemory()
{
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{	
		UnitModel* cur = *i;
		delete (cur);
	}
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{	
		BaseModel* cur = *i;
		delete (cur);
	}
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{	
		BaseModel* cur = *i;
		delete (cur);
	}
}

BWTA::Region* UnitManager::getBelievedEnemyMainBaseRegionNot( BWTA::Region* r )
{
	int bval = 0;
	BaseModel* bestBase = NULL;
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->getBaseRegion() == r) {
			continue;
		}
		if(cur->isAlive()) {
			int cval = cur->mineralValue();
			if(cur->mineralValue() > bval && cval != 0) {
				bval = cval;
				bestBase = cur;
			}
		}
	}
	if(bval != 0 && bestBase != NULL) {
		return bestBase->getBaseRegion();
	}
	std::set<BWTA::Region*> regions = BWTA::getRegions();
	int bestRegionValueSoFar = 0;
	BWTA::Region* bestRegionSoFar = NULL;
	for (set<BWTA::Region*>::iterator it = regions.begin(); it != regions.end(); ++it)
	{
		BWTA::Region* curR = *it;
		if(curR == r){
			continue;
		}
		int curval = valueRegion(curR);
		if(curval > bestRegionValueSoFar) {
			bestRegionValueSoFar = curval;
			bestRegionSoFar = curR;
		}
	}
	if(bestRegionSoFar != NULL) {
		return bestRegionSoFar;
	}

	// else, if we're on a two-player map, we already know where they'll be
	if(BWTA::getStartLocations().size() == 2) {
		for (set<TilePosition>::iterator itt = Broodwar->getStartLocations().begin(); itt != Broodwar->getStartLocations().end(); ++itt)
		{
			if((*itt) == Broodwar->self()->getStartLocation()) {

			} else {
				return BWTA::getRegion((*itt));
			}
		}
	}

	// missign logic: we're on a tow person map, we destroy the enemy main,
	// but we have no idea where the other bases are
	// this just points to the enmy main

	return NULL;
}

vector<UnitModel*> UnitManager::getFriendlyUnitsOfTypeInRange( Position p, int range, UnitType t )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer() && cur->getType() == t) {
		if(cur->getPosition().getDistance(p) <= range) {
			requestedCohort.push_back(cur);
		}

	}
	}
	return requestedCohort;
}

BaseModel* UnitManager::getBaseModelInRegion( BWTA::Region* r )
{

	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
		if(cur->getBaseRegion() == r) {
			return cur;
		}
		}
	}

	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
		if(cur->getBaseRegion() == r) {
			return cur;
		}
		}
	}


	return NULL;

}

vector<UnitModel*> UnitManager::getAllUnitsInRange( Position p, int range )
{
	std::vector<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->getPosition().getDistance(p) <= range) {
		requestedCohort.push_back(cur);
	}
	}
	return requestedCohort;
}

int UnitManager::countProductiveBases()
{

	int c = 0;
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	BaseModel* cur = *i;
	if(cur->isAlive() && cur->getCurMineralsLeft() >= cur->getStartMinerals()*0.2) {
		c++;
	}
	}
	return c;
}

void UnitManager::setMaximumBuildConstraint( UnitType u, int num )
{
	maximumBuildMap[u] = num;
}

int UnitManager::getMaximumBuildConstraint( UnitType u )
{
	if(maximumBuildMap[u] == NULL) {
		return 0;
	} else {
		return maximumBuildMap[u];
	}
}

set<Unit*> UnitManager::getEnemyMilitaryUnitsASUNITSInRange( Position p, int range )
{
	std::set<Unit*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		UnitModel* cur = *i;
		float x = (float)p.x()-(float)cur->getPosition().x();
		float y = (float)p.y()-(float)cur->getPosition().y();
		if(abs(sqrt(x)-sqrt(y)) <= range*range) {
				requestedCohort.insert(cur->getUnit());
		}
	}
	return requestedCohort;
}

set<UnitModel*> UnitManager::getAllFriendlyBuildingsOfType( UnitType t )
{
	std::set<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		UnitModel* cur = *i;
		if(cur->getType() == t) {
			requestedCohort.insert(cur);
		}
	}
	return requestedCohort;
}

int UnitManager::countNumUnderConstructionAtBase( UnitType t, BaseModel* b )
{

	int c = 0;
	std::set<UnitModel*> buildings = b->getBaseBuildings();
	for (set<UnitModel*>::iterator i = buildings.begin(); i != buildings.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer()) {
		if(cur->getType() == t) {
			if(cur->getUnit()->isBeingConstructed()) {
				c++;
			}
		}
	}
	}
	return c;
}

int UnitManager::getNumFriendlyUnitsAttacking( UnitModel* t )
{
	std::set<UnitModel*> attackingUnits = globalTargettingMap[t];

	int count = 0;
	for(std::set<UnitModel*>::const_iterator i = attackingUnits.begin(); i != attackingUnits.end(); i++) {
		UnitModel* cur = *i;
		if(cur->isAlive()) {
					count++;	
		}
	}
	return count;
}

int UnitManager::countFriendlyUnitsOfType( UnitType t )
{

	int c = 0;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{if(!(*i)->isAlive()) { continue; }
	UnitModel* cur = *i;
	if(cur->isOwnedByPlayer()) {
		if(cur->getType() == t) {
				c++;
		}
	}
	}
	return c;
}

BaseModel* UnitManager::getClosestFriendlyBaseModel( Position p )
{
	// note: this method is a bit of a hack. there are more robust ways of doing this later.
	BaseModel* tar = NULL;
	int bestDistance = 1000000;
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
			int dist = cur->getPosition().getDistance(p);
			if(dist < bestDistance) {
				bestDistance = dist;
				tar = cur;
			}
		}
	}

	// if this is null, we've probably lost the game...
	if(tar == NULL && Broodwar->getFrameCount() > 256) {
		//Broodwar->sendText("A minor setback!");
		Broodwar->leaveGame();
	}

	return tar;

}

bool UnitManager::hasBuildablePath( BWAPI::TilePosition start, BWAPI::TilePosition finish )
{
	if(start == finish){
		return true;
	}
	if(!start.isValid()) {
		start = start.makeValid();
	}
	if(!finish.isValid()) {
		finish = finish.makeValid();
	}


	TilePosition xCheck;
	
		for(int i = 0; i < abs(finish.x()-start.x()); i++) {
			if(start.x() < finish.x()) {
				xCheck = TilePosition(start.x()+i, start.y());
			}
			if(start.x() > finish.x()) {
				xCheck = TilePosition(start.x()-i, start.y());
			}
			if(!xCheck.isValid()) {
				xCheck = xCheck.makeValid();
			}
			if(MapData::buildability[xCheck.x(), xCheck.y()]  || BWTA::getNearestChokepoint(xCheck)->getCenter().getDistance((Position)xCheck) < 128) {

			} else {
				return false;
			}
		}

		TilePosition yCheck;
		for(int i = 0; i < abs(finish.y()-start.y()); i++) {
			if(start.y() < finish.y()) {
				yCheck = TilePosition(start.y(), start.y()+i);
			}
			if(start.y() > finish.y()) {
				yCheck = TilePosition(start.x(), start.y()-i);
			}
			if(!yCheck.isValid()) {
				yCheck = yCheck.makeValid();
			}
			if(MapData::buildability[xCheck.x(), xCheck.y()] || BWTA::getNearestChokepoint(yCheck)->getCenter().getDistance((Position)yCheck) < 128) {

			} else {
				return false;
			}
		}
	
		return true;
}

UnitModel* UnitManager::findWorkerGlobal()
{
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
			if(cur->getSubject() != NULL) {
				if(cur->getSubject()->getUnit()->isBeingConstructed() || cur->getWorkers().size() <= 3) {
					continue;
				}
			}
			UnitModel* worker = cur->findAvailableWorker();
			if(worker != NULL) {
				return worker;
			}
		}
	}
	for (vector<BaseModel*>::iterator it = friendlyBaseModels.begin(); it != friendlyBaseModels.end(); ++it)
	{
		BaseModel* cur = *it;
		if(cur->isAlive()) {
			if(cur->getWorkers().empty()) {
				continue;
			}
			if(cur->getSubject() != NULL) {
				if(cur->getSubject()->getUnit()->isBeingConstructed() || cur->getWorkers().size() <= 3) {
					continue;
				}
			}
			for (vector<UnitModel*>::iterator itt = cur->getWorkers().begin(); itt != cur->getWorkers().end(); ++itt)
			{
				if((*itt)->isAlive() && !(*itt)->getCurrentTaskType() == CONSTRUCTION) {
					int prb = rand()%100;
					if(prb >= 50) {
						return (*itt);
					}
				}
			}
		}
	}
	return NULL;
}

BaseModel* UnitManager::getClosestEnemyBaseModel( Position p )
{
	// note: this method is a bit of a hack. there are more robust ways of doing this later.
	BaseModel* tar = NULL;
	int bestDistance = 1000000;
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
			int dist = cur->getPosition().getDistance(p);
			if(dist < bestDistance) {
				bestDistance = dist;
				tar = cur;
			}
		}
	}



	return tar;
}

std::vector<BWAPI::TilePosition> UnitManager::AstarSearchPathNoObstacles( BWAPI::TilePosition start, BWAPI::TilePosition end)
{
	return AstarSearchPathNoObstacles(start, end, 2);
}

std::vector<BWAPI::TilePosition> UnitManager::AstarSearchPathNoObstacles( BWAPI::TilePosition start, BWAPI::TilePosition end, int grain )
{
	BWTA::Heap<BWAPI::TilePosition,int> openTiles(true);
	std::map<BWAPI::TilePosition,int> gmap;
	std::map<BWAPI::TilePosition,BWAPI::TilePosition> parent;
	std::set<BWAPI::TilePosition> closedTiles;

	std::set<Unit*> mins = Broodwar->getStaticMinerals();
	std::set<Unit*> geysers = Broodwar->getStaticGeysers();
	std::set<Unit*> neutrals = Broodwar->getStaticNeutralUnits();
	std::set<Unit*> nns = Broodwar->getNeutralUnits();
	mins.insert(geysers.begin(), geysers.end());
	mins.insert(neutrals.begin(), neutrals.end());

	openTiles.push(std::make_pair(start,0));
	gmap[start]=0;
	parent[start]=start;
	int GRAIN = grain;
	int TEMP_GRAIN = 5;
	int c = 0;
	while(!openTiles.empty())
	{
		BWAPI::TilePosition p=openTiles.top().first;
		if (p.getDistance(end) <= GRAIN*2)
		{
			std::vector<BWAPI::TilePosition> reverse_path;
			while(p!=parent[p])
			{
				reverse_path.push_back(p);
				p=parent[p];
			}
			reverse_path.push_back(start);
			std::vector<BWAPI::TilePosition> path;
			for(int i=reverse_path.size()-1;i>=0;i--)
				path.push_back(reverse_path[i]);
			return path;
		}
		int fvalue=openTiles.top().second;
		int gvalue=gmap[p];
		openTiles.pop();
		closedTiles.insert(p);

		int minx=max(p.x()-GRAIN,0);
		int maxx=min(p.x()+GRAIN,BWAPI::Broodwar->mapWidth()-GRAIN);
		int miny=max(p.y()-GRAIN,0);
		int maxy=min(p.y()+GRAIN,BWAPI::Broodwar->mapHeight()-GRAIN);
		for(int x=minx;x<=maxx;x+=GRAIN)
			for(int y=miny;y<=maxy;y+=GRAIN)
			{
				if (!MapData::lowResWalkability[x][y]) continue;
				if (p.x() != x && p.y() != y && !MapData::walkability[p.x()][y] && !MapData::walkability[x][p.y()]) continue;



				BWAPI::TilePosition t(x,y);
				if(!t.isValid()) {
					t = t.makeValid();
				}
				if(!t.hasPath(start)) {
					continue;
				}
				if (closedTiles.find(t)!=closedTiles.end()) continue;


				TilePosition pos = TilePosition(p.x(), p.y());
				bool cont = false;

			
				for(std::set<Unit*>::const_iterator i = mins.begin(); i != mins.end(); ++i) {
					Unit* curMin = *i;
					Position initPos = curMin->getInitialPosition();
					if(initPos.getApproxDistance((Position)pos) < 128) {
						//if(BWTA::getNearestBaseLocation(initPos)->getPosition().getDistance(initPos) > 100) {
						
						cont = true;
						break;
					}
					}
				
				if(cont) {
					continue;
				}


				int g=1+0.9*(gvalue-1);
				if (x!=p.x() && y!=p.y()) g+=4;
				int dx=abs(x-end.x());
				int dy=abs(y-end.y());

				int h=abs(dx-dy)*10+min(dx,dy)*14;
				//int d = 10;
				//int h = d*max(dx,dy);

				int f=g+h;
				if (gmap.find(t)==gmap.end() || g<gmap.find(t)->second)
				{
					gmap[t]=g;
					openTiles.set(t,f);
					parent[t]=p;
				}
			}
	}
	std::vector<BWAPI::TilePosition> nopath;
	return nopath;
}

BaseModel* UnitManager::getEnemyBaseModelInRegion( BWTA::Region* r )
{
	for (vector<BaseModel*>::iterator i = enemyBaseModels.begin(); i != enemyBaseModels.end(); ++i)
	{
		BaseModel* cur = *i;
		if(cur->isAlive()) {
		if(cur->getBaseRegion() == r) {
			return cur;
		}
		}
	}


	return NULL;
}

int UnitManager::getGlobalExpansionTimer()
{
	return GLOBAL_EXPANSION_TIMER;
}

int UnitManager::getGlobalExpansionThresh()
{
	return GLOBAL_EXPANSION_THRESH;
}

void UnitManager::resetGlobalExpansionTimer()
{
	GLOBAL_EXPANSION_TIMER = 0;
}

BWAPI::Position UnitManager::getClosestNeutralOrFriendlyBasePos( Position p )
{

	std::set<BWTA::BaseLocation*> bases = BWTA::getBaseLocations();
	Position best = Positions::None;
	for (set<BWTA::BaseLocation*>::iterator i = bases.begin(); i != bases.end(); ++i)
	{
		BWTA::BaseLocation* cur = *i;
		if(getBaseModelInRegion(cur->getRegion()) == NULL || getBaseModelInRegion(cur->getRegion())->isFriendlyBase()) {
			if(best == Positions::None) {
				best = cur->getPosition();
			} else {
				if(cur->getPosition().getDistance(p) < best.getDistance(p) ) {
					best = cur->getPosition();
				}
			}
		}
	}
	return best;
}



BWAPI::Position UnitManager::getClosestNeutralOrFriendlyBasePosNot( Position p, BWTA::Region* r )
{

	std::set<BWTA::BaseLocation*> bases = BWTA::getBaseLocations();
	Position best = Positions::None;
	for (set<BWTA::BaseLocation*>::iterator i = bases.begin(); i != bases.end(); ++i)
	{
		BWTA::BaseLocation* cur = *i;
		if(cur->getRegion() == r) {
			continue;
		}
		if(getBaseModelInRegion(cur->getRegion()) == NULL || getBaseModelInRegion(cur->getRegion())->isFriendlyBase()) {
			if(best == Positions::None) {
				best = cur->getPosition();
			} else {
				if(cur->getPosition().getDistance(p) < best.getDistance(p) ) {
					best = cur->getPosition();
				}
			}
		}
	}
	return best;
}

std::vector<Army*> UnitManager::getActiveArmies()
{
	return activeArmies;
}

Overseer* UnitManager::getOverseer()
{
	return overseer;
}

void UnitManager::setPreferredDTStrat( int f )
{
	preferredDTStrat = f;
}

int UnitManager::getPreferredDTStrat()
{
	return preferredDTStrat;
}

bool UnitManager::hasBeenRebuilt(Unit* u)
{
	if(rebuildList.find(u) == rebuildList.end()) {
		return false;
	} else {
		return true;
	}
}

void UnitManager::registerRebuilt( Unit* u )
{
	rebuildList.insert(u);
}

bool UnitManager::shouldContinue()
{
	for (vector<BaseModel*>::iterator i = friendlyBaseModels.begin(); i != friendlyBaseModels.end(); ++i) {
		BaseModel* base = (*i);
		if(base->isAlive()) {
			return true;
		}
	}
	return false;
}

set<UnitModel*> UnitManager::getAllFriendlyBuildingsOfTypeInRange( UnitType t, Position p, int range )
{
	std::set<UnitModel*> requestedCohort;
	for (vector<UnitModel*>::iterator i = unitModels.begin(); i != unitModels.end(); ++i)
	{
		if(!(*i)->isAlive()) { continue; }
		UnitModel* cur = *i;
		if(cur->getType() == t) {
			if(cur->getPosition().getDistance(p) <= range) {
				requestedCohort.insert(cur);
			}
		}
	}
	return requestedCohort;
}

void UnitManager::registerSuspectedEnemyBaseLoc( Position p )
{
	suspectLoc = p;
}

PathRepository* UnitManager::getPathRepo()
{
	return pathRepo;
}

BWAPI::Position UnitManager::getSuspectedEnemyBaseLoc()
{
	return suspectLoc;
}

bool UnitManager::isBlackListed( BWTA::Region* r )
{
	return !(blacklist.count(r) == 0);
}

void UnitManager::setUpRegionBlackList()
{
	// ignore the blocked off bits on fortress
	std::vector<Position> toBlackList;
	if(Broodwar->mapHash() == "83320e505f35c65324e93510ce2eafbaa71c9aa1") {
	toBlackList.push_back(Position(3720,460));
	toBlackList.push_back(Position(360,3631));
	toBlackList.push_back(Position(3718,3693));
	toBlackList.push_back(Position(384,397));
	}

	for(std::vector<Position>::const_iterator i = toBlackList.begin(); i != toBlackList.end(); i++) {
		Position cur = *i;
		blacklist.insert(BWTA::getRegion(cur));
	}




}
