//////////////////////////////////////////////////////////////////////////
//
// 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 "earlyRunBy.h"
#include "../units/him.h"
#include "../behavior/kiting.h"
#include "../behavior/scouting.h"
#include "../behavior/walking.h"
#include "../behavior/defaultBehavior.h"
#include "../Iron.h"

namespace { auto & bw = Broodwar; }




namespace iron
{


//////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                          //
//                                  class EarlyRunBy
//                                                                                          //
//////////////////////////////////////////////////////////////////////////////////////////////


EarlyRunBy::EarlyRunBy()
{
}


EarlyRunBy::~EarlyRunBy()
{
	for (MyUnit * u : m_Squad)
		if (u->GetBehavior()->IsWalking())
			u->ChangeBehavior<DefaultBehavior>(u);
}


string EarlyRunBy::StateDescription() const
{
	if (!m_started) return "-";
	if (m_started) return "started";

	return "-";
}


void EarlyRunBy::OnBWAPIUnitDestroyed(BWAPIUnit * pBWAPIUnit)
{
	if (m_started)
		if (MyUnit * u = pBWAPIUnit->IsMyUnit())
			if (contains(m_Squad, u))
				really_remove(m_Squad, u);
}


void EarlyRunBy::OnFrame_v()
{
	if ((him().Race() == Races::Terran) || (him().Race() == Races::Protoss)) return Abort();


	if (!him().StartingBase()) return;
	const Area * pHisArea = him().GetArea();


	vector<HisBuilding *> HisBlockingStaticDefenses;

	for (const auto & b : him().Buildings())
		if (b->GroundThreatBuilding())
			if (b->Completed())
				if (dist(b->Pos(), him().StartingBase()->BWEMPart()->Center()) < dist(b->Pos(), me().GetBase(0)->Center()))
				{
					if ((b->GetArea() != pHisArea) ||
						any_of(pHisArea->ChokePoints().begin(), pHisArea->ChokePoints().end(),
								[&b](const ChokePoint * cp){ return VChokePoint::Get(cp)->AirDistanceFrom(b->Pos()) < 8*32; }))
						HisBlockingStaticDefenses.push_back(b.get());
					else if (b->GetArea() == pHisArea)
						return Abort();
				}

	if (HisBlockingStaticDefenses.empty()) return;
	
	if (m_started)
	{
		for (MyUnit * u : m_Squad)
			for (const auto & fo : u->FaceOffs())
				if (!fo.His()->IsHisBuilding())
				if (!fo.His()->Type().isWorker())
					if (fo.HisAttack())
						return Abort();

		if (HisBlockingStaticDefenses.size() >= 2)
			for (MyUnit * u : m_Squad)
				if (any_of(HisBlockingStaticDefenses.begin(), HisBlockingStaticDefenses.end(), [u](HisBuilding * b)
							{ return dist(b->Pos(), u->Pos()) < dist(b->Pos(), u->PrevPos(1)); }))
				{
					u->ChangeBehavior<DefaultBehavior>(u);
				}
		really_remove_if(m_Squad, [](MyUnit * u){ return u->GetBehavior()->IsDefaultBehavior(); });

		for (MyUnit * u : m_Squad)
			if (u->GetArea() == pHisArea)
				if (dist(u->Pos(), him().StartingBase()->BWEMPart()->Center()) < 8*32)
				{
					u->SetStayInArea();
					u->ChangeBehavior<DefaultBehavior>(u);
				}
		really_remove_if(m_Squad, [](MyUnit * u){ return u->GetBehavior()->IsDefaultBehavior(); });

		if (m_Squad.empty()) m_started = false;
	}
	else
	{
		if (m_tries == 1) return Abort();

		if (HisBlockingStaticDefenses.size() >= 2) return Abort();

		vector<MyUnit *> Candidates;
		for (auto & u : me().Units(Terran_Vulture))
			if (u->Completed())
				if (u->Life() >= 50)
					if (u->GetArea() != pHisArea)
					{
						int hisBlockingStaticDefensesNearby = 0;
						int hisSoldiersNearby = 0;
						for (const auto & fo : u->FaceOffs())
							if (HisBuilding * b = fo.His()->IsHisBuilding())
							{
								if (contains(HisBlockingStaticDefenses, b))
									++hisBlockingStaticDefensesNearby;
							}
							else if (!fo.His()->Type().isWorker())
							{
								++hisSoldiersNearby;
								if (fo.HisAttack() && !fo.His()->Is(Zerg_Zergling)) return Abort();
							}

						if (hisBlockingStaticDefensesNearby >= 1)
						{
							if (hisSoldiersNearby >= 1) return;
							Candidates.push_back(u.get());
						}
					}

		if (Candidates.size() >= 3)
		{
			sort(Candidates.begin(), Candidates.end(), [](const MyUnit * a, const MyUnit * b){ return a->Life() > b->Life(); });
			Candidates.resize(3);

		///	ai()->SetDelay(500);
		///	bw << "start runby !!!" << endl;
			m_started = true;
			m_startedSince = ai()->Frame();
			++m_tries;
			m_Squad.clear();
			for (MyUnit * u : Candidates)
			{
				u->ChangeBehavior<Walking>(u, Position(pHisArea->Top()), __FILE__ + to_string(__LINE__));
				m_Squad.push_back(u);
			}
		}
	}
}


} // namespace iron



