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

import com.tyr.DebugMessages;
import com.tyr.Tyr;
import com.tyr.agents.Agent;
import com.tyr.agents.WorkerAgent;

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


/**
 * This class manages the mining workers for a specific mineral patch.
 * @author Simon
 *
 */
public class PatchWorkers extends UnitGroup
{
	/**
	 * The base where the workers will return the minerals.
	 */
	public Unit resourceDepot;
	
	/**
	 * The minerals close to the base from which we will mine.
	 */
	public Unit mineral;
	
	/**
	 * This class manages the mining workers for a specific mineral patch. 
	 * @param rejects OutOfJob object to which all units are sent that are no longer used.
	 * @param resourceDepot The base where the workers will return the minerals.
	 * @param mineral The minerals close to the base from which we will mine.
	 */
	public PatchWorkers(OutOfJob rejects, Unit resourceDepot, Unit mineral) 
	{
		super(rejects);
		this.resourceDepot = resourceDepot;
		this.mineral = mineral;
	}

	@Override
	public void onFrame(Game game, Player self, Tyr bot)
	{
		if (mineral == null)
		{
			DebugMessages.addMessage("Mineral is null for PatchWorker!");
			return;
		}
		if (!mineral.exists())
		{
			DebugMessages.addMessage("Mineral does not exist for PatchWorker!");
			mineral = null;
			for (Agent agent : units)
				rejects.add(agent);
			units = new ArrayList<Agent>();
			return;
		}
		
		Tyr.drawCircle(mineral.getPosition(), Color.Teal, 16);
		
		// If a unit is not mining minerals, send it to work.
		for(Agent worker : units)
		{
			worker.drawCircle(Color.Cyan);
			if(worker.unit.isIdle() || worker.unit.isGatheringGas())
			{
				worker.unit.gather(mineral);
				return;
			}
			Unit target = worker.unit.getTarget();
			if (worker.unit.isGatheringMinerals() && target != null && target.getType().isMineralField() && target.getID() != mineral.getID())
			{
				worker.drawCircle(Color.White, 4);
				worker.unit.gather(mineral);
			}
		}
	}
	
	@Override
	public Agent pop()
	{
		for(int i=units.size()-1; i>= 0; i--)
		{
			if (!((WorkerAgent)units.get(i)).isBlocked 
					&& !units.get(i).unit.isConstructing() 
					&& units.get(i).distanceSquared(resourceDepot.getPosition()) <= 1152*1152
					&& units.get(i).unit.getOrder() != Order.ConstructingBuilding)
			{
				Agent result = units.get(i);
				remove(i);
				return result;
			}
		}
		return null;
	}
	
	/**
	 * Removes an agent from this unit group and returns it.
	 * @param pos The worker closest to this position will be returned.
	 * @return The removed agent. This may be null if no agent is available.
	 *		   This does not necessarily mean that this unit group contains no more agents.
	 */
	public Agent pop(Position pos) 
	{
		Agent result = null;
		double distance = Double.MAX_VALUE;
		for(Agent worker : units)
		{
			if (((WorkerAgent)worker).isBlocked || worker.unit.isConstructing())
				continue;
			
			int newDist = worker.distanceSquared(pos);
			if(newDist < distance)
			{
				distance = newDist;
				result = worker;
			}
		}
		units.remove(result);
		return result;
	}

	@Override
	public void add(Agent agent)
	{
		if (agent == null)
			return;
		if(agent.unit == null)
			return;
		super.add(agent);

		if(agent.unit.isConstructing())
			return;
		
		if(mineral != null)
			agent.unit.gather(mineral);
	}
	
	@Override
	public void cleanup()
	{
		super.cleanup();
		
		if (mineral == null || !mineral.exists() || mineral.getResources() <= 0)
			mineral = null;
		
		if (mineral == null)
		{
			for(Agent unit : units)
				rejects.add(unit);
			units = new ArrayList<Agent>();
		}
	}
}
