/*
* Tyr is an AI for StarCraft: Broodwar, 
* 
* Please visit https://github.com/SimonPrins/Tyr for further information.
* 
* Copyright 2015 Simon Prins
*
* This file is part of Tyr.
* Tyr is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
* Tyr is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with Tyr.  If not, see http://www.gnu.org/licenses/.
*/


package com.tyr.tasks;

import com.tyr.BWTAProxy;
import com.tyr.EnemyManager;
import com.tyr.EnemyPosition;
import com.tyr.PositionUtil;
import com.tyr.Settings;
import com.tyr.Tyr;
import com.tyr.agents.Agent;

import bwapi.Color;
import bwapi.Game;
import bwapi.Player;
import bwapi.Position;
import bwapi.Race;
import bwapi.Unit;
import bwapi.UnitType;
import bwta.Region;


/**
 * A task that determines whether our main base needs defending and if so will try to defend it.
 */
public class CannonDefenseTask extends Task
{
	/**
	 * Invading enemy worker which needs to be checked.
	 */
	private Unit invader;
	
	/**
	 * The location we will attack.
	 */
	private Position target;
	
	private Region homeRegion = null;

	boolean proxied;
	
	boolean cannonsBuilt;
	
	boolean workerRush = false;
	
	@Override
	public boolean isRequired(Game game, Player self, Tyr bot) 
	{
		return game.enemy().getRace() == Race.Protoss;
	}

	@Override
	public void solve(Game game, Player self, Tyr bot)
	{
		if (game.getFrameCount() >= 200 && homeRegion == null && BWTAProxy.initialized)
			homeRegion = BWTAProxy.getRegion(self.getStartLocation());
		
		if (homeRegion == null)
			return;
		
		if (!workerRush )
		{
			int count = 0;
			for (Unit unit : EnemyManager.getEnemyUnits())
				if (unit.getType().isWorker()
						&& PositionUtil.distanceSq(unit, Tyr.tileToPosition(self.getStartLocation())) <= Settings.getLargeInvasionDist() * Settings.getLargeInvasionDist())
					count++;
			
			if (count >= 3)
			{
				workerRush = true;
				if (solution != null)
					((SendTroopsSolution)solution).done(bot.hobos);
			}
		}
		
		if (workerRush)
			return;

		proxied = false;
		for (EnemyPosition pos : EnemyManager.getManager().enemyBuildingMemory)
			if (pos.pos != null && game.getFrameCount() >= 200 && BWTAProxy.initialized && BWTAProxy.getRegion(pos.pos) == homeRegion)
			{
				proxied = true;
				if (pos.type == UnitType.Protoss_Photon_Cannon)
					cannonsBuilt = true;
			}
		
		if (!cannonsBuilt && proxied)
		{
			for (Unit unit : EnemyManager.getEnemyUnits())
			{
				if (unit.getType() != UnitType.Protoss_Photon_Cannon)
					continue;
				if (!unit.isCompleted())
					continue;
				if (!unit.isPowered())
					continue;
				if (BWTAProxy.getRegion(unit.getPosition()) != homeRegion)
					continue;
				proxied = true;
				break;
			}
		}
				
		if (proxied
				|| (EnemyManager.getManager().getInvader() != null && !EnemyManager.getManager().getInvader().getType().isWorker()))
		{
			if (!cannonsBuilt)
			{
				if (invader != null && invader.getType() == UnitType.Protoss_Probe)
				{
					invader = null;
					target = null;
				}
				if (invader == null)
				{
					for (EnemyPosition pos : EnemyManager.getManager().enemyBuildingMemory)
					{
						if (BWTAProxy.getRegion(pos.pos) != homeRegion)
							continue;
						invader = null;
						target = pos.pos;
						break;
					}
				}
			}
			if (target != null)
			{
				for (Agent agent = bot.workForce.pop(); agent != null; agent = bot.workForce.pop())
					((SendTroopsSolution)solution).add(agent);
					
				// We set the position where we want the units to defend.
				((SendTroopsSolution)solution).setTarget(target);
				
				// We call the super class, which will send the units out to defend.
				super.solve(game, self, bot);
				
				return;
			}
			((SendTroopsSolution)solution).done(bot.hobos);
			invader = null;
			target = null;
			return;
		}
		
		if (invader == null)
		{
			for (Unit enemy : EnemyManager.getEnemyUnits())
			{
				if (!enemy.getType().isWorker())
					continue;
				if (BWTAProxy.getRegion(enemy.getPosition()) != homeRegion)
					continue;
				invader = enemy;
				break;
			}
		}
		if (invader == null)
		{
			target = null;
			((SendTroopsSolution)solution).done(bot.hobos);
			return;
		}
		
		Position newTarget = EnemyManager.getManager().getLastPosition(invader);
		if (newTarget != null)
			target = newTarget;
		else if (target != null && ((SendTroopsSolution)solution).getCount() > 0 && ((SendTroopsSolution)solution).distanceSq(target) <= 32*32)
		{
			invader = null;
			target = null;
			((SendTroopsSolution)solution).done(bot.hobos);
			return;
		}
		
		if (target != null && BWTAProxy.initialized && BWTAProxy.getRegion(target) != homeRegion)
		{
			invader = null;
			target = null;
			((SendTroopsSolution)solution).done(bot.hobos);
			return;
		}
		
		Tyr.drawCircle(target, Color.Red);
		
		if (((SendTroopsSolution)solution).getCount() == 0)
		{
			Agent defender = bot.workForce.pop(target);
			if (defender == null)
				return;
			((SendTroopsSolution)solution).add(defender);
		}
		
		// We set the position where we want the units to defend.
		((SendTroopsSolution)solution).setTarget(target);
		
		// We call the super class, which will send the units out to defend.
		super.solve(game, self, bot);
	}

	@Override
	public void findSolution(Game game, Player self, Tyr bot)
	{
		solution = new SendTroopsSolution(this, target);
	}
}
