//////////////////////////////////////////////////////////////////////////
//
// This file is part of Iron's source files.
// Iron is free software, licensed under the MIT/X11 License. 
// A copy of the license is provided with the library in the LICENSE file.
// Copyright (c) 2016, Igor Dimitrijevic
//
//////////////////////////////////////////////////////////////////////////


#include "depot.h"
#include "../strategy/strategy.h"
#include "../strategy/zerglingRush.h"
#include "../strategy/zealotRush.h"
#include "../strategy/marineRush.h"
#include "../Iron.h"

namespace { auto & bw = Broodwar; }


namespace iron
{


//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class My<Terran_Supply_Depot>
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////


template<>
class ExpertInConstructing<Terran_Supply_Depot> : public ConstructingExpert
{
public:
						ExpertInConstructing() : ConstructingExpert(Terran_Supply_Depot) {}

	void				UpdateConstructingPriority() override;

private:
};


void ExpertInConstructing<Terran_Supply_Depot>::UpdateConstructingPriority()
{
	if (Builders() < BuildingsUncompleted()) { m_priority = 590; return; }

	if (me().SupplyMax() == 200) { m_priority = 0; return; }

	/*
	if (me().Buildings(Terran_Supply_Depot).size() < 5)
		if (me().BuildingsBeingTrained(Terran_Supply_Depot))
			{ m_priority = 0; return; }
*/

	const int supplyAvailable = me().SupplyAvailable();

	if (ai()->GetStrategy()->Detected<ZerglingRush>() ||
		ai()->GetStrategy()->Detected<ZealotRush>() ||
		ai()->GetStrategy()->Detected<MarineRush>())
			if (supplyAvailable >= 2)
				for (const auto & b : me().Buildings(Terran_Factory))
					if (b->Completed() && b->CanAcceptCommand() && !b->Unit()->isTraining())
						{ m_priority = 0; return; }

	if (auto s = ai()->GetStrategy()->Detected<ZerglingRush>())
		if (me().SupplyMax() == 18)
			if ((me().SupplyAvailable() >= 3) || !s->SnipersAvailable())
				{ m_priority = 0; return; }


/**
	if (ai()->GetStrategy()->Detected<ZerglingRush>())
		if (me().Units(Terran_Vulture).size() == 0)
			if (me().SupplyAvailable() >= 1)
				if (me().MineralsAvailable() + 3*(int)Mining::Instances().size() < 150)
					if (!me().UnitsBeingTrained(Terran_Marine))
						{ m_priority = 0; return; }
*/
//	if (!ai()->GetStrategy()->Detected<ZerglingRush>())
//		if (me().Buildings(Terran_Supply_Depot).size() == 2)
//			if (me().Buildings(Terran_Factory).size() == 0)
//				{ m_priority = 0; return; }

	if (BuildingsUncompleted() >= (Buildings() < 6 ? 1 : 2))
		{ m_priority = 0; return; }

	double trainingCapacity = 0;
	for (auto type : {Terran_Command_Center, Terran_Barracks, Terran_Factory, Terran_Starport})
		for (const auto & b : me().Buildings(type))
			if (b->Completed())
				if (b->Unit()->isTraining() && !b->Unit()->getTrainingQueue().empty())
				{
					frame_t buildTime = b->Unit()->getTrainingQueue().front().buildTime();
					trainingCapacity += 1.0 * (buildTime - b->TimeToTrain()) / buildTime;
				}
				else
					trainingCapacity += 1.0;
			else
				trainingCapacity += 1.0 * (300 - min(300, b->RemainingBuildTime())) / 300;

	bool someSupplyProviderHasJustStartedBuilding = false;
	double supplyBeeingCreated = 0;
	for (auto type : {Terran_Supply_Depot, Terran_Command_Center})
		for (const auto & b : me().Buildings(type))
			if (!b->Completed())
			{
				supplyBeeingCreated += b->Type().supplyProvided()/2 * (b->Type().buildTime() - b->RemainingBuildTime()) / b->Type().buildTime();
				if (b->RemainingBuildTime() > b->Type().buildTime()/2)
					someSupplyProviderHasJustStartedBuilding = true;
			}

//	bw << ai()->Frame() << ") ExpertInConstructing : " << me().Buildings(Terran_Supply_Depot).size() << " depots : " << supplyBeeingCreated << " "  << trainingCapacity << " " << endl;

	int n = supplyAvailable + lround(supplyBeeingCreated - trainingCapacity - 2 - (int)me().Buildings(Terran_Supply_Depot).size());
#if DEV
	bw->drawTextScreen(615, 25, "%c(%d)", Text::White, n);
#endif

	// prevents from building several supply providers at the same time
	if (someSupplyProviderHasJustStartedBuilding && (n >= -2))
		{ m_priority = 0; return; }

	if (n >= (int)me().Buildings(Terran_Supply_Depot).size()/2)
		{ m_priority = 0; return; }


	if (n < 0)	m_priority = -n * 1000;
	else		m_priority = 500 / (n+1);
}


ExpertInConstructing<Terran_Supply_Depot>	My<Terran_Supply_Depot>::m_ConstructingExpert;

ConstructingExpert * My<Terran_Supply_Depot>::GetConstructingExpert() { return &m_ConstructingExpert; }


My<Terran_Supply_Depot>::My(BWAPI::Unit u)
	: MyBuilding(u, make_unique<DefaultBehavior>(this))
{
	assert_throw(u->getType() == Terran_Supply_Depot);

	m_ConstructingExpert.OnBuildingCreated();
}


void My<Terran_Supply_Depot>::DefaultBehaviorOnFrame()
{CI(this);
	if (DefaultBehaviorOnFrame_common()) return;
}




	
} // namespace iron



