#include "Strategy_BuildTaskManager.h"

using namespace MyBot;

Strategy_BuildTaskManager & Strategy_BuildTaskManager::Instance()
{
	static Strategy_BuildTaskManager instance;
	return instance;
}

Strategy_BuildTaskManager::Strategy_BuildTaskManager()
{
	isAutoWorkerTrainingMode = false;
	isAutoSupplyManagementMode = false;
}



void Strategy_BuildTaskManager::update()
{
	// 1초에 4번만 실행
	if (BWAPI::Broodwar->getFrameCount() % 6 != 0) {
		return;
	}

	if (BuildManager::Instance().buildQueue.isEmpty()) {
		isAutoWorkerTrainingMode = true;
		isAutoSupplyManagementMode = true;
	}

	// 자원에 여유가 아주 많이 있을 때에는 해처리 확장을 자동으로 하게 한다
	/*
	if (BWAPI::Broodwar->self()->minerals() > 1000) {
		isAutoWorkerTrainingMode = true;
		isAutoSupplyManagementMode = true;
	}
	else {
		isAutoWorkerTrainingMode = false;
		isAutoSupplyManagementMode = false;
	}
	*/

	//std::cout << "BWAPI::Broodwar->self()->supplyTotal() " << BWAPI::Broodwar->self()->supplyTotal() << std::endl;
	//std::cout << "BWAPI::Broodwar->self()->supplyUsed() " << BWAPI::Broodwar->self()->supplyUsed() << std::endl;

	// supply 는 게임 상 숫자의 2배
	if (BWAPI::Broodwar->self()->supplyTotal() > 30 * 2) {
		isAutoWorkerTrainingMode = true;
	}

	/*
	if (BWAPI::Broodwar->self()->supplyUsed() > 20 * 2) {
		isAutoSupplyManagementMode = true;
	}
	*/

	// 일꾼 및 서플라이 빌드
	executeWorkerTraining();

	executeSupplyManagement();

	executeConstructionTask();

	//TODO : 미리 보내놓기
	//moveWorkerToConstructionPlace();

	executeUnitBuildTask();
}


void Strategy_BuildTaskManager::executeUnitBuildTask()
{
	// 해당 갯수만큼 추가 생산하기
	// TODO : 위치 선정
	for (auto it = StrategyManager::Instance().taskList.begin(); it != StrategyManager::Instance().taskList.end(); ) {

		if ((*it).taskGoal == TaskGoalType::Build_Unit_Another) {

			//std::cout << "Build_Unit_Another " << (*it).targetUnitType.c_str() << std::endl;
			for (int i = 0; i < (*it).targetCount; i++) {

				if ((*it).isUrgent) {
					//std::cout << "queueAsHighestPriority " << (*it).targetUnitType.c_str() << std::endl;

					// 위치 지정시 task 에 있는 위치를 그대로 적용
					if ((*it).targetPosition != BWAPI::Positions::None) {
						BuildManager::Instance().buildQueue.queueAsHighestPriority((*it).targetUnitType, BWAPI::TilePosition((*it).targetPosition), false);
					}
					else {
						BuildManager::Instance().buildQueue.queueAsHighestPriority((*it).targetUnitType, false);
					}
				}
				else {
					//std::cout << "queueAsLowestPriority " << (*it).targetUnitType.c_str() << std::endl;
					// 위치 지정시 task 에 있는 위치를 그대로 적용
					if ((*it).targetPosition != BWAPI::Positions::None) {
						BuildManager::Instance().buildQueue.queueAsLowestPriority((*it).targetUnitType, BWAPI::TilePosition((*it).targetPosition), false);
					}
					else {
						BuildManager::Instance().buildQueue.queueAsLowestPriority((*it).targetUnitType, false);
					}
				}
			}
			it = StrategyManager::Instance().taskList.erase(it);
		}
		else {
			++it;
		}
	}

	// 일정 갯수까지 생산하기
	// TODO : 여러개가 있을 경우, 무엇을 먼저 생산할 것인가
	for (auto it = StrategyManager::Instance().taskList.begin(); it != StrategyManager::Instance().taskList.end();) {
		if ((*it).taskGoal == TaskGoalType::Build_Unit_By_Limit) {			
			BuildUnitByLimit(*it, MetaType((*it).targetUnitType), (*it).targetCount);
		}
		++it;
	}
}

void Strategy_BuildTaskManager::executeConstructionTask()
{
	// 현재 BuildStrategy 를 수행하는데 필요한 최소한의 건물들을 건설한다
	// 기존 BuildStrategy 에서 새로운 BuildStrategy 로 바뀌었을때 뿐만 아니라, 
	// BuildStrategy 가 안바뀌었어도 필요한 건물이 파괴/취소되었을 경우, 필요한 건물을 신규 건설해서 보충하도록 하는 것이다

	for (auto & task : StrategyManager::Instance().taskList) {

		/*
		if (task.taskGoal == TaskGoalType::Build_Unit_By_Limit) {

			if (task.targetUnitType == BWAPI::UnitTypes::Zerg_Hydralisk_Den) {
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Hatchery));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Spawning_Pool));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Hydralisk_Den));
			}
			else if (task.targetUnitType == BWAPI::UnitTypes::Zerg_Sunken_Colony) {
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Hatchery));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Spawning_Pool));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Creep_Colony));
			}
			else if (task.targetUnitType == BWAPI::UnitTypes::Zerg_Spire) {
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Hatchery));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Spawning_Pool));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Lair));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Spire));
			}
			else if (task.targetUnitType == BWAPI::UnitTypes::Zerg_Queens_Nest) {
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Hatchery));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Spawning_Pool));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Lair));
				checkBuildPreconditionAndBuildOne(task, MetaType(BWAPI::UnitTypes::Zerg_Queens_Nest));
			}
		}
		else 
		*/
		if (task.taskGoal == TaskGoalType::Build_Tech) {
			checkBuildPreconditionAndBuildOne(task, MetaType(task.targetTechType));
		}
		else if (task.taskGoal == TaskGoalType::Build_Upgrade) {
			checkBuildPreconditionAndBuildOne(task, MetaType(task.targetUpgradeType));
		}
	}
}
void Strategy_BuildTaskManager::checkBuildPreconditionAndBuildOne(StrategicTask task, MetaType metaType)
{
	// TODO : 선행 건물, 선행 기술 등을 체크해서 선행 요소가 파괴되어 다시 지어야 하는 것은 나중에 코딩한다
	// TODO : SeedPositionStrategy 

	// TODO : Sunken 성큰 계속 짓는다
	// TODO : 해처리 계속 짓는다

	// metaType 이 건물인 경우, 이미 빌드되어있거나 빌드 중이면 빌드하지않고, 그렇지 않으면 빌드한다
	if (metaType.isBuilding()) {

		if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Hatchery)
		{
			if (BWAPI::Broodwar->canMake(BWAPI::UnitTypes::Zerg_Hatchery)
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hatchery) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Hatchery) == 0
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Lair) == 0
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Hive) == 0)
			{
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType()) == 0) {
					if (ConstructionManager::Instance().getConstructionQueueItemCount(metaType.getUnitType()) == 0) {
						BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUnitType(), false);
					}
				}
			}
		}
		else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Lair)
		{
			if (BWAPI::Broodwar->canMake(BWAPI::UnitTypes::Zerg_Lair)
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Lair) == 0
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Hive) == 0)
			{
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType()) == 0) {
					BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUnitType(), false);
				}
			}
		}
		else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Hive)
		{
			if (BWAPI::Broodwar->canMake(BWAPI::UnitTypes::Zerg_Hive)
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Hive) == 0)
			{
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType()) == 0) {
					BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUnitType(), false);
				}
			}
		}
		else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Greater_Spire)
		{
			if (BWAPI::Broodwar->canMake(BWAPI::UnitTypes::Zerg_Greater_Spire)
				&& BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Greater_Spire) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Greater_Spire) == 0)
			{
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType()) == 0) {
					BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUnitType(), false);
				}
			}
		}
		else {
			if (BWAPI::Broodwar->canMake(metaType.getUnitType())
				&& BWAPI::Broodwar->self()->completedUnitCount(metaType.getUnitType()) == 0
				&& BWAPI::Broodwar->self()->incompleteUnitCount(metaType.getUnitType()) == 0)
			{
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType()) == 0) {
					if (ConstructionManager::Instance().getConstructionQueueItemCount(metaType.getUnitType()) == 0) {
						BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUnitType(), false);
					}
				}
			}

		}
	}
	// metaType 이 Tech / Upgrade 인 경우, 이미 리서치되어있거나 리서치 중이면 빌드하지않고, 그렇지 않으면 빌드한다
	else if (metaType.isTech())
	{
		BWAPI::UnitType producerType = metaType.whatBuilds();
		BWAPI::UnitType requiredUnitType = metaType.getTechType().requiredUnit();

		if (BWAPI::Broodwar->self()->hasResearched(metaType.getTechType()) == false
			&& BWAPI::Broodwar->self()->isResearching(metaType.getTechType()) == false) 
		{
			// 버로우 리서치는 해처리 뿐만 아니라 레어, 하이브에서도 가능하지만, BWAPI 4.1.2 에서는 해처리에서만 가능
			/*
			bool isThereProducer = false;
			if (producerType == BWAPI::UnitTypes::Zerg_Hatchery) {
				isThereProducer = (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hatchery) + BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair) + BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive) > 0);
			}
			else {
				isThereProducer = (BWAPI::Broodwar->self()->completedUnitCount(producerType) > 0);
			}

			if (isThereProducer) {
			*/
			if (true) {
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getTechType()) == 0) {
					//std::cout << "Build_Tech : " << metaType.getTechType().c_str()
					//	<< " hasResearched " << BWAPI::Broodwar->self()->hasResearched(metaType.getTechType())
					//	<< " isResearching " << BWAPI::Broodwar->self()->isResearching(metaType.getTechType())
					//	<< " producer Count " << BWAPI::Broodwar->self()->completedUnitCount(producerType)
					//	<< " getItemCount " << BuildManager::Instance().buildQueue.getItemCount(metaType.getTechType())
					//	<< std::endl;
										
					BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getTechType(), task.isUrgent);
				}
			}
		}
	}
	else if (metaType.isUpgrade())
	{
		BWAPI::UnitType producerType = metaType.whatBuilds();
		BWAPI::UnitType requiredUnitType = metaType.getUpgradeType().whatsRequired();

		if (BWAPI::Broodwar->self()->getUpgradeLevel(metaType.getUpgradeType()) < task.targetCount
			&& BWAPI::Broodwar->self()->isUpgrading(metaType.getUpgradeType()) == false) {

			// 오버로드 업그레이드는 레어 뿐만 아니라 하이브에서도 가능하지만, BWAPI 4.1.2 에서는 레어에서만 가능
			/*
			bool isThereProducer = false;
			if (producerType == BWAPI::UnitTypes::Zerg_Lair) {
				isThereProducer = (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair) + BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive ) > 0);
			}
			// 공중유닛 업그레이드는 스파이어 뿐만 아니라 그레이터 스파이어에서도 가능하지만, BWAPI 4.1.2 에서는 레어에서만 가능
			else if (producerType == BWAPI::UnitTypes::Zerg_Spire) {
				isThereProducer = (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Spire) + BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Greater_Spire) > 0);
			}
			else {
				isThereProducer = (BWAPI::Broodwar->self()->completedUnitCount(producerType) > 0);
			}

			if (isThereProducer) {
			*/
			if (true) {
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUpgradeType()) == 0) {

					//std::cout << "Build_Upgrade : " << metaType.getUpgradeType().c_str()
					//	<< " task.targetCount " << task.targetCount
					//	<< " getUpgradeLevel " << BWAPI::Broodwar->self()->getUpgradeLevel(metaType.getUpgradeType())
					//	<< " isUpgrading " << BWAPI::Broodwar->self()->isUpgrading(metaType.getUpgradeType())
					//	<< " producer Count " << BWAPI::Broodwar->self()->completedUnitCount(producerType)
					//	<< " getItemCount " << BuildManager::Instance().buildQueue.getItemCount(metaType.getUpgradeType())
					//	<< std::endl;

					BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUpgradeType(), task.isUrgent);
				}
			}
		}
	}

}

void Strategy_BuildTaskManager::BuildUnitByLimit(StrategicTask task, MetaType metaType, int limitCount)
{
	// TODO : SeedPositionStrategy

	// metaType 이 건물인 경우
	int currentCount = 0;
	int currentCreepColonyCount = 0;
	int currentCreepColonyCompletedCount = 0;

	if (metaType.isBuilding()) {

		if (BWAPI::Broodwar->canMake(metaType.getUnitType())) {

			currentCount += BWAPI::Broodwar->self()->completedUnitCount(metaType.getUnitType()) + BWAPI::Broodwar->self()->incompleteUnitCount(metaType.getUnitType());
			currentCount += BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType());
			currentCount += ConstructionManager::Instance().getConstructionQueueItemCount(metaType.getUnitType());
			
			// TODO : 성큰, 스포어
			if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Sunken_Colony
				|| metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Spore_Colony) 
			{
				currentCreepColonyCompletedCount = BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Creep_Colony);
				currentCreepColonyCount += BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Creep_Colony) + BWAPI::Broodwar->self()->incompleteUnitCount(BWAPI::UnitTypes::Zerg_Creep_Colony);
				currentCreepColonyCount += BuildManager::Instance().buildQueue.getItemCount(BWAPI::UnitTypes::Zerg_Creep_Colony);
				currentCreepColonyCount += ConstructionManager::Instance().getConstructionQueueItemCount(BWAPI::UnitTypes::Zerg_Creep_Colony);

				//std::cout << "BuildUnitByLimit : Zerg_Sunken_Colony " 
				//	<< " limitCount " << limitCount
				//	<< " currentCount " << currentCount
				//	<< " currentCreepColonyCompletedCount " << currentCreepColonyCompletedCount
				//	<< " currentCreepColonyCount " << currentCreepColonyCount
				//	<< std::endl;

				if (currentCount + currentCreepColonyCount < limitCount) {

					// 크립 콜로니를 건설 안하고 있으면
					if (BuildManager::Instance().buildQueue.getItemCount(BWAPI::UnitTypes::Zerg_Creep_Colony) == 0
						&& ConstructionManager::Instance().getConstructionQueueItemCount(BWAPI::UnitTypes::Zerg_Creep_Colony) == 0) {

						BWAPI::TilePosition seedPosition;

						// TODO : 성큰 콜로니 위치 선정
						if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Sunken_Colony) {
							// 앞마당 안먹었을 경우
							if (InformationManager::Instance().hasBuildingAroundBaseLocation(StrategyManager::Instance().myFirstExpansionBaseLocation, 
									InformationManager::Instance().selfPlayer, 10) == false) 
							{								
								seedPosition = StrategyManager::Instance().myMainBaseLocation->getTilePosition();
							}
							// 앞마당 먹었을 경우
							else {
								// 적 종족 및 전략에 따라, 맵에 따라, 성큰 갯수에 따라
								seedPosition = StrategyManager::Instance().myFirstExpansionBaseLocation->getTilePosition();
							}
						}
						// TODO : 스포어 콜로니 위치 선정
						else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Spore_Colony) {
							seedPosition = StrategyManager::Instance().myMainBaseLocation->getTilePosition();
						}

						BWAPI::TilePosition possiblePosition = ConstructionPlaceFinder::Instance().getBuildLocationNear(BWAPI::UnitTypes::Zerg_Creep_Colony, seedPosition);
						if (possiblePosition != BWAPI::TilePositions::None) {
							BuildManager::Instance().buildQueue.queueAsLowestPriority(BWAPI::UnitTypes::Zerg_Creep_Colony, possiblePosition, false);
							//std::cout << "queueAsLowestPriority Zerg_Creep_Colony at " << possiblePosition.x << "," << possiblePosition.y << std::endl;
							currentCreepColonyCount++;
						}
					}
				}
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Creep_Colony) {
				currentCount = BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Zerg_Creep_Colony);
				currentCount += BuildManager::Instance().buildQueue.getItemCount(BWAPI::UnitTypes::Zerg_Creep_Colony);
				currentCount += ConstructionManager::Instance().getConstructionQueueItemCount(BWAPI::UnitTypes::Zerg_Creep_Colony);
				currentCount += BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Zerg_Sunken_Colony);
				currentCount += BuildManager::Instance().buildQueue.getItemCount(BWAPI::UnitTypes::Zerg_Sunken_Colony);
				currentCount += ConstructionManager::Instance().getConstructionQueueItemCount(BWAPI::UnitTypes::Zerg_Sunken_Colony);
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Lair) {
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Lair && unit->isMorphing() == true) {
						currentCount++;
					}
				}
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Hive) {
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Hive && unit->isMorphing() == true) {
						currentCount++;
					}
				}
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Greater_Spire) {
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Greater_Spire && unit->isMorphing() == true) {
						currentCount++;
					}
				}
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Lurker) {
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Lurker_Egg && unit->isMorphing() == true) {
						currentCount++;
					}
				}
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Guardian) {
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Cocoon && unit->isMorphing() == true && unit->getBuildType() == BWAPI::UnitTypes::Zerg_Guardian) {
						currentCount++;
					}
				}
			}
			else if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Devourer) {
				for (auto & unit : BWAPI::Broodwar->self()->getUnits()) {
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Cocoon && unit->isMorphing() == true && unit->getBuildType() == BWAPI::UnitTypes::Zerg_Devourer) {
						currentCount++;
					}
				}
			}

			if (currentCount < limitCount) {

				// 성큰의 경우 크립이 먼저 있어야 한다
				if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Sunken_Colony
					|| metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Spore_Colony) 
				{
					if (currentCreepColonyCompletedCount == 0) {
						return;
					}
				}

				//std::cout << "BuildUnitByLimit : " << metaType.getUnitType().c_str()
				//	<< " limitCount " << limitCount
				//	<< " currentCount " << currentCount
				//	<< std::endl;


				if (metaType.getUnitType() == BWAPI::UnitTypes::Zerg_Creep_Colony) {
					BWAPI::TilePosition possiblePosition = BWAPI::TilePositions::None;
					for (auto & chokepoint : StrategyManager::Instance().frontlineChokepointList) {
						possiblePosition = ConstructionPlaceFinder::Instance().getBuildLocationNear(BWAPI::UnitTypes::Zerg_Creep_Colony, BWAPI::TilePosition(chokepoint->getCenter()));
						if (possiblePosition != BWAPI::TilePositions::None) {
							BuildManager::Instance().buildQueue.queueAsHighestPriority(BWAPI::UnitTypes::Zerg_Creep_Colony, possiblePosition, true);
							//std::cout << "queueAsLowestPriority Zerg_Creep_Colony at " << possiblePosition.x << "," << possiblePosition.y << std::endl;
							break;
						}
					}

					if (possiblePosition == BWAPI::TilePositions::None) {
						possiblePosition = ConstructionPlaceFinder::Instance().getBuildLocationNear(BWAPI::UnitTypes::Zerg_Creep_Colony, StrategyManager::Instance().myFirstExpansionBaseLocation->getTilePosition());
						if (possiblePosition != BWAPI::TilePositions::None) {
							BuildManager::Instance().buildQueue.queueAsHighestPriority(BWAPI::UnitTypes::Zerg_Creep_Colony, possiblePosition, true);
							//std::cout << "queueAsLowestPriority Zerg_Creep_Colony at " << possiblePosition.x << "," << possiblePosition.y << std::endl;
						}
					}

					if (possiblePosition == BWAPI::TilePositions::None) {
						possiblePosition = ConstructionPlaceFinder::Instance().getBuildLocationNear(BWAPI::UnitTypes::Zerg_Creep_Colony, StrategyManager::Instance().myMainBaseLocation->getTilePosition());
						if (possiblePosition != BWAPI::TilePositions::None) {
							BuildManager::Instance().buildQueue.queueAsHighestPriority(BWAPI::UnitTypes::Zerg_Creep_Colony, possiblePosition, true);
							//std::cout << "queueAsLowestPriority Zerg_Creep_Colony at " << possiblePosition.x << "," << possiblePosition.y << std::endl;
						}
					}
				}
				else {
					BuildManager::Instance().buildQueue.queueAsHighestPriority(metaType.getUnitType(), true);
				}

			}
		}
	}
	// metaType 이 건물이 아닌 유닛 인 경우
	else if (metaType.isUnit()) {

		if (BWAPI::Broodwar->canMake(metaType.getUnitType()) && BWAPI::Broodwar->self()->supplyUsed() < 390) {
			currentCount += BWAPI::Broodwar->self()->completedUnitCount(metaType.getUnitType()) + BWAPI::Broodwar->self()->incompleteUnitCount(metaType.getUnitType());
			currentCount += BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType());
						
			//std::cout << "BuildUnitByLimit : " << metaType.getUnitType().c_str()
			//	<< " limitCount " << limitCount
			//	<< " currentCount " << currentCount
			//	<< std::endl;

			if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg) {

				for (auto & unit : BWAPI::Broodwar->self()->getUnits())
				{
					if (unit == nullptr || unit->exists() == false) continue;
					if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg) {
						// Zerg_Egg 에게 morph 명령을 내리면 isMorphing = true, isBeingConstructed = true, isConstructing = true 가 된다
						// Zerg_Egg 가 다른 유닛으로 바뀌면서 새로 만들어진 유닛은 잠시 isBeingConstructed = true, isConstructing = true 가 되었다가, 
						if (unit->isMorphing() && unit->getBuildType() == metaType.getUnitType()) {

							if (metaType.getUnitType().isTwoUnitsInOneEgg()) {
								currentCount+=2;
							}
							else {
								currentCount++;
							}
						}
					}
				}
			}

			if (currentCount < limitCount) {
				if (BuildManager::Instance().buildQueue.getItemCount(metaType.getUnitType()) == 0) 
				{
					BuildManager::Instance().buildQueue.queueAsLowestPriority(metaType.getUnitType(), false);
				}
			}
		}

	}
}



// 일꾼 계속 추가 생산
void Strategy_BuildTaskManager::executeWorkerTraining()
{
	// isAutoWorkerTrainingMode 가 아니면 하지 않습니다
	if (isAutoWorkerTrainingMode == false) {
		return;
	}

	if (BWAPI::Broodwar->self()->minerals() >= 50) {

		// workerCount = 현재 일꾼 수 + 생산중인 일꾼 수
		int workerCount = BWAPI::Broodwar->self()->allUnitCount(InformationManager::Instance().getWorkerType());

		if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg) {

			for (auto & unit : BWAPI::Broodwar->self()->getUnits())
			{
				if (unit == nullptr || unit->exists() == false) continue;
				if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg) {
					// Zerg_Egg 에게 morph 명령을 내리면 isMorphing = true, isBeingConstructed = true, isConstructing = true 가 된다
					// Zerg_Egg 가 다른 유닛으로 바뀌면서 새로 만들어진 유닛은 잠시 isBeingConstructed = true, isConstructing = true 가 되었다가, 
					if (unit->isMorphing() && unit->getBuildType() == BWAPI::UnitTypes::Zerg_Drone) {
						workerCount++;
					}
				}
			}
		}
		else {
			for (auto & unit : BWAPI::Broodwar->self()->getUnits())
			{
				if (unit == nullptr || unit->exists() == false) continue;
				if (unit->getType().isResourceDepot())
				{
					if (unit->isTraining()) {
						workerCount += unit->getTrainingQueue().size();
					}
				}
			}
		}

		// 최적의 일꾼 수 = 미네랄 * 1 + 가스 * 3 + (3 여유분)
		int optimalWorkerCount = 0;
		for (BWTA::BaseLocation* baseLocation : InformationManager::Instance().getOccupiedBaseLocations(InformationManager::Instance().selfPlayer)) {
			optimalWorkerCount += baseLocation->getMinerals().size();
			optimalWorkerCount += baseLocation->getGeysers().size() * 3;
			optimalWorkerCount += 3;
		}

		if (workerCount < optimalWorkerCount ) {
			for (auto & unit : BWAPI::Broodwar->self()->getUnits())
			{
				if (unit == nullptr || unit->exists() == false) continue;
				if (unit->getType().isResourceDepot())
				{
					if (unit->isTraining() == false || unit->getLarva().size() > 0) {

						// 빌드큐에 일꾼 생산이 1개는 있도록 한다
						if (BuildManager::Instance().buildQueue.getItemCount(InformationManager::Instance().getWorkerType()) == 0) {
							//std::cout << "worker enqueue" << std::endl;
							BuildManager::Instance().buildQueue.queueAsLowestPriority(MetaType(InformationManager::Instance().getWorkerType()), false);
						}
					}
				}
			}
		}
	}
}

// Supply DeadLock 예방 및 SupplyProvider 가 부족해질 상황 에 대한 선제적 대응으로서 SupplyProvider를 추가 건설/생산한다
void Strategy_BuildTaskManager::executeSupplyManagement()
{
	// isAutoSupplyManagementMode 모드이거나
	// 중간에 오버로드가 죽어서 supplyUsed 가 supplyTotal 보다 커져버렸을 때 오버로드 자동 생산
	// 이미 supplyTotal 이 200 꽉찼으면 더이상 안한다
	if ( (isAutoSupplyManagementMode == true 
		|| BWAPI::Broodwar->self()->supplyUsed() > BWAPI::Broodwar->self()->supplyTotal()) 
		&& BWAPI::Broodwar->self()->supplyTotal() < 400) 
	{
		// 1초에 한번만 실행
		if (BWAPI::Broodwar->getFrameCount() % 24 != 0) {
			return;
		}
	
		// 게임에서는 서플라이 값이 200까지 있지만, BWAPI 에서는 서플라이 값이 400까지 있다
		// 저글링 1마리가 게임에서는 서플라이를 0.5 차지하지만, BWAPI 에서는 서플라이를 1 차지한다
		if (BWAPI::Broodwar->self()->supplyTotal() <= 400)
		{
			// 최대 larva 갯수 (ResourceDepot의 갯수 * 3) 만큼 buildQueue에 있는 unit 들이 생산될 것이므로, supplyNeededForBuildQueueUnits 를 계산한다 
			int supplyNeededForBuildQueueUnits = 0;

			int supplyIncresePlanInBuildQueue = 0;

			int buildQueueUnitCount = 0;
			// 
			int buildQueueUnitCountMax = (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hatchery)
				+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair)
				+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive)) * 3;

			for (size_t i = 0; i < BuildManager::Instance().buildQueue.size(); i++) {
				BuildOrderItem t = BuildManager::Instance().buildQueue[i];
				if (t.metaType.isUnit() && !t.metaType.isBuilding()) {

					supplyNeededForBuildQueueUnits += t.metaType.getUnitType().supplyRequired();

					supplyIncresePlanInBuildQueue += t.metaType.getUnitType().supplyProvided();

					buildQueueUnitCount++;
					if (buildQueueUnitCount == buildQueueUnitCountMax) {
						break;
					}
				}
			}

			// 최대 larva 갯수 (ResourceDepot의 갯수 * 3) * 서플라이 2 짜리 유닛을 생산한다고 가정. 
			// 울트라, 러커 등 고급 유닛을 뽑을때는 * 서플라이 3 ~ 4 짜리 유닛을 생산한다고 가정해야함
			int defaultSupplyMargin = (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hatchery)
				+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair)
				+ BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive)) * 3 * 2;

			// 추가 수정 : Hatchery 만 있을 때에는 서플라이 0.5 ~ 1 짜리 유닛인 저글링, 히드라 밖에 생산안되므로 라바 갯수만큼만 서플라이 마진 확보하면 되지만
			// Lair 가 만들어진 이후에는 서플라이 2 짜리 유닛인 히드라 -> 러커, 뮤탈리스크 등이 생산되므로 라바 갯수 * 2 만큼 서플라이 마진 확보
			// 울트라리스크 캐번이 만들어진 이후에는 서플라이 4 짜리 유닛인 울트라리스크가 생산되나, 자원의 한계가 있으므로, 자원을 고려해서 최대 라바 갯수 * 4 만큼 서플라이 마진 확보
			if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Lair) > 0
				|| BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Hive) > 0) 
			{
				defaultSupplyMargin = defaultSupplyMargin * 2;
			}

			if (BWAPI::Broodwar->self()->completedUnitCount(BWAPI::UnitTypes::Zerg_Ultralisk_Cavern) > 0) {
				int possibleUltraliskNumber = std::min(BWAPI::Broodwar->self()->minerals() / 200, BWAPI::Broodwar->self()->gas() / 200);

				defaultSupplyMargin = std::max(defaultSupplyMargin, possibleUltraliskNumber * 4 * 2);
			}

			supplyNeededForBuildQueueUnits = std::max(defaultSupplyMargin, supplyNeededForBuildQueueUnits);

			// currentSupplyShortage 를 계산한다
			int currentSupplyShortage = BWAPI::Broodwar->self()->supplyUsed() + supplyNeededForBuildQueueUnits - BWAPI::Broodwar->self()->supplyTotal() - supplyIncresePlanInBuildQueue;
			
			// currentSupplyShortage 가 부족분이 있고, 서플라이가 200 꽉차지 않았으면
			if (currentSupplyShortage > 0 && BWAPI::Broodwar->self()->supplyTotal() < 400) {

				// 생산/건설 중인 Supply를 센다
				int onBuildingSupplyCount = 0;

				// 저그 종족인 경우, 생산중인 Zerg_Overlord 를 센다
				if (BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg) {
					for (auto & unit : BWAPI::Broodwar->self()->getUnits())
					{
						if (unit == nullptr || unit->exists() == false) continue;
						if (unit->getType() == BWAPI::UnitTypes::Zerg_Egg && unit->getBuildType() == BWAPI::UnitTypes::Zerg_Overlord) {
							onBuildingSupplyCount += BWAPI::UnitTypes::Zerg_Overlord.supplyProvided();
						}
						// 갓태어난 Overlord 는 아직 SupplyTotal 에 반영안되어서, 추가 카운트를 해줘야함 
						if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord && unit->isConstructing()) {
							onBuildingSupplyCount += BWAPI::UnitTypes::Zerg_Overlord.supplyProvided();
						}
					}
				}
				// 저그 종족이 아닌 경우, 건설중인 Protoss_Pylon, Terran_Supply_Depot 를 센다
				else {
					onBuildingSupplyCount += ConstructionManager::Instance().getConstructionQueueItemCount(InformationManager::Instance().getBasicSupplyProviderUnitType()) * InformationManager::Instance().getBasicSupplyProviderUnitType().supplyProvided();
				}

				//std::cout << "currentSupplyShortage : " << currentSupplyShortage << " onBuildingSupplyCount : " << onBuildingSupplyCount << std::endl;

				if (currentSupplyShortage > onBuildingSupplyCount) {

					// BuildQueue 최상단에 SupplyProvider 가 있지 않으면 enqueue 한다
					bool isToEnqueue = true;
					if (!BuildManager::Instance().buildQueue.isEmpty()) {
						BuildOrderItem currentItem = BuildManager::Instance().buildQueue.getHighestPriorityItem();
						if (currentItem.metaType.isUnit() && currentItem.metaType.getUnitType() == InformationManager::Instance().getBasicSupplyProviderUnitType()) {
							isToEnqueue = false;
						}
					}
					if (isToEnqueue) {
						//std::cout << "enqueue supply provider " << InformationManager::Instance().getBasicSupplyProviderUnitType().getName().c_str() << std::endl;
						BuildManager::Instance().buildQueue.queueAsHighestPriority(MetaType(InformationManager::Instance().getBasicSupplyProviderUnitType()), true);
					}
				}

			}

	}
}
}
