#include "BaseModel.h"
#include "BuildOrderTemplate.h"
#include "Overseer.h"
#include "BaseModelConsistencyMonitor.h"
#include "ExpandTask.h"
//#include "Windows.h"
BaseModel::BaseModel(UnitModel* centre, Overseer* ov) {
	subject = centre;
	loc = BWTA::getNearestBaseLocation(subject->getPosition());
	baseMinerals = loc->getMinerals();
	baseGeysers = loc->getGeysers();
	overseer = ov;
	mainBaseSpawnCounter = 0;
	mainBaseSpawnTimer = 0;
	respawned = false;
	baseTemplate = NULL;
	workersGatheringGas = 4;
	workerClaimTimer = 0;
	expandSubject = NULL;
	workersMiningMinerals = 4;	
	main = false;
		alive = true;
	pos = centre->getPosition();
	curMinerals = -1;
	startMinerals = -1;
	startGas = -1;
	curGas = 0;
	parent = NULL;
	spawnedExpansion = false;
	friendly = centre->isOwnedByPlayer();
	baseRegion = centre->getRegion();
	buildFrame = Broodwar->getFrameCount();
	managingWorkers = true;
	// BUG: some base locations do not report all available gas at their locations
	std::set<Unit*> mins = Broodwar->getMinerals();
	for (set<Unit*>::iterator i = mins.begin(); i != mins.end(); ++i)
	{
		Unit* cur = *i;
		if(BWTA::getRegion(cur->getPosition()) != baseRegion) {
			continue;
		}
		if(cur->getPosition().getDistance(pos) < 464) {
			baseMinerals.insert(cur);
		}
	}
	std::set<Unit*> gas = Broodwar->getGeysers();
	for (set<Unit*>::iterator i = gas.begin(); i != gas.end(); ++i)
	{
		Unit* cur = *i;
		if(BWTA::getRegion(cur->getPosition()) != baseRegion) {
			continue;
		}
		if(cur->getPosition().getDistance(pos) < 464) {
			baseGeysers.insert(cur);
		}
	}

}

BaseModel::BaseModel( UnitModel* centre, Overseer* ov, BuildOrderTemplate* bo )
{
	subject = centre;
	overseer = ov;
	baseTemplate = bo;
	loc = BWTA::getNearestBaseLocation(subject->getPosition());
	baseMinerals = loc->getMinerals();
	baseGeysers = loc->getGeysers();
	workersGatheringGas = 4;
	workersMiningMinerals = 4;
		expandSubject = NULL;
	main = false;
	spawnedExpansion = false;
	pos = centre->getPosition();
	curMinerals = -1;
	startMinerals = -1;
	startGas = -1;
	curGas = 0;
	friendly = centre->isOwnedByPlayer();
	baseRegion = centre->getRegion();
	buildFrame = Broodwar->getFrameCount();
	parent = NULL;
	alive = true;
	respawned = false;
	mainBaseSpawnCounter = 0;
	mainBaseSpawnTimer = 0;
}

//************************************
// Method:    getSubject
// FullName:  getSubject
// Access:    public 
// Returns:   BaseModel::UnitModel*
// Comments:  none
//************************************
UnitModel* BaseModel::getSubject() {
	return subject;
}

bool minSort (BWAPI::Unit* i, BWAPI::Unit* j) { 
	Position refPos = BWTA::getNearestBaseLocation(i->getPosition())->getPosition();
	float distA = BWTA::getGroundDistance((TilePosition)i->getPosition(), (TilePosition)refPos);
	float distB = BWTA::getGroundDistance((TilePosition)j->getPosition(), (TilePosition)refPos);
	return distA > distB;
}

//************************************
// Method:    updateBaseModel
// FullName:  BaseModel::updateBaseModel
// Access:    public 
// Returns:   void
// Comments:  Maintains the base model data structures with up-to-date information.
//************************************
void BaseModel::updateBaseModel(vector<UnitModel*> units) {
	
	// for a start lets update our base template to make sure we're current
	if(baseTemplate != NULL) {
		baseTemplate->update();
	}
	if(expandSubject != NULL) {
		if(expandSubject->isFinished()) {
			expandSubject = NULL;
			mainBaseSpawnTimer = 8120;
		}
	}
	if(workerClaimTimer > 0){
		workerClaimTimer--;
	}
	if(Broodwar->getFrameCount() > 256){
		alive = setAlive(); 
		if(mainBaseSpawnTimer > 0) {
			mainBaseSpawnTimer--;
		}

		if(!respawned) {
			if(curMinerals <= startMinerals*0.2) {
			respawned = true;
			if(parent != NULL && parent != this) {
				BaseModel* gprnt = parent;
				if(parent->isAlive()) {
					parent->setSpawned(false);
				} else {
					BaseModel* grandParent = parent->getParent();
					if(grandParent != NULL) {
						if(grandParent->isAlive()) {
							if(grandParent->hasSpawnedExpansion()) {
								grandParent->setSpawned(false);
							}
						} else {
							BaseModel* greatGrandParent = parent->getParent()->getParent();
							if(greatGrandParent != NULL) {
								if(greatGrandParent->isAlive()) {
									if(greatGrandParent->hasSpawnedExpansion()) {
										greatGrandParent->setSpawned(false);
									}
								}
							}
						}
					}
				}
			}
		}
		}


	}
if(Broodwar->getFrameCount()%24 == 0) {
	// forget the workers we might have seen last time
	activeWorkers.clear();
	defenders.clear();
	
	monitorForPower();
	bool lookForNewSubject = false;
	if(subject->getType().isResourceDepot()) {

	} else {
		lookForNewSubject = true;
	}

	// primary idea: go through find our units in this region
	// and assign them to this base's data structure
	// in the future we can extend this to evaluate how well-defended a base is by examining
	// the kinds of fixed-emplacements like bunkers and turrets that might be present in a region
	workersMiningMinerals = 0;
	workersGatheringGas = 0;
	for (vector<UnitModel*>::iterator i = units.begin(); i != units.end(); ++i)
	{
		UnitModel* unit = *i;
		
		if((unit->isOwnedByPlayer() == isFriendlyBase()) && unit->isAlive()) {
			// and we only care about stuff that is near this base region
			if(unit->getRegion() == baseRegion) {
					unit->setBaseOwner(this);
				// remember a worker
					if(lookForNewSubject) {
					if(unit->getType().isResourceContainer()) {
						subject = unit;	
					}
					}
				if(unit->getType().isWorker() && unit->getCurrentTaskType() == NO_TASK) {
					activeWorkers.push_back(unit);	
					if(unit->getBaseOwner() != this || unit->getBaseOwner() == NULL) {
						unit->setBaseOwner(this);
					}
					if(unit->getUnit()->isCarryingMinerals() || unit->getUnit()->isGatheringMinerals()) {
						workersMiningMinerals++;
					}
					if(unit->getUnit()->isGatheringGas() || unit->getUnit()->isCarryingGas() || unit->getUnit()->getOrder() == BWAPI::Orders::MoveToGas || unit->getUnit()->getOrder() == BWAPI::Orders::WaitForGas|| unit->getUnit()->getOrder() == BWAPI::Orders::ReturnGas|| unit->getUnit()->getOrder() == BWAPI::Orders::HarvestGas) {
						workersGatheringGas++;
					}

				} else {
				// or a building
				if(unit->getType().isBuilding()) {
					baseContents.insert(unit);
				} else {
					// should be an defender
					if(unit->isOwnedByPlayer()) {
					defenders.push_back(unit);
					}
				}

				}
			}
		}
	}
	manageLocalDefenders();
	
	////////Broodwar->sendText("base contents: %d", baseContents.size());

	/*
	update minerals
	*/
	if(subject->isOwnedByPlayer()) {


	// bit of a hack, but oh well
	//curMinerals = 0;
	int minTemp = 0;
	bool minVis = false;
	for (set<BWAPI::Unit*>::iterator i = baseMinerals.begin(); i != baseMinerals.end(); ++i)
	{
		BWAPI::Unit* currentMin = *i;
		if(!currentMin->isVisible()) {
			continue;
		} else {
			minVis = true;
		}
			minTemp = minTemp + currentMin->getResources();
	}
	if(minVis) {
		curMinerals = minTemp;
	}
	

	if(startMinerals == -1) {
		startMinerals = curMinerals;
	}
	
	/*
	update gas
	*/
	
	//baseGeysers.clear();
	std::set<Unit*> gas = getBaseGeysers();
	// bit of a hack, but oh well
	//curGas = 0;

	for (set<BWAPI::Unit*>::iterator i = gas.begin(); i != gas.end(); ++i)
	{
		BWAPI::Unit* currentGas = *i;
		if(!currentGas->isVisible()) {
			continue;
		}
		curGas = curGas + currentGas->getResources();
	}

	if(startGas == -1) {
		startGas = curGas;
	}

	if(!subject->getUnit()->isCompleted()) {
		return;
	}
	if(Broodwar->getFrameCount()%24 == 0) {
		manageWorkerPopulation();
	}

		//pd->monitor();
	}
}

}

//************************************
// Method:    drawBaseModel
// FullName:  BaseModel::drawBaseModel
// Access:    public 
// Returns:   void
// Comments:  none
//************************************
void BaseModel::drawBaseModel()
{
	
	// draw the location of the base centre

	if(isAlive()) {
		//Broodwar->drawEllipseMap(subject->getPosition().x(), getSubject()->getPosition().y(), 20, 20, BWAPI::Colors::Green, true);
	} else {
		//Broodwar->drawEllipseMap(subject->getPosition().x(), getSubject()->getPosition().y(), 20, 20, BWAPI::Colors::Red, true);
	}
	// draw lines to all of the workers owned by this base
	if(activeWorkers.empty()) {
		//return;
	}
	for (vector<UnitModel*>::iterator i = activeWorkers.begin(); i != activeWorkers.end(); ++i)
	{
		//Broodwar->drawLineMap(getSubject()->getPosition().x(), getSubject()->getPosition().y(), (*i)->getPosition().x(), (*i)->getPosition().y(), BWAPI::Colors::White);
	}

	if(baseContents.empty()) {
		return;
	}
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		if((*i)->isAlive()) {
		//Broodwar->drawLineMap(getSubject()->getPosition().x(), getSubject()->getPosition().y(), (*i)->getPosition().x(), (*i)->getPosition().y(), BWAPI::Colors::Yellow);
		}
	}

	if(baseTemplate != NULL) {
	//Broodwar->drawTextMap(pos.x()-16, pos.y()-96, "mins: %d", getCurMineralsLeft());
	//Broodwar->drawTextMap(pos.x()-16, pos.y()-80, "min count: %d, miners: %d, target: %d", baseMinerals.size(), workersMiningMinerals, baseTemplate->getTargetMineralWorkers());
	}
	}

//************************************
// Method:    findAvailableWorker
// FullName:  BaseModel::findAvailableWorker
// Access:    public 
// Returns:   UnitModel*
// Comments:  Looks at the workers at this base, and attempts to return one based on some criteria - ie. not busy, not returning minerals etc.
//************************************
UnitModel* BaseModel::findAvailableWorker()
{
	// possible extension: pass in a point where we'd like to build, and find the worker closest to this point
	// so we can get building faster. would this even make a huge difference though?

	// also: as it stands, do we always want the first worker we find?
	// is there a better way?
	UnitModel* model = NULL;
	for (vector<UnitModel*>::iterator i = activeWorkers.begin(); i != activeWorkers.end(); ++i)
	{
		model = *i;

		BWAPI::Unit* unit = model->getUnit(); // best to do this, even though it's not ideal
		if(model->isAlive()) {
		// so now we need to know if the unit is busy with other stuff
		if(model->getCurrentTaskType() == CONSTRUCTION) continue;
		if(model->getCurrentTaskType() == SCOUTING) continue;
				if(model->getCurrentTaskType() == EXPAND) continue;
		if(unit->isConstructing()) continue;
		if(unit->isCarryingMinerals()) continue;
		if(unit->isCarryingGas()) continue;
		if(unit->isRepairing()) continue;
		if(unit->isGatheringGas()) continue;
		if(model->isFollowingPath()) continue;

		return model;
		}
	}


	if(model == NULL) {
		for (vector<UnitModel*>::iterator i = activeWorkers.begin(); i != activeWorkers.end(); ++i)
		{
			if((*i)->getCurrentTaskType() != NO_TASK) {
				continue;
			}
			if((*i)->getUnit()->isGatheringMinerals() || (*i)->getUnit()->isGatheringGas()) {
			if(rand()%100 >= 50) {
				model = *i;
				break;
			}
		}
		}
	}
	return model;
}

//************************************
// Method:    getBaseBuildings
// FullName:  BaseModel::getBaseBuildings
// Access:    public 
// Returns:   vector<UnitModel*>
// Comments:  none
//************************************
set<UnitModel*> BaseModel::getBaseBuildings()
{
	return baseContents;
}

//************************************
// Method:    hasBuilding
// FullName:  BaseModel::hasBuilding
// Access:    public 
// Returns:   bool
// Parameter: UnitType t
// Comments:  Tells us whether or not this base has this building in its sphere of influence.
//************************************
bool BaseModel::hasBuildingComplete( UnitType t )
{

	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		UnitModel* curBuilding = *i;
		if(!curBuilding->isAlive()) {
			continue;
		}
		if(curBuilding->getType() == t && !curBuilding->getUnit()->isBeingConstructed()) {
			return true;
		}

	}
	return false;
}

bool BaseModel::hasBuildingUnderConstruction( UnitType t )
{

	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		UnitModel* curBuilding = *i;
		if(!curBuilding->isAlive()) {
			continue;
		}
		if(curBuilding->getType() == t && (curBuilding->getUnit()->isBeingConstructed() || !curBuilding->getUnit()->isCompleted())) {
			return true;
		}
	}
	return false;
}



//************************************
// Method:    setBuildOrderTemplate
// FullName:  BaseModel::setBuildOrderTemplate
// Access:    public 
// Returns:   void
// Parameter: BaseConfigurationTemplate * btemp
// Comments:  none
//************************************
void BaseModel::setBuildOrderTemplate( BuildOrderTemplate* btemp )
{

	baseTemplate = btemp;
	baseTemplate->setBaseModel(this);
}



//************************************
// Method:    manageWorkerPopulation
// FullName:  BaseModel::manageWorkerPopulation
// Access:    public 
// Returns:   void
// Comments:  For now we just manage minerals. But later we want to have some mechanism to also assign units to gas mining.
//************************************
void BaseModel::manageWorkerPopulation()
{

	if(baseMinerals.empty() || !managingWorkers || mineralsExhausted()) {
		// in this case we want to maynard our mineral workers
		// but do it later ;)
		return;
	}
	int assignedToGas = 0;
	bool addedGasThisTurn = false;
	for (vector<UnitModel*>::iterator i = activeWorkers.begin(); i != activeWorkers.end(); ++i)
	{
		UnitModel* currentWorker = *i;	
		if(currentWorker->getBaseOwner() != this) {
			continue;
		}
		if(currentWorker->getCurrentTaskType() != NO_TASK || currentWorker->isFollowingPath() || currentWorker->isUnderThreatRange(96)) {
			continue;
		}
		if(currentWorker->getUnit()->isAttackFrame() || currentWorker->getUnit()->isAttacking() || currentWorker->getUnit()->isStartingAttack()) {
			continue;
		}
		// if this worker is idle, send him to a random mineral patch
		if(currentWorker->getUnit()->isCompleted()) {

			if((currentWorker->getUnit()->isGatheringMinerals() || currentWorker->getUnit()->isIdle()) && hasBuildingComplete(Broodwar->self()->getRace().getRefinery()) && (!mineralsExhausted())) {
				if(workersGatheringGas+assignedToGas <= 3 && !currentWorker->getUnit()->isCarryingMinerals() && workerClaimTimer == 0) {
					currentWorker->getUnit()->rightClick(getBuilding(Broodwar->self()->getRace().getRefinery())->getUnit());
					assignedToGas++;
					addedGasThisTurn = true;
					workerClaimTimer = 256;
					continue;
				}
			}



			if(!mineralsExhausted() && currentWorker->getUnit()->isIdle()) {
				if(!getBaseMinerals().empty()) {
					//	bool foundEmpty = false;
					//	std::random_shuffle(baseMinerals.begin(), baseMinerals.end());
					int c = 0;
					Unit* tar = NULL;
					for (set<Unit*>::iterator it = baseMinerals.begin(); it != baseMinerals.end(); ++it)
					{
						Unit* curMineral = *it;
						if(curMineral->isBeingGathered() || curMineral->getResources() <= 10) {

						} else {
							tar = curMineral;
							break;
						}
					}

					if(tar == NULL) {
						Unit* minp = returnRandomMinPatch();
						if(minp != NULL) {
							currentWorker->getUnit()->rightClick(minp);
						}
						continue;
					} else {
						currentWorker->getUnit()->rightClick(tar);
						continue;
					}
				}

			}
		}

	}

}

//************************************
// Method:    getWorkers
// FullName:  BaseModel::getWorkers
// Access:    public 
// Returns:   vector<UnitModel*>
// Comments:  none
//************************************
vector<UnitModel*> BaseModel::getWorkers()
{
	return activeWorkers;
}

//************************************
// Method:    getBaseGeysers
// FullName:  BaseModel::getBaseGeysers
// Access:    public 
// Returns:   vector<Unit*>
// Comments:  none
//************************************
set<Unit*> BaseModel::getBaseGeysers()
{
	baseGeysers.clear();
	baseGeysers = loc->getGeysers();
	std::set<Unit*> gas = Broodwar->getGeysers();
	for (set<Unit*>::iterator i = gas.begin(); i != gas.end(); ++i)
	{
		Unit* cur = *i;
		if(cur->getPosition().getDistance(pos) < 464) {
			baseGeysers.insert(cur);
		}
	}
	return baseGeysers;
}

//************************************
// Method:    getBuilding
// FullName:  BaseModel::getBuilding
// Access:    public 
// Returns:   bool
// Parameter: UnitType t
// Comments:  none
//************************************
UnitModel* BaseModel::getBuilding( UnitType t )
{
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		UnitModel* curBuilding = *i;
		if(curBuilding->getType() == t) {
			return curBuilding;
		}

	}
	return NULL;
}

bool BaseModel::mineralsExhausted()
{
	return curMinerals <= 200;
}


bool BaseModel::gasExhausted()
{
	return curGas <= 200;
}

Position BaseModel::getBaseAttackLoc()
{
	Position attackLoc = Positions::None;
	if(!isAlive()) {
		return attackLoc;
	}
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		UnitModel* curBuilding = *i;
		if(curBuilding->isAlive()) {
			if(curBuilding->getUnit()->isUnderAttack()) {
				attackLoc = curBuilding->getPosition();
			}
		}
	}
	if(attackLoc == Positions::None) {
	for (vector<UnitModel*>::iterator it = defenders.begin(); it != defenders.end(); ++it)
	{
		UnitModel* cur = *it;
		if(cur->isAlive()) {
			if(cur->getUnit()->isUnderAttack()) {
				attackLoc = cur->getPosition();
			}
		}
	}
	}
	if(attackLoc == Positions::None) {
		for (vector<UnitModel*>::iterator itt = activeWorkers.begin(); itt != activeWorkers.end(); ++itt)
		{
			UnitModel* cur = *itt;
			if(cur->isAlive()) {
				if(cur->getUnit()->isUnderAttack()) {
					attackLoc = cur->getPosition();
				}
			}
		}
	}
	return attackLoc;
}

bool BaseModel::isBeingDefended()
{
	int numGuardians = 0;
	int numAttackers = 0;
	std::vector<int> percievedAttackers;
	if(defenders.empty()){
		return false;
	}
		std::vector<UnitModel*> filteredDefenders;
		Position lastAttackLoc = getBaseAttackLoc();
		for(std::vector<UnitModel*>::const_iterator it = defenders.begin(); it != defenders.end(); ++it) {
			UnitModel* cur = *it;
			if(!cur->isAlive()) {
				continue;
			}
			if(cur->getPosition().getDistance(lastAttackLoc) < cur->getType().groundWeapon().maxRange()) {
				filteredDefenders.push_back(cur);
			}

		}

	for(std::vector<UnitModel*>::const_iterator i = filteredDefenders.begin(); i != filteredDefenders.end(); ++i) {
		UnitModel* cur = *i;
		if(cur->getCurrentTaskType() == GUARD || cur->getUnit()->isAttacking()) {
			numGuardians++;
		}
		if(cur->getUnit()->isUnderAttack() || cur->getUnit()->isAttacking()) {
				percievedAttackers.push_back(overseer->getUnitManager()->getAllEnemyUnitsInRange(cur->getPosition(), 256).size());
		}
	}

	for(std::vector<int>::const_iterator i = percievedAttackers.begin(); i != percievedAttackers.end(); ++i) {
		int cur = *i;
		if(cur > numAttackers) {
			numAttackers = cur;
		}
	}
	////////Broodwar->sendText("[attackers: %d] [defenders: %d]", numAttackers, numGuardians);
	if(numGuardians == 0 || numAttackers >= numGuardians) {
		return false;
	}
	
	return true;
}

vector<UnitModel*> BaseModel::getDefenders()
{
	return defenders;
}

void BaseModel::registerNewBuilding( UnitModel* t )
{
	if(t->getType() == UnitTypes::Protoss_Pylon) {
		return;
	}
	if(baseContents.find(t) == baseContents.end()) {
		baseContents.insert(t);
	}
}

bool BaseModel::isMainBase()
{
	return main;
}

void BaseModel::setMainBase()
{
	main = true;
}

bool BaseModel::isUnderAttack()
{
	for (set<UnitModel*>::iterator it = baseContents.begin(); it != baseContents.end(); ++it)
	{
		UnitModel* curBuilding = *it;
		if(curBuilding->isAlive()) {
			if(curBuilding->getUnit()->isUnderAttack()) {
				return true;
			}
		}
	}

		for (vector<UnitModel*>::iterator i = defenders.begin(); i != defenders.end(); ++i)
		{
			UnitModel* curDefender = *i;
			if(curDefender->getUnit()->isUnderAttack()) {
				return true;
			}
		}
	

		for (vector<UnitModel*>::iterator itt = activeWorkers.begin(); itt != activeWorkers.end(); ++itt)
		{
			UnitModel* curWorker = *itt;
			if(curWorker->getUnit()->isUnderAttack()) {
				return true;
			}
		}
	
	return false;
}

BWAPI::Position BaseModel::getPosition()
{
	return pos;
}

//************************************
// Method:    isAlive
// FullName:  BaseModel::isAlive
// Access:    public 
// Returns:   bool
// Comments:  none
//************************************
bool BaseModel::isAlive()
{
	return alive;
}

set<Unit*> BaseModel::getBaseMinerals()
{
	baseMinerals.clear();
	baseMinerals = loc->getMinerals();
	std::set<Unit*> mins = Broodwar->getMinerals();
	for (set<Unit*>::iterator i = mins.begin(); i != mins.end(); ++i)
	{
		Unit* cur = *i;
		if(BWTA::getRegion(cur->getPosition()) != baseRegion) {
			continue;
		}
		if(cur->getPosition().getDistance(pos) < 464) {
			baseMinerals.insert(cur);
		}
	}

	return baseMinerals;
}

int BaseModel::getCurMineralsLeft()
{
	return curMinerals;
}

int BaseModel::getStartMinerals()
{
	return startMinerals;
}

BuildOrderTemplate* BaseModel::getBuildOrder()
{
	return baseTemplate;
}

bool BaseModel::hasSpawnedExpansion()
{
	if(expandSubject == NULL) {
	if(isMainBase()) {
		if(mainBaseSpawnTimer > 0) {
			return true;
		}
		if(mainBaseSpawnCounter < 1) {
			return false;
		} else {
			return true;
		}
	} else {
		return spawnedExpansion;
	}
	} else {
		return true;
	}
}

void BaseModel::setSpawned( bool s )
{
		if(isMainBase()) {
			if(s == true) {
				spawnedExpansion = s;
				mainBaseSpawnTimer = 8120;
				mainBaseSpawnCounter++;
			}
			if(s == false){
				if(mainBaseSpawnCounter >= 1) {
					mainBaseSpawnCounter--;
				}
				
				spawnedExpansion = s;
				mainBaseSpawnTimer = 0;

			}

		} else {
			spawnedExpansion = s;
		}
}

bool BaseModel::isUnderThreat()
{
	for (set<UnitModel*>::iterator it = baseContents.begin(); it != baseContents.end(); ++it)
	{
		UnitModel* curBuilding = *it;
		if(curBuilding->isAlive()) {
			if(curBuilding->isUnderThreat()) {
					threatLoc = curBuilding->getThreatLoc();
				return true;
			}
		}
	}

	for (vector<UnitModel*>::iterator i = defenders.begin(); i != defenders.end(); ++i)
	{
		UnitModel* curDefender = *i;
		if(curDefender->isAlive()) {
		if(curDefender->isUnderThreat()) {
			return true;
		}
		}
	}


	for (vector<UnitModel*>::iterator itt = activeWorkers.begin(); itt != activeWorkers.end(); ++itt)
	{
		UnitModel* curWorker = *itt;
		if(curWorker->isAlive()) {
		if(curWorker->isUnderThreat()) {
			return true;
		}
		}
	}
	return false;
}

BaseModelConsistencyMonitor* BaseModel::getBCM()
{
	return baseTemplate->getBCM();
}

bool BaseModel::isFriendlyBase()
{
	return friendly;
}

BWTA::Region* BaseModel::getBaseRegion()
{
	return baseRegion;
}

int BaseModel::mineralValue()
{
	int val = 0;
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		if((*i)->isAlive() && ((*i)->getType().isBuilding())){
			val+= (*i)->getType().mineralPrice();
		}
	}
	return val;
}

int BaseModel::getNumMineralWorkers()
{
	return workersMiningMinerals;
}

int BaseModel::getNumGasWorkers()
{
	return workersGatheringGas;
}

void BaseModel::randomAssignMineralWorker()
{
	// TODO: Write code
}

void BaseModel::setWorkerManagement( bool status )
{
	managingWorkers = status;
}

BaseLocation* BaseModel::getBaseLOC()
{
	return loc;
}

Unit* BaseModel::returnRandomMinPatch()
{
	getBaseMinerals();
	for (set<Unit*>::iterator i = baseMinerals.begin(); i != baseMinerals.end(); ++i)
	{
		Unit* cur = *i;
		if(cur->getResources() >= 10) {
		int r = rand()%100;
		if(r > 50) {
			return cur;
		}
		}
	}
	if(baseMinerals.empty()) {
		return NULL;
	} else {
	return *(baseMinerals.begin());
	}
}

BaseModel* BaseModel::getParent()
{
	return parent;
}

void BaseModel::setParent( BaseModel* p )
{
	parent = p;
}

void BaseModel::setSubject( UnitModel* um )
{
	subject = um;
}

int BaseModel::countNumTypeInBase( UnitType t )
{
	int val = 0;
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		if((*i)->isAlive() && (*i)->getType() == t){
			val++;
		}
	}
	return val;
}

bool BaseModel::isUnderThreatMin( int num )
{
	for (set<UnitModel*>::iterator it = baseContents.begin(); it != baseContents.end(); ++it)
	{
		UnitModel* curBuilding = *it;
		if(curBuilding->isAlive()) {
			if(curBuilding->isUnderThreatMin(num)) {
				threatLoc = curBuilding->getThreatLoc();
				return true;
			}
		}
	}

	for (vector<UnitModel*>::iterator i = defenders.begin(); i != defenders.end(); ++i)
	{
		UnitModel* curDefender = *i;
		if(curDefender->isAlive()) {
			if(curDefender->isUnderThreatMin(num)) {
				threatLoc = curDefender->getThreatLoc();
				return true;
			}
		}
	}


	for (vector<UnitModel*>::iterator itt = activeWorkers.begin(); itt != activeWorkers.end(); ++itt)
	{
		UnitModel* curWorker = *itt;
		if(curWorker->isAlive()) {
			if(curWorker->isUnderThreatMin(num)) {
				threatLoc = curWorker->getThreatLoc();
				return true;
			}
		}
	}
	return false;
}

void BaseModel::manageLocalDefenders()
{
	if(isUnderThreat()) {
		for (vector<UnitModel*>::iterator it = defenders.begin(); it != defenders.end(); ++it)
		{
			UnitModel* cur = *it;
			if(cur->isAlive()) {
				if(cur->getUnit()->isIdle()) {
					if(threatLoc != Positions::None) {
					cur->getUnit()->attack(threatLoc);
					}
				}
			}
		}
	}
}

void BaseModel::monitorForPower()
{
	if(Broodwar->getFrameCount()%768 == 0) {
	for (set<UnitModel*>::iterator it = baseContents.begin(); it != baseContents.end(); ++it)
	{
		UnitModel* curBuilding = *it;
		if(curBuilding->isAlive()) {
			if(curBuilding->getUnit()->getType().requiresPsi() && curBuilding->getUnit()->isUnpowered()) {
				if(baseTemplate != NULL) {
					if(overseer->getUnitManager()->countNumUnderConstructionAtBase(UnitTypes::Protoss_Pylon, this) == 0) {
					ConstructionTask* buildSupplyTask = new ConstructionTask(curBuilding->getTilePosition(),UnitTypes::Protoss_Pylon,overseer);
					overseer->getArbitrator()->stageNewTask(buildSupplyTask);
					overseer->registerTask(buildSupplyTask);
					return;
					}
				}
			}
		}
	}
	}

}

bool BaseModel::setAlive()
{

	if(baseContents.empty()) {
		return false;
	}
	for (set<UnitModel*>::iterator itx = baseContents.begin(); itx != baseContents.end(); ++itx)
	{
		UnitModel* curBuilding = *itx;
		if(curBuilding->getType() == UnitTypes::Resource_Vespene_Geyser) {
			continue;
		}
		if(curBuilding->getType().isBuilding()) {
			if(curBuilding->isAlive() && (curBuilding->isOwnedByPlayer() == isFriendlyBase())) {
				return true;
			}
		}

	}
	if(subject != NULL) {
		if(subject->isAlive()) {
			return true;
		}
	}
	alive = false;
	if(parent != NULL && parent != this) {
		BaseModel* gprnt = parent;
		if(parent->isAlive()) {
			parent->setSpawned(false);
		} else {
			BaseModel* grandParent = parent->getParent();
			if(grandParent != NULL) {
				if(grandParent->isAlive()) {
					if(grandParent->hasSpawnedExpansion()) {
						grandParent->setSpawned(false);
					}
				} else {
					BaseModel* greatGrandParent = parent->getParent()->getParent();
					if(greatGrandParent != NULL) {
						if(greatGrandParent->isAlive()) {
							if(greatGrandParent->hasSpawnedExpansion()) {
								greatGrandParent->setSpawned(false);
							}
						}
				}
			}
		}
	}
	}
	return false;
}

void BaseModel::setMainBaseExpandTimer( int t )
{
	mainBaseSpawnTimer = t;
}

void BaseModel::setExpandSubject( ExpandTask* e )
{
	expandSubject = e;
}

BWAPI::Position BaseModel::getBaseThreatLoc()
{
	return threatLoc;
}

std::vector<UnitModel*> BaseModel::getBaseDefenders()
{
	return defenders;
}

UnitModel* BaseModel::getRandomBuilding()
{
	if(baseContents.empty()) {
		return NULL;
	}
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); i++)
	{
		UnitModel* cur = *i;
		if(cur->isAlive()) {
			int rnum = rand()%100;
			if(rnum >= 50) {
				return cur;
			}
		}
	}
	return NULL;
}

void BaseModel::registerWorker( UnitModel* um )
{
	activeWorkers.push_back(um);
}

void BaseModel::deRegisterWorker( UnitModel* um )
{
	for (vector<UnitModel*>::iterator i = activeWorkers.begin(); i != activeWorkers.end(); i++)
	{
		if((*i) == um) {
			i = activeWorkers.erase(i);
			break;
		}
	}
}

UnitModel* BaseModel::returnRandomPylon()
{
	UnitModel* py = NULL;	
	for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
	{
		UnitModel* cur = *i;
		if(cur->getType() != UnitTypes::Protoss_Pylon) {
			continue;
		}
		if(py == NULL) {
			py = cur;
		}
			int r = rand()%100;
			if(r > 100-(100/countNumTypeInBase(UnitTypes::Protoss_Pylon))) {
				return cur;
			}
	}
	if(py == NULL) {
		for (set<UnitModel*>::iterator i = baseContents.begin(); i != baseContents.end(); ++i)
		{
			UnitModel* cur = *i;
			if(cur->getType() == UnitTypes::Protoss_Pylon) {
				return cur;
			}
		}
	}
	return py;
}

