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

import java.util.ArrayList;

import com.tyr.BWTAProxy;
import com.tyr.Settings;
import com.tyr.Tyr;
import com.tyr.agents.Agent;
import com.tyr.agents.BunkerAgent;
import com.tyr.unitgroups.TankDefense;

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


/**
 * Keeps track of all the structures defending a specific base. 
 * @author Simon
 *
 */
public class DefensiveStructures
{
	/**
	 * The position of the base we are trying to defend.
	 */
	public Position defendedPosition;
	
	/**
	 * The position where the defences are to be placed.
	 */
	private Position defensePos;
	
	/**
	 * List of all the actual structures defending the base.
	 */
	public ArrayList<Unit> defences = new ArrayList<Unit>();
	
	/**
	 * If this is set to true, the base is considered too far to actually defend.
	 * The defending structures will not be managed.
	 */
	public boolean tooFar = false;
	
	/**
	 * Have the defences been disabled?
	 */
	public boolean disabled = false;
	
	/**
	 * The tanks defending the base.
	 */
	public TankDefense tanks;
	
	/**
	 * Keeps track of all the structures defending a specific base.
	 * @param defendedPosition The position of the base we are trying to defend.
	 * @param defensePos The position where the defences are to be placed.
	 */
	public DefensiveStructures(Position defendedPosition, Position defensePos)
	{
		this.defendedPosition = defendedPosition;
		this.defensePos = defensePos;
		tanks = new TankDefense(Tyr.bot.hobos, defensePos);
		if (BWTAProxy.initialized && Tyr.self != null && defensePos != null)
			tooFar = Tyr.tileToPosition(Tyr.self.getStartLocation()).getDistance(defensePos) > 1200;
	}
	
	/**
	 * Add a structure to the list of defending structures.
	 * @param unit The structure to be added.
	 */
	public void add(Unit unit)
	{
		defences.add(unit);
	}
	
	/**
	 * This method is assumed to be called each frame.
	 * @param game The object representing the state of the game.
	 * @param self The object representing the player.
	 * @param bot The bot.
	 */
	public void onFrame(Game game, Player self, Tyr bot) 
	{		
		if(tanks.units.size() < Settings.getDefensiveTanks())
			bot.homeGroup.addTanks(tanks, Settings.getDefensiveTanks() - tanks.units.size());
		
		tanks.cleanup();
		
		tanks.onFrame(game, self, bot);
		
        for(int i=0; i<defences.size(); i++)
        {
        	if(defences.get(i) == null 
        			|| defences.get(i).getHitPoints() <= 0 
        			|| !defences.get(i).exists() 
        			|| defences.get(i).getRemoveTimer() != 0)
        	{
        		defences.remove(i);
        		i--;
        	}
        }
        
        for(Unit structure : defences)
        {
        	game.drawBoxMap(structure.getTilePosition().getX()*32, structure.getTilePosition().getY()*32,
        			structure.getTilePosition().getX()*32 + structure.getType().tileWidth()*32,
        			structure.getTilePosition().getY()*32 + structure.getType().tileHeight()*32,
        			Color.Orange);
        }
		
	}
	
	/**
	 * Return the number of structures of a specific type for this base.
	 * @param type The type of structure of which we want to know how many there are.
	 * @return The number of structures of a specific type for this base. 
	 */
	public int getUnitCount(UnitType type)
	{
		int count = 0;
		
		for(Unit unit : defences)
			if(unit.getType() == type)
				count++;
		
		for(BuildCommand com : Tyr.bot.buildCommands)
			if(com.building == type && com.position.getDistance(Tyr.positionToTile(defensePos)) < 128)
				count++;
		
		return count;
	}
	
	/**
	 * The position where the defences are to be placed. 
	 * @return The position where the defences are to be placed.
	 */
	public Position getDefensePos() 
	{
		if (BWTAProxy.initialized && defensePos == null)
		{
			defensePos = SpaceManager.getMainExit();
			Position start = Tyr.tileToPosition(Tyr.self.getStartLocation());
			defensePos = new Position((defensePos.getX() + start.getX())/2, 
					(defensePos.getY() + start.getY())/2);
		}
		return defensePos;
	}
	
	/**
	 * Disables the defensive structures.
	 * The structures will no longer be managed.
	 * The bunkers will be disabled as well, so that all units will vacate it and scvs will no longer repair it.
	 */
	public void disable() 
	{
		tanks.disable();
		for(Unit unit : defences)
		{
			if(unit.getType() == UnitType.Terran_Bunker)
			{
				Agent bunker = Tyr.bot.agentMap.get(unit.getID());
				((BunkerAgent)bunker).disabled = true;
			}
		}
		disabled = true;
	}
}
