#include "BuildingPlacement.h"

namespace { auto & map = BWEM::Map::Instance(); }

//@TODO save a target build position with each sunken/spore colony
// so that each base gets the right number of each
//@TODO also make sure sunkens don't block off the natural
//@TODO place hatcheries closer to the main ramp and tech buildings farther back
TilePosition BuildingPlacement::getPosition(BWAPI::UnitType unit)
{
	TilePosition tp = Macro::players.at(Macro::selfID).bases.front().tilePosition;
	if (unit == UnitTypes::Zerg_Sunken_Colony && Macro::players.at(Macro::selfID).bases.size() > 1)
	{
		for (size_t i = 0; i < Macro::players.at(Macro::selfID).bases.size(); i++)
		{
			if (Macro::players.at(Macro::selfID).bases.at(i).sunkenCount 
				+ Macro::players.at(Macro::selfID).bases.at(i).creepColonyCount
				< Macro::players.at(Macro::selfID).bases.at(i).desiredSunkenCount())
				tp = Macro::players.at(Macro::selfID).bases.at(i).defenseLocation;
		}
	}
	else if (unit == UnitTypes::Zerg_Spore_Colony && Macro::players.at(Macro::selfID).bases.size() > 1)
	{
		for (size_t i = 0; i < Macro::players.at(Macro::selfID).bases.size(); i++)
		{
			if (Macro::players.at(Macro::selfID).bases.at(i).sporeCount
				+ Macro::players.at(Macro::selfID).bases.at(i).creepColonyCount
				< Macro::players.at(Macro::selfID).bases.at(i).desiredSporeCount())
				tp = Macro::players.at(Macro::selfID).bases.at(i).defenseLocation;
		}
	}
	else if (unit == UnitTypes::Zerg_Extractor)
	{
		for (auto b : Macro::players.at(Macro::selfID).bases)
		{
			if (b.gasPatches > b.extractorsBuilt())
			{
				for (auto unit : BWAPI::Broodwar->getNeutralUnits())
				{
					if ((unit->getType() == BWAPI::UnitTypes::Resource_Vespene_Geyser)
						&& unit->getDistance(b.base->getPosition()) < 400)
					{
						tp = unit->getTilePosition();
					}
				}
				//tp = b.base->getClosestUnit(UnitTypes::Resource_Vespene_Geyser)->getTilePosition();
			}
		}
	}
	else
	{
		tp = Broodwar->getBuildLocation(unit, Macro::players.at(Macro::selfID).bases.front().tilePosition);
	}

	checkBounds(tp);
	return tp;
}

bool BuildingPlacement::build(CUnit unit)
{
	bool built = false;
	int buildingRange = 4;
	for (int x = -buildingRange; x <= buildingRange; x++)
	{
		for (int y = -buildingRange; y <= buildingRange; y++)
		{
			TilePosition tp = TilePosition(unit.target.x + x, unit.target.y + y);
			if (!(tp == Macro::lastBuildLocation)
				&& unit.unit->build(unit.targetUnit, tp))
			{
				built = true;
				break;
			}
		}
	}
	return built;
}

TilePosition BuildingPlacement::checkBounds(TilePosition tp)
{
	if (tp.x < 1) tp.x = 1;
	if (tp.y < 1) tp.y = 1;
	if (tp.x > map.Size().x) tp.x = map.Size().x - 2;
	if (tp.y > map.Size().y) tp.y = map.Size().y - 2;
	return tp;
}

std::vector<double> BuildingPlacement::getDirection(TilePosition tp1, TilePosition tp2)
{
	double deltaX = tp1.x - tp2.x;
	double deltaY = tp1.y - tp2.y;
	double slope = sqrt(pow(deltaX, 2.0) + pow(deltaY, 2.0));

	std::vector<double> vector;
	vector.push_back((deltaX / slope));
	vector.push_back((deltaY / slope));
	return vector;
}