//////////////////////////////////////////////////////////////////////////
//
// 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 "bunker.h"
#include "../behavior/sniping.h"
#include "../strategy/strategy.h"
#include "../strategy/zerglingRush.h"
#include "../strategy/marineRush.h"
#include "../Iron.h"

namespace { auto & bw = Broodwar; }


namespace iron
{



//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class My<Terran_Bunker>
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////


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

	void				UpdateConstructingPriority() override;

private:
};


void ExpertInConstructing<Terran_Bunker>::UpdateConstructingPriority()
{
	if (me().CompletedBuildings(Terran_Barracks) == 0) { m_priority = 0; return; }

	if (Builders() < BuildingsUncompleted()) { m_priority = 590; return; }

	if (auto s = ai()->GetStrategy()->Detected<ZerglingRush>())
		if (!s->NoLocationForBunkerForDefenseCP())
			if (ai()->Me().GetVArea()->DefenseCP())
			{
				if (Buildings() < ((int)me().Units(Terran_Marine).size() + 3) / 4)
				{
					m_priority = s->MaxMarines() == 4 ? 605 : 620;
					return;
				}
			}

	if (auto s = ai()->GetStrategy()->Detected<MarineRush>())
		if (Buildings() == 0)
			if (all_of(him().Units().begin(), him().Units().end(), [](const unique_ptr<HisUnit> & u)
				{ return !u->Is(Terran_Marine) || (groundDist(u->Pos(), me().GetBase(0)->Center()) > 32*12); }))
			{
				m_priority = 605;
				return;
			}

	m_priority = 0;
}


ExpertInConstructing<Terran_Bunker>	My<Terran_Bunker>::m_ConstructingExpert;

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


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

	m_ConstructingExpert.OnBuildingCreated();
}


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


void My<Terran_Bunker>::Load(BWAPIUnit * u, bool noCheck)
{CI(this);
	assert_throw(!u->Loaded());

///	bw << NameWithId() << " load! " << u->NameWithId() << endl;
	bool result = Unit()->load(u->Unit());
	OnCommandSent(noCheck, result, NameWithId() + " load " + u->NameWithId());
}


void My<Terran_Bunker>::Unload(BWAPIUnit * u, bool noCheck)
{CI(this);
	assert_throw(u->Loaded());

///	bw << NameWithId() << " unload! " << u->NameWithId() << endl;
	bool result = Unit()->unload(u->Unit());
	OnCommandSent(noCheck, result, NameWithId() + " unload " + u->NameWithId());
}


int My<Terran_Bunker>::LoadedUnits() const
{
	return Unit()->getLoadedUnits().size();
}


int My<Terran_Bunker>::Snipers() const
{
	return count_if(Sniping::Instances().begin(), Sniping::Instances().end(), [this](const Sniping * pSniper)
								{ return pSniper->Where() == this; });
}


int My<Terran_Bunker>::MaxRepairers() const
{
	return	(Life()*4 > MaxLife()*3) ? 1 :
			(Life()*4 > MaxLife()*2) ? 2 : 3;
}

	
} // namespace iron



