/*
* 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.unitgroups;

import com.tyr.BWTAProxy;
import com.tyr.DebugMessages;
import com.tyr.Settings;
import com.tyr.Tyr;
import com.tyr.agents.Agent;
import com.tyr.buildingplacement.DefensiveStructures;
import com.tyr.buildingplacement.SpaceManager;

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

/**
 * This UnitGroup contains all offensive units that are not currently supposed to attack
 *  and that are nor supposed to defend a base.
 */
public class HomeGroup extends UnitGroup
{
	/**
	 * The target position where all idle units are to be gathered.
	 */
	public Position target = null;
	
	/**
	 * The defensive structures where we want to place our defending units.
	 */
	private DefensiveStructures defenses = null;
	
	/**
	 * Do we keep siege tanks sieged when there is no enemy nearby.
	 */
	public static boolean keepTanksSieged = false;
	
	/**
	 * The position of our natural expand.
	 */
	private Position natural;
	
	/**
	 * Do we always put our defending units at the natural expand?
	 */
	public static boolean defendAtNatural;

	public HomeGroup(OutOfJob rejects)
	{
		super(rejects);
	}

	@Override
	public void onFrame(Game game, Player self, Tyr bot) 
	{
		DebugMessages.addMessage("HomeGroup size: " + units.size());
		
		// At the start of the game, we gather our defences at the main.
		if (bot.defensiveStructures.size() > 0)
			defenses = bot.defensiveStructures.get(0);
		
		// Once we expand to the natural, we gather our defences there.
		if (bot.defensiveStructures.size() > 1)
		{
			if (natural == null)
				natural = SpaceManager.getNatural();
			if (natural != null)
			{
				for (DefensiveStructures structures : bot.defensiveStructures)
				{
					if (structures.defendedPosition.getDistance(natural) < 100)
					{
						defenses = structures;
						break;
					}
				}
			}
		}
			
		
		// Update the target.
		if (defendAtNatural && BWTAProxy.initialized)
		{
			if (game.mapFileName().contains("Alchemist"))
			{
				if (Tyr.bot.workForce.mineralWorkers.size() > 1)
					target = Tyr.bot.workForce.mineralWorkers.get(1).defensePos;
			}
			else
			{
				if (natural == null)
					natural = SpaceManager.getNatural();
				target = SpaceManager.getDefensePos(natural);
			}
		}
		else if(Settings.getRallyPoint() != null)
			target = Settings.getRallyPoint();
		else if (defenses != null && defenses.defences.size() > 0 
				&& defenses.defences.get(0).getPosition() != null)
			target = defenses.defences.get(0).getPosition();
		else if (BWTAProxy.initialized && defenses != null)
			target = defenses.getDefensePos();
		
		// Send all units to the target.
		if (target != null)
		{
			Tyr.drawCircle(target, Color.Green, 128);
			for(Agent agent : units)
			{
				if (agent.unit.getScarabCount() < 5 && agent.unit.getType() == UnitType.Protoss_Reaver && !agent.unit.isTraining())
					agent.unit.train(UnitType.Protoss_Scarab);
				else if (agent.unit.getType() == UnitType.Protoss_Carrier && !agent.unit.isTraining() && agent.unit.getInterceptorCount() < 8)
					agent.unit.train(UnitType.Protoss_Interceptor);
				
				else if (agent.unit.getType() == UnitType.Terran_Siege_Tank_Tank_Mode)
				{
					if (keepTanksSieged && agent.distanceSquared(target) <= 128*128)
						agent.unit.siege();
					else
						agent.drawCircle(Color.Yellow, 4);
				}
				else if (agent.unit.getType() == UnitType.Terran_Siege_Tank_Siege_Mode)
				{
					if (!keepTanksSieged || agent.distanceSquared(target) > 128*128)
						agent.unit.unsiege();
				}
				else if (agent.distanceSquared(target) > 128*128)
					agent.unit.move(target);
				agent.drawCircle(Color.Grey);
			}
		}
		
	}
	
	@Override
	public void add(Agent agent)
	{
		// The unit should stop whatever it is doing and go do nothing at the target location.
		if (target != null)
			agent.unit.move(target);
		
		// We still have to add the agent as normal.
		super.add(agent);
	}
	
	/**
	 * Removes an agent from the unit group and returns it.
	 * @param type The type of unit to remove.
	 * @return The removed agent.
	 */
	public Agent pop(UnitType type) 
	{
		for(int i = units.size()-1; i>=0; i--)
		{
			Agent agent = units.get(i);
			if (agent.unit.getType() == type)
			{
				units.remove(i);
				return agent;
			}
		}
		return null;
	}
	
	/**
	 * Adds tanks to a UnitGroup.
	 * @param tanks The UnitGroup to which the tanks are to be added.
	 * @param amount The maximum number of tanks that should be added.
	 */
	public void addTanks(UnitGroup tanks, int amount)
	{
		for(int i = units.size()-1; i >= 0 && amount > 0; i--)
		{
			Agent agent = units.get(i);
			if (agent.unit.getType() == UnitType.Terran_Siege_Tank_Siege_Mode
					|| agent.unit.getType() == UnitType.Terran_Siege_Tank_Tank_Mode)
			{
				tanks.add(agent);
				units.remove(i);
				amount--;
			}
		}
	}
	
	@Override 
	public int takeAgent(Agent agent)
	{
		if (agent.unit.getType() == UnitType.Terran_Medic 
				|| agent.unit.getType() == UnitType.Terran_Science_Vessel 
				|| agent.unit.getType() == UnitType.Terran_Dropship
				|| agent.unit.getType() == UnitType.Protoss_Observer
				|| agent.unit.getType() == UnitType.Protoss_High_Templar
				|| agent.unit.getType() == UnitType.Protoss_Reaver
				|| agent.unit.getType() == UnitType.Protoss_Shuttle)
			return 1;
		if (agent.unit.getType() == UnitType.Protoss_Scarab
				|| agent.unit.getType() == UnitType.Protoss_Interceptor)
			return -1;
		if (agent.unit.getType().canAttack() 
    			&& ! agent.unit.getType().isWorker() 
    			&& !agent.unit.getType().isBuilding() 
    			&& agent.unit.isCompleted()
    			&& agent.unit.getType() != UnitType.Terran_Vulture_Spider_Mine)
			return 1;
		else 
			return -1;
	}
	
	/**
	 * The target position where all idle units are to be gathered.
	 * @return The target position where all idle units are to be gathered.
	 */
	public Position getTarget()
	{
		return target;
	}
}
