//////////////////////////////////////////////////////////////////////////
//
// 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 "barracks.h"
#include "../behavior/exploring.h"
#include "../strategy/expand.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_Barracks>
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////


template<>
class ExpertInTraining<Terran_Marine> : public TrainingExpert
{
public:
						ExpertInTraining(MyBuilding * pWhere) : TrainingExpert(Terran_Marine, pWhere) {}

	void				UpdateTrainingPriority() override;

private:
};


void ExpertInTraining<Terran_Marine>::UpdateTrainingPriority()
{
	// deal with gas steal
	if (Units() < 2) 
		for (auto & b : him().Buildings())
			if (b->Type().isRefinery())
				if (b->GetArea() == me().GetArea())
					{ m_priority = 615; return; }

	int maxCount = him().Race() == Races::Terran ? 1 : 2;
	if (auto s = ai()->GetStrategy()->Detected<ZerglingRush>()) maxCount = s->MaxMarines();
	if (auto s = ai()->GetStrategy()->Detected<ZealotRush>())   maxCount = s->MaxMarines();
	if (auto s = ai()->GetStrategy()->Detected<MarineRush>())   maxCount = s->MaxMarines();

	if (Units() >= maxCount) { m_priority = 0; return; }

	if (ai()->GetStrategy()->Detected<ZerglingRush>() ||
		ai()->GetStrategy()->Detected<ZealotRush>() ||
		ai()->GetStrategy()->Detected<MarineRush>())
		{ m_priority = 615; return; }

	if (me().Buildings(Terran_Factory).size() < 2) { m_priority = 0; return; }
	if ((Units() == 1) && (me().Buildings(Terran_Supply_Depot).size() < 3)) { m_priority = 0; return; }

	m_priority = 200;
}


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

	void				UpdateConstructingPriority() override;

private:
};


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

	if (Buildings() == 0)
	{
		if (me().SupplyUsed() >= 11)	m_priority = 610;
		else								m_priority = 590;
		return;
	}

	m_priority = 0;
}


ExpertInConstructing<Terran_Barracks>	My<Terran_Barracks>::m_ConstructingExpert;

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


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

	AddTrainingExpert<Terran_Marine>();

	m_ConstructingExpert.OnBuildingCreated();
}


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



//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class My<Terran_Marine>
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////

My<Terran_Marine>::My(BWAPI::Unit u)
	: MyUnit(u, make_unique<DefaultBehavior>(this))
{
	assert_throw(u->getType() == Terran_Marine);
}


void My<Terran_Marine>::DefaultBehaviorOnFrame()
{CI(this);
//	if (ai()->GetStrategy()->Detected<ZerglingRush>())
//		if (!GetStronghold())
//			EnterStronghold(me().GetVBase(0)->GetStronghold());
	assert_throw(GetStronghold());

	if (ai()->GetStrategy()->Detected<ZerglingRush>() ||
		ai()->GetStrategy()->Detected<ZealotRush>() ||
		ai()->GetStrategy()->Detected<MarineRush>())
			return ChangeBehavior<Exploring>(this, me().GetArea());

	if (none_of(Exploring::Instances().begin(), Exploring::Instances().end(),
		[](const Exploring * e){ return e->Where() == me().GetArea(); }))
		return ChangeBehavior<Exploring>(this, me().GetArea());

	return ChangeBehavior<Exploring>(this, findNatural(me().GetVBase(0))->BWEMPart()->GetArea());
}

	
} // namespace iron



