//////////////////////////////////////////////////////////////////////////
//
// 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 "starport.h"
#include "tower.h"
#include "production.h"
#include "army.h"
#include "../behavior/raiding.h"
#include "../behavior/exploring.h"
#include "../behavior/walking.h"
#include "../strategy/strategy.h"
#include "../strategy/wraithRush.h"
#include "../Iron.h"

namespace { auto & bw = Broodwar; }


namespace iron
{

//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class My<Terran_Starport>
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////


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

	void				UpdateTrainingPriority() override;

private:
};


void ExpertInTraining<Terran_Wraith>::UpdateTrainingPriority()
{
//	if (me().GetBase(0)->Center().y < ai()->GetMap().Center().y) { m_priority = 0; return; }

	if (ai()->GetStrategy()->Detected<WraithRush>())
		{ m_priority = 0; return; }

	int limit = me().Army().AirAttackOpportunity() + 2;
	limit = max(limit, 3 + count_if(him().UnitTrace().begin(), him().UnitTrace().end(), [](const pair<Unit, HisUnitTrace> & p)
				{ return p.second.Type() == Terran_Wraith; }));

	if (me().Production().GasAvailable() >= Cost(Terran_Wraith).Gas()*2/4)
	{
		if (Units() + Where()->IdlePosition() < 3)			m_priority = 475;
		else if (Units() + Where()->IdlePosition() < limit)	m_priority = 420;
		return;
	}

	m_priority = 0;
}


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

	void				UpdateConstructingPriority() override;

private:
};


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

	if (him().Race() == Races::Terran)
	{
		if (Buildings() == 0)
			if (me().CompletedBuildings(Terran_Factory) >= 2)
				if (me().CompletedUnits(Terran_Vulture) > (me().Army().HisMarines() + 2*me().Army().HisMedics()) / 2)
				{
				///	DO_ONCE ai()->SetDelay(500);
					m_priority = 500; return;
				}
	}
	
	if (him().Race() == Races::Protoss)
	{
		if (Buildings() == 0)
		{
			if (me().CompletedBuildings(Terran_Command_Center) >= 2)
				if (me().SupplyUsed() >= 80)
				{
				///	DO_ONCE ai()->SetDelay(500);
					m_priority = min(500, me().Army().AirAttackOpportunity() * 100);
					return;
				}

			if (me().CompletedBuildings(Terran_Command_Center) >= 3)
				if (me().SupplyUsed() >= 150)
				{
				///	DO_ONCE ai()->SetDelay(500);
					m_priority = 500;
					return;
				}
		}
	}
	
	if (him().Race() == Races::Zerg)
	{
		if (Buildings() == 0)
		{
			if (me().Army().HisInvisibleUnits())
				if (me().CompletedBuildings(Terran_Command_Center) >= 2)
				{
					if (me().SupplyUsed() >= 70 - 2*me().Army().HisInvisibleUnits())
					{
					///	DO_ONCE ai()->SetDelay(500);
						m_priority = min(500, me().Army().AirAttackOpportunity() * 100);
						return;
					}
				}

			if (me().CompletedBuildings(Terran_Command_Center) >= 3)
				if (me().SupplyUsed() >= 120)
				{
				///	DO_ONCE ai()->SetDelay(500);
					m_priority = 500;
					return;
				}
		}
	}

	m_priority = 0;
}


ExpertInConstructing<Terran_Starport>	My<Terran_Starport>::m_ConstructingExpert;

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

vector<ConstructingAddonExpert *> My<Terran_Starport>::m_ConstructingAddonExperts {My<Terran_Control_Tower>::GetConstructingAddonExpert()};


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

	AddTrainingExpert<Terran_Wraith>();

	m_ConstructingExpert.OnBuildingCreated();
}




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

//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class My<Terran_Wraith>
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////

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


void My<Terran_Wraith>::DefaultBehaviorOnFrame()
{CI(this);
//	return ChangeBehavior<Walking>(this, Pos(), __FILE__ + to_string(__LINE__));
//	return ChangeBehavior<Walking>(this, ai()->GetMap().Center(), __FILE__ + to_string(__LINE__));

	///	DO_ONCE ai()->SetDelay(500); bw << "Wraith here" << endl;

	if (him().StartingBase())
	{
		if (!him().StartingBaseDestroyed())
		{
		///	bw << NameWithId() << " go to his base!" << endl; ai()->SetDelay(2000);
			return ChangeBehavior<Raiding>(this, him().StartingBase()->BWEMPart()->Center());
		}
		else
		{
			return ChangeBehavior<Exploring>(this, FindArea());
		}
	}
}





	
} // namespace iron



