//////////////////////////////////////////////////////////////////////////
//
// 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 "scan.h"
#include "../behavior/behavior.h"
#include "../behavior/sieging.h"
#include "../units/factory.h"
#include "../units/comsat.h"
#include "../Iron.h"

namespace { auto & bw = Broodwar; }


namespace iron
{



void scan()
{
	const int cost = Cost(TechTypes::Scanner_Sweep).Energy();

	static frame_t sScanLastTime = 0;
	if (ai()->Frame() - sScanLastTime < 100) return;

	int totalAvailableScans = 0;
	int maxAvailableScansPerComsat = 0;
	My<Terran_Comsat_Station> * pBestComsat = nullptr;
	for (const unique_ptr<MyBuilding> & b : me().Buildings(Terran_Comsat_Station))
		if (b->Completed())
		{
			int availableScans = b->Energy() / cost;
			totalAvailableScans += availableScans;
			if (availableScans > maxAvailableScansPerComsat)
			{
				maxAvailableScansPerComsat = availableScans;
				pBestComsat = b->IsMy<Terran_Comsat_Station>();
			}
		}

	me().SetTotalAvailableScans(totalAvailableScans);

	if (!(pBestComsat && pBestComsat->CanAcceptCommand())) return;

	
	map<HisBWAPIUnit *, vector<MyUnit *>> map_Target_Candidates;
	for (const auto & u : him().Units())
		if (u->Is(Zerg_Lurker))
			if (u->InFog() || !u->Unit()->isDetected())
				map_Target_Candidates[u.get()].reserve(5);

	vector<MyUnit *> Candidates;
	for (MyUnit * u : me().Units())
		if (u->Completed())
			if ( ((u->Is(Terran_Vulture) || u->Is(Terran_Wraith))
					&& (u->GetBehavior()->IsKiting() || u->GetBehavior()->IsRaiding() || u->GetBehavior()->IsRepairing()))
				||(u->Is(Terran_Siege_Tank_Siege_Mode)
					&& (u->GetBehavior()->IsSieging() && (u->GetBehavior()->IsSieging()->State() != Sieging::unsieging)))
				)
				if (u->Is(Terran_Siege_Tank_Siege_Mode) || (u->NotFiringFor() > 2*u->AvgCoolDown()))
					Candidates.push_back(u);

	for (MyUnit * u : Candidates)
		for (auto & tc : map_Target_Candidates)
		{
			if (u->Is(Terran_Siege_Tank_Siege_Mode))
			{
				if (!dynamic_cast<const My<Terran_Siege_Tank_Tank_Mode> *>(u)->CanSiegeAttack(tc.first))
					continue;
			}
			else
			{
				if (FaceOff(u, tc.first).DistanceToMyRange() >
					(u->Is(Terran_Vulture) || u->Is(Terran_Wraith) ? 10*32 : 5*32))
					continue;
			}

			if (u->Flying() || (groundDist(u->Pos(), tc.first->Pos()) < 15*32))
				tc.second.push_back(u);
		}

	for (const auto & tc : map_Target_Candidates)
	{
#if DEV
		for (int i = 0 ; i < (int)tc.second.size() ; ++i)
		{
			bw->drawBoxMap(tc.first->Pos()-(30+2*i), tc.first->Pos()+(30+2*i), Colors::Yellow);
			bw->drawLineMap(tc.second[i]->Pos(), tc.first->Pos(), Colors::Yellow);
		}
#endif

		if ((tc.second.size() >= 5) ||
			((tc.second.size() >= 3) && (any_of(tc.second.begin(), tc.second.end(), [](const MyUnit * u)
												{ return u->Is(Terran_Siege_Tank_Siege_Mode) || u->Is(Terran_Wraith); }))))
			{
				pBestComsat->Scan(tc.first->Pos());
				sScanLastTime = ai()->Frame();
				return;
			}

	}
}




} // namespace iron



