/*
* 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 java.util.ArrayList;

import com.tyr.BWTAProxy;
import com.tyr.EnemyManager;
import com.tyr.Tyr;
import com.tyr.agents.Agent;
import com.tyr.agents.None;
import com.tyr.buildingplacement.SpaceManager;
import com.tyr.unitgroups.AttackGroup;
import com.tyr.unitgroups.UnitGroup;

import bwapi.Color;
import bwapi.Game;
import bwapi.Player;
import bwapi.Position;

/**
 * This class implements a solution for defending using wraiths.
 */
public class WraithDefenseSolution extends Solution
{
	/**
	 *  The group of attacking units.
	 */
	private AttackGroup attackGroup;
	
	/**
	 *  The target of the attack.
	 */
	private Position attackTarget;
	
	/**
	 * The position at which we want to regroup.
	 */
	private Position defendTarget;
	
	/**
	 * The attacking state.
	 */
	private final int ATTACK = 1;

	/**
	 * The defending state.
	 */
	private final int DEFEND = 2;

	/**
	 * The state the object is currently in.
	 */
	private int phase = ATTACK;
	
	
	
	/**
	 * This class implements a solution for defending using wraiths.
	 * @param task The task that started this solution.
	 */
	public WraithDefenseSolution(Task task) 
	{
		super(task);
		
		this.attackGroup = new AttackGroup(attackTarget);
	}

	@Override
	public void onFrame(Game game, Player self, Tyr bot)
	{
		if (!BWTAProxy.initialized)
			return;
		if (defendTarget == null)
			defendTarget = SpaceManager.getNatural();

		if (attackTarget == null && defendTarget != null)
		{
			ArrayList<Position> expands = EnemyManager.getManager().getOrderedExpands();
			if (expands == null)
				return;
			int selfPos = EnemyManager.getManager().getSelfPos();
			
			int defendPos = 0;
			for (;defendPos < expands.size();defendPos++)
				if (expands.get(defendPos).getDistance(defendTarget) < 100)
					break;
			
			int attackPos;
			if (defendPos > selfPos)
				attackPos = (defendPos + 1) % expands.size();
			else
				attackPos = (defendPos - 1 + expands.size()) % expands.size();
			attackTarget = expands.get(attackPos);
		}
		
		if (attackTarget == null || defendTarget == null)
			return;

		// Draw some debug info.
		Tyr.drawCircle(phase == ATTACK? attackTarget:defendTarget, phase == ATTACK?Color.Orange:Color.Green, 64);
		
		if (this.size() == 0)
			return;
		
		// Determine whether we are in the attacking or regrouping phase.
		determinePhase();

		// Manage the attackGroup.
		attackGroup.cleanup();
		attackGroup.setTarget(phase == ATTACK?attackTarget:defendTarget);
		attackGroup.onFrame(game, self, bot);
	}
	
	/**
	 * This method is called at the start of each frame.
	 * It determines when the phase changes.
	 */
	private void determinePhase()
	{
		if(phase == DEFEND)
		{
			for (Agent agent : attackGroup.units)
				if (agent.distanceSquared(defendTarget) > 200*200)
					return;
			phase = ATTACK;
		}
		else
		{
			for (Agent agent : attackGroup.units)
				if (agent.distanceSquared(attackTarget) > 200*200)
					return;
			phase = DEFEND;
		}
	}
	
	/**
	 * Add an agent to the attack group with the attacking agents.
	 * @param unit The agent to be added.
	 */
	public void add(Agent agent)
	{
		attackGroup.add(agent);
	}
	
	/**
	 * This method is called when this solution is no longer needed.
	 */
	public void done(UnitGroup unitGroup) 
	{
		for(Agent unit : attackGroup.units)
		{
			unitGroup.add(unit);
			unit.order(new None(unit));
		}
		attackGroup.units = new ArrayList<Agent>();
	}
	
	/**
	 * Clears the solution so that it can be removed.
	 */
	public void clear() 
	{
		attackGroup.clear();
	}

	/**
	 * Returns the number if agents sent out by this solution.
	 * @return Returns the number if agents sent out by this solution.
	 */
	public int size() 
	{
		return attackGroup.units.size();
	}
}
