#include "Squad.h"

using namespace MyBot;

Squad::Squad()
{
}

Squad::~Squad()
{
}

void Squad::addUnit(BWAPI::Unit unit)
{
	addUnitWithMission(unit, commonMission);

}
void Squad::addUnitWithMission(BWAPI::Unit unit, Mission newMission)
{
	unitset.insert(unit);

	setUnitMission(unit, newMission);
}

BWAPI::Unitset::iterator Squad::removeUnit(BWAPI::Unitset::iterator  it)
{
	unitMissionMap.erase((*it));

	return unitset.erase(it);
}


int Squad::getCount(BWAPI::UnitType unitType)
{
	int result = 0;
	for (auto unit : unitset) {
		if (unit->getType() == unitType) {
			result++;
		}
	}
	return result;
}

void Squad::setUnitMission(BWAPI::Unit unit, Mission newMission)
{
	if (!unit) { return; }

	auto & it = unitMissionMap.find(unit);
	if (it == unitMissionMap.end())
	{
		unitMissionMap[unit] = newMission;

		/*
		std::cout << "setUnitMission " << unit->getType().getName() << " (" << unit->getID() << ") to " << newMission.missionType;
		if (newMission.targetUnit != nullptr) {
			std::cout << " targetUnit " << newMission.targetUnit->getType().getName() << " ID " << newMission.targetUnit->getID()
				<< " at " << newMission.targetUnit->getTilePosition().x << "," << newMission.targetUnit->getTilePosition().y;
		}
		if (newMission.targetPosition != BWAPI::Positions::None) {
			std::cout << " targetPosition " << newMission.targetPosition.x / TILE_SIZE << "," << newMission.targetPosition.y / TILE_SIZE;
		}
		std::cout << std::endl;
		*/
	}
	else {
		Mission & mission = unitMissionMap[unit];

		// 그전 mission 과 달라졌을때만 바꾼다
		if (mission.missionType != newMission.missionType
			|| mission.targetPosition != newMission.targetPosition
			|| mission.targetUnit != newMission.targetUnit)
		{
			mission.missionType = newMission.missionType;
			mission.targetPosition = newMission.targetPosition;
			mission.targetUnit = newMission.targetUnit;

			mission.missionSetFrame = BWAPI::Broodwar->getFrameCount();


			/*
			std::cout << "setUnitMission " << unit->getType().getName() << " (" << unit->getID() << ") to " << newMission.missionType;
			if (newMission.targetUnit != nullptr) {
				std::cout << " targetUnit " << newMission.targetUnit->getType().getName() << " ID " << newMission.targetUnit->getID()
					<< " at " << newMission.targetUnit->getTilePosition().x << "," << newMission.targetUnit->getTilePosition().y;
			}
			if (newMission.targetPosition != BWAPI::Positions::None) {
				std::cout << " targetPosition " << newMission.targetPosition.x / TILE_SIZE << "," << newMission.targetPosition.y / TILE_SIZE;
			}
			std::cout << std::endl;
			*/
		}
	}
}

Mission* Squad::getUnitMission(BWAPI::Unit unit)
{
	auto & it = unitMissionMap.find(unit);
	if (it == unitMissionMap.end())
	{
		unitMissionMap[unit] = Mission();
	}

	return &(unitMissionMap[unit]);
}

void Squad::executeMission()
{
	// 먼저, 죽은 유닛 및 건물을 건물 유닛은 제거한다
	for (auto it = unitset.begin(); it != unitset.end(); ) {
		BWAPI::Unit myUnit = *it;
		if (myUnit == nullptr || myUnit->exists() == false || myUnit->getHitPoints() <= 0 || myUnit->getType().isBuilding()) {
			it = unitset.erase(it);
		}
		else {
			++it;
		}
	}

	// 뮤탈리스크 부대에서 오버로드, 뮤탈리스크, 에그, 라바가 아닌 유닛은 제거한다
	if (squadName.compare("mainCombatMutaliskSquad") == 0) {
		for (auto it = unitset.begin(); it != unitset.end();) {
			BWAPI::Unit myUnit = *it;
			if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Scourge
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Cocoon
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Guardian
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Devourer
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Larva
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Egg
				|| myUnit->getType() == BWAPI::UnitTypes::Zerg_Overlord)
			{
				++it;
			}
			else {
				it = unitset.erase(it);
			}
		}
	}

	for (auto it = unitMissionMap.begin(); it != unitMissionMap.end();) {
		BWAPI::Unit myUnit = (*it).first;
		if (myUnit == nullptr || myUnit->exists() == false || myUnit->getHitPoints() <= 0) {
			it = unitMissionMap.erase(it);
		}
		else {
			++it;
		}
	}

	for (auto it = unitTargetMap.begin(); it != unitTargetMap.end();) {
		BWAPI::Unit enemyUnit = (*it).first;
		BWAPI::Unit myUnit = (*it).second;
		if (enemyUnit == nullptr || enemyUnit->exists() == false || enemyUnit->getHitPoints() <= 0
			|| myUnit == nullptr || myUnit->exists() == false || myUnit->getHitPoints() <= 0) 
		{
			it = unitTargetMap.erase(it);
		}
		else {
			++it;
		}
	}

	for (auto & myUnit : unitset) {
		Mission* unitMission = getUnitMission(myUnit);

		std::map<BWAPI::Unit, UnitInfo> & unitAndUnitInfoMap = InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().selfPlayer);
		auto & it = unitAndUnitInfoMap.find(myUnit);
		if (it != unitAndUnitInfoMap.end()) {

			UnitInfo& unitInfo = it->second;

			if (unitMission->missionType == MissionType::Move) {
				if (unitMission->targetPosition != BWAPI::Positions::None) {

					// 도착했으면 미션 해제
					if (myUnit->getDistance(unitMission->targetPosition) < 3 * TILE_SIZE) {
						unitMission->missionType = MissionType::Mission_Undefined;
					}
					else if (myUnit->isBurrowed()) {
						myUnit->unburrow();
					}
					else {

						// TODO : 이동 명령을 받았지만, 드론, 오버로드 같이 공격능력이 없는데 적 유닛이 있거나 공격받고 있으면 이동경로를 수정해야 한다
						// 오버로드 드랍 의 경우에는 다른 미션으로 처리
						/*
						if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Overlord)
						{
							for (auto & it : InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer)) {
								BWAPI::Unit enemyUnit = it.first;
								UnitInfo & enemyUnitInfo = it.second;

								if (enemyUnitInfo.type.canAttack()
									&& enemyUnitInfo.type.airWeapon() != BWAPI::WeaponTypes::None
									&& enemyUnitInfo.type.isWorker() == false)
								{
									if (enemyUnitInfo.lastPosition.getDistance(myUnit->getPosition()) <= enemyUnitInfo.type.airWeapon().maxRange() + 3 * TILE_SIZE) {

										CommandUtil::move(myUnit, BWAPI::Position(unitMission->targetPosition.x + 100, unitMission->targetPosition.y + 100));
									}
								}
							}

						}
						else {
						*/
							CommandUtil::move(myUnit, unitMission->targetPosition);
						//}


					}

				}
			}
			else if (unitMission->missionType == MissionType::MovePoint) {
				if (unitMission->targetPosition != BWAPI::Positions::None) {

					// 도착했으면 미션 해제
					if (myUnit->getDistance(unitMission->targetPosition) < 1 * TILE_SIZE) {
						unitMission->missionType = MissionType::Mission_Undefined;
					}
					else {
						CommandUtil::move(myUnit, unitMission->targetPosition);
					}
				}
			}

			else if (unitMission->missionType == MissionType::Return_Home) {
				if (unitMission->targetPosition != BWAPI::Positions::None) {
					CommandUtil::move(myUnit, unitMission->targetPosition);
				}
			}
			else if (unitMission->missionType == MissionType::Wait) {
			}
			else if (unitMission->missionType == MissionType::Burrow) {
				if (myUnit->canBurrow() ) {
					if (myUnit->isBurrowed() == false) {
						myUnit->burrow();
					}
				}
			}
			else if (unitMission->missionType == MissionType::MoveAndHoldPosition) {
				// 도착했으면 미션 변경
				if (myUnit->getDistance(unitMission->targetPosition) < 0.5 * TILE_SIZE) {
					unitMission->missionType = MissionType::HoldPosition;
				}
				else {
					CommandUtil::move(myUnit, unitMission->targetPosition);
				}
			}
			else if (unitMission->missionType == MissionType::Attack) {

				bool hasCommanded = false;

				// 일반적인 CommandUtil::attack 으로는 껌밟기 버그는 안일어나지만, 저글링이 정찰 일꾼을 죽이지 못한다
				// 정찰 일꾼을 확실하게 죽이기 위해, 저글링이 정찰 일꾼을 공격하는 경우에 한해, unit->attack 으로 지시한다
				if (unitInfo.type == BWAPI::UnitTypes::Zerg_Zergling) {

					if (unitMission->targetUnit != nullptr && unitMission->targetUnit->isVisible() && unitMission->targetUnit->getHitPoints() > 0) {

						// 정찰 일꾼을 죽이는 경우에만 unit->attack 으로 지시한다
						if (unitMission->targetUnit->getType().isWorker()) {

							// 아무일 안하고 있었거나, 다른 명령을 수행하다가 처음 일꾼 공격을 명령받은 경우
							bool isFreezed = false;

							BWAPI::Order order = myUnit->getOrder();

							// 껌밟은 상황인가:
							//
							// isIdle() == false && isMoving() = true && isAccelerating() = true 
							// isIdle() == true && isMoving() = false && isAccelerating() = false 를 계속 왔다갔다하거나
							//
							// isIdle() == false && isMoving() = true && isAccelerating() = true 로 지속됨
							//
							// 위치는 계속 동일
							// 
							if (myUnit->isMoving() == true 
								&& myUnit->isAccelerating() == true
								&& unitInfo.positionBefore == myUnit->getPosition()
								&& BWAPI::Broodwar->getFrameCount() - unitInfo.positionBeforeRecordFrame >= 4			// 10프레임마다 갱신하므로, 최대 9 만큼 차이 나게 된다
								)
							{
								isFreezed = true;
							}
							
							// 껌밟은 상황이 아니고, 잘 이동 / 공격하고 있다면 계속 명령
							if (isFreezed == false) {
								if (BWAPI::Broodwar->getFrameCount() % 10 == 0) {

									if (myUnit->isAttacking() == false) {
										myUnit->attack(unitMission->targetUnit);
									}
								}
							}
							// 껌밟아서 멈춰있는 상황이라면, 껌밟은 것을 푼다
							else {

								// 근처 임의의 장소로 move 해야 잘 풀리는 듯
								// Stop 이나 HoldPosition 으로는 정지된 것 잘 안풀린다
								
								if (myUnit->getLastCommand().getType() != BWAPI::UnitCommandTypes::Stop && myUnit->getLastCommand().getType() != BWAPI::UnitCommandTypes::Hold_Position)
								{
									myUnit->stop();
									//std::cout << "stop " << std::endl;
								}
								if (myUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Stop)
								{
									myUnit->holdPosition();
									//std::cout << "holdPosition " << std::endl;
								}
								if (myUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Hold_Position)
								{
									CommandUtil::move(myUnit, unitMission->targetUnit->getPosition());
									//std::cout << "move " << std::endl;
								}
							}
						}
						// 일반적인 경우에는 CommandUtil::attackUnit 을 사용한다
						else {
							CommandUtil::attackUnit(myUnit, unitMission->targetUnit);
						}
					}
					else {
						UnitAndUnitInfoMap & enemyUnitAndUnitInfoMap = InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer);
						if (enemyUnitAndUnitInfoMap.find(unitMission->targetUnit) != enemyUnitAndUnitInfoMap.end()) {
							UnitInfo& enemyUnitInfo = enemyUnitAndUnitInfoMap.find(unitMission->targetUnit)->second;

							CommandUtil::attackMove(myUnit, enemyUnitInfo.lastPosition);
						}					
					}
				}
				// 히드라
				else if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Hydralisk) {

					hasCommanded = controlHydralisk(myUnit);

					if (hasCommanded == false) {
						if (unitMission->targetUnit != nullptr && unitMission->targetUnit->isVisible() && unitMission->targetUnit->getHitPoints() > 0) {
							CommandUtil::attackUnit(myUnit, unitMission->targetUnit);
						}
						else {
							// TODO : targetPosition ? enemyUnitInfo.lastPosition
							//UnitInfo& enemyUnitInfo = InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer).find(unitMission->targetUnit)->second;
							//CommandUtil::move(myUnit, unitMission->targetPosition);
						}
					}
				}
				// 러커
				else if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker) {

					hasCommanded = controlLurker(myUnit);

					if (hasCommanded == false) {
						if (unitMission->targetUnit != nullptr && unitMission->targetUnit->isVisible() && unitMission->targetUnit->getHitPoints() > 0) {
							CommandUtil::attackUnit(myUnit, unitMission->targetUnit);
						}
						else {
							// TODO : targetPosition ? enemyUnitInfo.lastPosition
							//UnitInfo& enemyUnitInfo = InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer).find(unitMission->targetUnit)->second;
							//CommandUtil::move(myUnit, unitMission->targetPosition);
						}
					}
				}
				// 그렇지 않은 경우는 그냥 공격
				else {
					if (unitMission->targetUnit != nullptr && unitMission->targetUnit->isVisible() && unitMission->targetUnit->getHitPoints() > 0) {
						CommandUtil::attackUnit(myUnit, unitMission->targetUnit);
					}
					else {
						// TODO : targetPosition ? enemyUnitInfo.lastPosition
						//UnitInfo& enemyUnitInfo = InformationManager::Instance().getUnitAndUnitInfoMap(InformationManager::Instance().enemyPlayer).find(unitMission->targetUnit)->second;
						//CommandUtil::attackMove(myUnit, unitMission->targetPosition);
					}
				}
			}
			else if (unitMission->missionType == MissionType::AttackMove) {

				bool hasCommanded = false;

				// 러커
				if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker) {

					hasCommanded = controlLurker(myUnit);

					if (hasCommanded == false) {
						if (myUnit->isBurrowed() == true && unitMission->targetUnit != nullptr && unitMission->targetUnit->isVisible() && unitMission->targetUnit->getHitPoints() > 0) {
							CommandUtil::attackUnit(myUnit, unitMission->targetUnit);
							hasCommanded = true;
						}
						else if (myUnit->isBurrowed() == false && unitMission->targetPosition != BWAPI::Positions::None) {
							CommandUtil::move(myUnit, unitMission->targetPosition);
							hasCommanded = true;
						}
					}
				}
				// 디파일러
				else if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Defiler) {

					hasCommanded = controlDefiler(myUnit);

					if (hasCommanded == false) {
						if (myUnit->isBurrowed() == false && unitMission->targetPosition != BWAPI::Positions::None) {
							CommandUtil::move(myUnit, unitMission->targetPosition);
							hasCommanded = true;
						}
					}
				}
				// 퀸
				else if (myUnit->getType() == BWAPI::UnitTypes::Zerg_Queen) {

					hasCommanded = controlQueen(myUnit);

					if (hasCommanded == false) {
						if (myUnit->isBurrowed() == false && unitMission->targetPosition != BWAPI::Positions::None) {
							CommandUtil::move(myUnit, unitMission->targetPosition);
							hasCommanded = true;
						}
					}
				}
				else if (myUnit->getType().canAttack()) {

					if (unitMission->targetUnit != nullptr && unitMission->targetUnit->exists() && unitMission->targetUnit->getHitPoints() > 0) {
						CommandUtil::attackUnit(myUnit, unitMission->targetUnit);
					}
					else if (unitMission->targetPosition != BWAPI::Positions::None) {

						// 도착했으면 미션 변경
						if (myUnit->getDistance(unitMission->targetPosition) < 3 * TILE_SIZE) {
							unitMission->missionType = MissionType::Mission_Undefined;
						}
						else {
							CommandUtil::attackMove(myUnit, unitMission->targetPosition);
						}
					}

				}
				// TODO : 오버로드, 퀸, 디파일러 등 canAttack 못하는 유닛은 그냥 혼자 앞서나갈 수 있음
				else {
					if (unitMission->targetPosition != BWAPI::Positions::None) {

						// 도착했으면 미션 해제
						if (myUnit->getDistance(unitMission->targetPosition) < 3 * TILE_SIZE) {
							unitMission->missionType = MissionType::Mission_Undefined;
						}
						else {
							CommandUtil::move(myUnit, unitMission->targetPosition);
						}
					}
				}
			}
			else if (unitMission->missionType == MissionType::HoldPosition) {
				if (myUnit->isHoldingPosition() == false) {
					myUnit->holdPosition();
				}
			}
			else if (unitMission->missionType == MissionType::Stop) {
				if (myUnit->isIdle() == false) {
					myUnit->stop();
				}
			}
		}
	}
}


bool Squad::controlHydralisk(BWAPI::Unit myUnit)
{
	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	double tempDistance = 0;

	return hasCommanded;
}

bool Squad::controlLurker(BWAPI::Unit myUnit)
{
	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;
	bool isToUseStopLurker = false;
	BWAPI::Position destinationPosition;

	double tempDistance = 0;

	// 근처에 러커가 공격가능한 적 유닛이 있는가?
	BWAPI::Position nearEnemyUnitPosition = BWAPI::Positions::None;
	// 근처에 러커를 공격가능한 적 유닛이 있는가?
	BWAPI::Position nearUnwinnableEnemyUnitPosition = BWAPI::Positions::None;

	for (BWAPI::Unit enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
		if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

		tempDistance = myUnit->getDistance(enemyUnit->getPosition());

		// TODO : 적 지상 유닛에게 더 가까이 가서 버로우?
		if (tempDistance <= 6 * TILE_SIZE
			&& enemyUnit->isFlying() == false)		
		{
			nearEnemyUnitPosition = enemyUnit->getPosition();
		}

		if (tempDistance <= 8 * TILE_SIZE) {
			if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Carrier
				|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Scout
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Wraith
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Battlecruiser
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel
				|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk
				|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Guardian
				) 
			{
				nearUnwinnableEnemyUnitPosition = enemyUnit->getPosition();
			}
		}
	}

	for (BWAPI::Unit enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
		if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

		if (enemyUnit->isFlying()) continue;

		tempDistance = myUnit->getDistance(enemyUnit->getPosition());
		// TODO : 적 유닛에게 더 가까이 가서 버로우
		if (tempDistance <= 6 * TILE_SIZE) {
			nearEnemyUnitPosition = enemyUnit->getPosition();
		}
	}


	// 목적지에 도착했는가?
	bool isArrived = false;
	if (unitMission->missionType == MissionType::AttackMove || unitMission->missionType == MissionType::Move) {
		destinationPosition = unitMission->targetPosition;
		if (destinationPosition != BWAPI::Positions::None) {

			// 대충 근처에 오면 버로우
			// 정확한 포지션에 가지 못할 수 있기 때문에
			if (myUnit->getDistance(destinationPosition) < 4 * TILE_SIZE) {
				isArrived = true;
			}
		}
	}
	else if (unitMission->missionType == MissionType::Attack) {
		if (unitMission->targetUnit != nullptr) {

			if (unitMission->targetUnit->getPosition().isValid()){
				// 대충 근처에 오면 버로우
				// 정확한 포지션에 가지 못할 수 있기 때문에
				if (myUnit->getDistance(unitMission->targetUnit->getPosition()) < 4 * TILE_SIZE) {
					isArrived = true;
				}
			}
		}
	}

	// 버로우 되어있지 않은 상태에서
	if (myUnit->isBurrowed() == false) {

		// 공격 명령일 경우, 근처에 적 유닛이 있으면 버로우 시킨다
		// 공격 명령이 아닐 경우에는 근처에 적 유닛이 있어도 버로우 시키지 않는다
		if (unitMission->missionType == MissionType::AttackMove || unitMission->missionType == MissionType::Attack) {

			if (nearEnemyUnitPosition != BWAPI::Positions::None) {
				myUnit->burrow();
				hasCommanded = true;
			}
		}

		// 목적지에 도착했으면 버로우 시킨다
		if (isArrived == true) {
			myUnit->burrow();
			hasCommanded = true;
		}
	}
	// 버로우 되어있는 상태에서
	else {

		// 공격 명령일 경우 
		if (unitMission->missionType == MissionType::AttackMove || unitMission->missionType == MissionType::Attack) {

			// 목적지에서 가깝든 멀든, 버로우되어있는데, 적이 사정거리 내에 근처에 있으면
			if (nearEnemyUnitPosition != BWAPI::Positions::None) {

				// 스탑러커 : 적진에서 아군 본진으로 오는 path 중간에 매복 시켜놓는 ambush Lurker 의 경우.  
				// TODO : 테란 마린 시즈탱크, 프로토스 하이템플러, 저그 (오버로드 때문에 어려울지도) 저글링 / 디파일러 사살용
				if (isToUseStopLurker) {

					int enemyGroundUnitCount = 0;
					int enemyDetectorUnitCount = 0;
					int myLurkerUnitCount = 0;
					int myOtherAttackUnitCount = 0;
					for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
						if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

						// 럴커 사정거리 : 6
						if (enemyUnit->getType().isFlyer() == false && enemyUnit->getDistance(myUnit) <= 6 * TILE_SIZE) {
							enemyGroundUnitCount++;
						}
						// 싸이언스 베쓸 : 10
						// 옵저버 : 9 + 2
						// 오버로드 : 9 + 2
						if (enemyUnit->getType().isDetector() == true && enemyUnit->getDistance(myUnit) < enemyUnit->getType().sightRange() * TILE_SIZE) {
							enemyDetectorUnitCount++;
						}
					}
					for (auto & myFriendUnit : BWAPI::Broodwar->self()->getUnits()) {

						if (myFriendUnit == nullptr || myFriendUnit->exists() == false) continue;

						if (myFriendUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker && myUnit->getPosition().getDistance(myFriendUnit->getPosition()) < 6 * TILE_SIZE) {
							myLurkerUnitCount++;
						}
						else if (myFriendUnit->getType().canAttack() && myFriendUnit->getType().isWorker() == false && myFriendUnit->getDistance(myUnit) < 6 * TILE_SIZE) {
							myOtherAttackUnitCount++;
						}
					}

					std::cout << "Lurker " << myUnit->getID()
						<< " myLurkerUnitCount " << myLurkerUnitCount
						<< " myOtherAttackUnitCount " << myOtherAttackUnitCount
						<< " enemyGroundUnitCount " << enemyGroundUnitCount
						<< std::endl;


					// 러커만 3마리 이상 같이 있고, 주위에 적 탐지유닛이 없고, 주위에 아군 공격유닛이 없으면 매복 효과 발생. 스탑 러커 가동.
					// 공격 반경 내에 적 지상유닛이 4마리 이상 될때까지 가만히 있는다
					if (myLurkerUnitCount >= 3 && enemyDetectorUnitCount == 0 && myOtherAttackUnitCount == 0) {
						if (enemyGroundUnitCount < 4) {
							myUnit->stop();
							std::cout << "Stop Lurker " << myUnit->getID() << std::endl;
							hasCommanded = true;
						}
					}
				}

				// TODO : 가장 많이 죽일 수 있는 유닛,  쪽으로 공격한다
				if (hasCommanded == false) {
					
					// 일단 공격 우선순위 높은 유닛을 먼저 공격한다
					for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
						if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;
						if (enemyUnit->getType().isFlyer() == false && enemyUnit->getDistance(myUnit) <= 6 * TILE_SIZE) {
							// 
							if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_High_Templar
								|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Archon
								|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar
								|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Dark_Archon
								|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Medic
								|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode
								|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode
								|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Ghost
								|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker
								|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Defiler
								) 
							{
								CommandUtil::attackUnit(myUnit, enemyUnit);
								break;
							}
						}
					}
				}
			}
			// 사정거리가 긴 유닛 / 공중 유닛 (ex: 탱크) 등 로부터 일방적으로 맞고만 있으면 언버로우 시킨다
			else if (nearUnwinnableEnemyUnitPosition != BWAPI::Positions::None) {
				myUnit->unburrow();
				hasCommanded = true;
			}
			// 근처에 적 유닛이 없으면 
			else {
				// 목적지로부터 멀면, 언버로우 시켜서 향후 이동을 하게 한다
				if (isArrived == false) {
					if (nearEnemyUnitPosition == BWAPI::Positions::None) {
						myUnit->unburrow();
						hasCommanded = true;
					}
				}
			}
		}
		// 이동 명령일 경우, 목적지로부터 멀면 언버로우 시킨다
		else {
			if (isArrived == false) {
				myUnit->unburrow();
				hasCommanded = true;
			}
		}
	}

	return hasCommanded;

}

bool Squad::controlQueen(BWAPI::Unit myUnit)
{

	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	BWAPI::Position destinationPosition;

	double tempDistance = 0;
	
	if (hasCommanded == false) {
		if (myUnit->getEnergy() >= BWAPI::TechTypes::Spawn_Broodlings.energyCost()) {

			// 근처에 적군 하이템플러, 시즈탱크, 디파일러, 러커가 있는가
			BWAPI::Position nearEnemyUnitPosition;

			for (BWAPI::Unit enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
				if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

				if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_High_Templar
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Defiler
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Ultralisk
					) {
					tempDistance = myUnit->getDistance(enemyUnit->getPosition());
					//if (tempDistance <= 11 * TILE_SIZE)
					{
						nearEnemyUnitPosition = enemyUnit->getPosition();

						myUnit->useTech(BWAPI::TechTypes::Plague, nearEnemyUnitPosition);
						hasCommanded = true;
					}
				}
			}
		}
	}

	if (hasCommanded == false) {
		if (myUnit->getEnergy() >= BWAPI::TechTypes::Parasite.energyCost()) {

			// 근처에 적군 옵저버나 셔틀이 있는가
			BWAPI::Position nearEnemyUnitPosition;

			for (BWAPI::Unit enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
				if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

				if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Shuttle
					|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Observer
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Corsair
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Carrier
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Arbiter
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Dropship
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Battlecruiser
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Overlord
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Defiler
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Queen
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Ultralisk
					) {
					if (enemyUnit->isParasited() == false) {
						tempDistance = myUnit->getDistance(enemyUnit->getPosition());
						//if (tempDistance <= 11 * TILE_SIZE)
						{
							nearEnemyUnitPosition = enemyUnit->getPosition();

							myUnit->useTech(BWAPI::TechTypes::Parasite, nearEnemyUnitPosition);
							hasCommanded = true;
						}
					}
				}
			}
		}
	}

	/*
	if (hasCommanded == false) {
		if (myUnit->getEnergy() >= BWAPI::TechTypes::Ensnare.energyCost()) {

			// 근처에 적군 커세어가 무리지어 있는가
			BWAPI::Position nearEnemyUnitPosition;

			for (BWAPI::Unit enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
				if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

				if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Corsair
					|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Carrier
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Probe
					|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Zealot
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_SCV
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Marine
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Wraith
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Battlecruiser
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Drone
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Zergling
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Hydralisk
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Devourer
					//|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Scourge
					) {
					if (enemyUnit->isPlagued() == false) {
						tempDistance = myUnit->getDistance(enemyUnit->getPosition());
						if (tempDistance <= 11 * TILE_SIZE)
						{
							nearEnemyUnitPosition = enemyUnit->getPosition();

							myUnit->useTech(BWAPI::TechTypes::Ensnare, nearEnemyUnitPosition);
							hasCommanded = true;
						}
					}
				}
			}
		}
	}
	*/

	return hasCommanded;
}

bool Squad::controlDefiler(BWAPI::Unit myUnit)
{
	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	BWAPI::Position destinationPosition;

	double tempDistance = 0;

	// 에너지가 적으면, 가장 가까운 저글링을 컨슘 한다
	if (BWAPI::Broodwar->self()->hasResearched(BWAPI::TechTypes::Consume)) {

		if (myUnit->getEnergy() < 150) {
			double minDistance = 1000000000;
			BWAPI::Unit targetZergling = nullptr;
			for (BWAPI::Unit zerglingUnit : BWAPI::Broodwar->self()->getUnits()) {
				if (zerglingUnit == nullptr || zerglingUnit->exists() == false) continue;

				if (zerglingUnit->getType() == BWAPI::UnitTypes::Zerg_Zergling) {
					tempDistance = myUnit->getDistance(zerglingUnit->getPosition());

					if (minDistance > tempDistance) {
						minDistance = tempDistance;
						targetZergling = zerglingUnit;
					}
				}
			}

			if (targetZergling != nullptr) {
				myUnit->useTech(BWAPI::TechTypes::Consume, targetZergling);
				hasCommanded = true;
			}
		}
	}

	if (hasCommanded == false) {
		if (myUnit->getEnergy() >= BWAPI::TechTypes::Dark_Swarm.energyCost()) {

			// 근처에 아군 러커가 버로우되어있는가?
			BWAPI::Position nearMyLurkerBurrowedPosition;

			for (BWAPI::Unit friendUnit : BWAPI::Broodwar->self()->getUnits()) {
				if (friendUnit == nullptr || friendUnit->exists() == false) continue;

				if (friendUnit->getType() == BWAPI::UnitTypes::Zerg_Lurker) {
					if (friendUnit->isBurrowed() && friendUnit->isUnderDarkSwarm() == false) {
						tempDistance = myUnit->getDistance(friendUnit->getPosition());
						//if (tempDistance <= 11 * TILE_SIZE)
						{
							nearMyLurkerBurrowedPosition = friendUnit->getPosition();

							myUnit->useTech(BWAPI::TechTypes::Dark_Swarm, nearMyLurkerBurrowedPosition);
							hasCommanded = true;
						}
					}
				}
			}
		}
	}

	if (hasCommanded == false) {
		if (myUnit->getEnergy() >= BWAPI::TechTypes::Plague.energyCost()) {

			// 근처에 적군 벙커나 캐리어가 있는가
			BWAPI::Position nearEnemyUnitPosition;

			for (BWAPI::Unit enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
				if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;

				if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Carrier
					|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Observer
					|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Arbiter
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Battlecruiser
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Wraith
					|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Bunker
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk
					|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Devourer
					) {
					if (enemyUnit->isPlagued() == false) {
						tempDistance = myUnit->getDistance(enemyUnit->getPosition());
						//if (tempDistance <= 11 * TILE_SIZE)
						{
							nearEnemyUnitPosition = enemyUnit->getPosition();

							myUnit->useTech(BWAPI::TechTypes::Plague, nearEnemyUnitPosition);
							hasCommanded = true;
						}
					}
				}
			}
		}
	}

	return hasCommanded;
}

bool Squad::controlScourge(BWAPI::Unit myUnit)
{
	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	for (auto & enemyUnit : BWAPI::Broodwar->enemy()->getUnits()) {
		if (enemyUnit == nullptr || enemyUnit->exists() == false) continue;
		if (enemyUnit->getType().isFlyer()) {

			if (enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Corsair
				|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Observer
				|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Shuttle
				|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Carrier
				|| enemyUnit->getType() == BWAPI::UnitTypes::Protoss_Arbiter
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Dropship
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Wraith
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Valkyrie
				|| enemyUnit->getType() == BWAPI::UnitTypes::Terran_Battlecruiser
				|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Overlord
				|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Mutalisk
				|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Guardian
				|| enemyUnit->getType() == BWAPI::UnitTypes::Zerg_Devourer
				)
			{
				int numAirAttackableUnit = 0;
				for (auto & enemyAroundUnit : BWAPI::Broodwar->getUnitsInRadius(enemyUnit->getPosition(), 8 * TILE_SIZE)) {
					if (enemyAroundUnit == nullptr || enemyAroundUnit->exists() == false) continue;

					if (enemyAroundUnit->getType().airWeapon() != BWAPI::WeaponTypes::None) {
						numAirAttackableUnit++;
					}
				}
				if (numAirAttackableUnit < 6) {
					CommandUtil::attackUnit(myUnit, enemyUnit);
				}
				break;
			}
		}
	}

	return hasCommanded;
}

bool Squad::controlMutalisk(BWAPI::Unit myUnit)
{
	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	return hasCommanded;
}

bool Squad::controlGuardian(BWAPI::Unit myUnit)
{
	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	return hasCommanded;
}

bool Squad::controlUltralisk(BWAPI::Unit myUnit)
{
	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	return hasCommanded;
}

bool Squad::controlDevourer(BWAPI::Unit myUnit)
{
	if (myUnit == nullptr || myUnit->exists() == false) {
		return false;
	}

	Mission* unitMission = getUnitMission(myUnit);
	bool hasCommanded = false;

	return hasCommanded;
}

