/*
* 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.Tyr;
import com.tyr.agents.Agent;
import com.tyr.agents.None;

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

/**
 * This class implements a solution for clearing a blocking mineral patch.
 */
public class ClearMineralSolution extends Solution 
{
	/**
	 * The position of the mineral patch we want to clear.
	 */
	private Position clearMineralPos;
	
	/**
	 * The worker who will clear the patch.
	 */
	private Agent worker;
	
	/**
	 * Are we finished removing the mineral patch?
	 */
	public boolean finished;
	
	/**
	 * This class implements a solution for clearing a blocking mineral patch.
	 * @param task The calling task.
	 * @param pos The position of the mineral we want to clear.
	 */
	public ClearMineralSolution(Task task, Position pos) 
	{
		super(task);
		clearMineralPos = pos;
	}
	
	@Override
	public void onFrame(Game game, Player self, Tyr bot)
	{
		if (worker != null && worker.isDead())
			worker = null;
		
		if (worker == null || finished)
			return;
		
		worker.drawCircle(Color.White);
		game.drawTextMap(worker.unit.getX(), worker.unit.getY(), worker.unit.getOrder().toString());
		
		int distanceSq = worker.distanceSquared(clearMineralPos);
		
		// Try to find the mineral patch.
		Unit mineral = null;
		if (distanceSq <= 64*64)
		{
			// See if the mineral pach is mined out.
			mineral = getMineral();
			if (mineral == null)
			{
				finished = true;
				return;
			}
		}
		
		// If the worker is still carrying minerals, it needs to return those first.
		if (worker.unit.isCarryingMinerals())
		{
			if (!worker.unit.getOrder().equals(Order.ReturnMinerals))
				worker.unit.returnCargo();
			return;
		}
		
		// Order the unit to move towards the minerals.
		if (distanceSq > 64*64)
		{
			worker.unit.move(clearMineralPos);
			worker.drawCircle(Color.Red, 6);
			return;
		}
		
		// Order the unit to gather from the minerals.
		worker.drawCircle(Color.Green, 6);
		if (worker.unit.isIdle() || worker.unit.getOrder() == Order.Move)
			worker.unit.gather(mineral);
	}
	
	/**
	 * Get the blocking mineral.
	 * @return Gets the blocking mineral, or null if the mineral is mined out or not visible.
	 */
	private Unit getMineral() 
	{
		for(Unit mineral : Tyr.game.neutral().getUnits())
		{
			if (!mineral.getType().isMineralField())
				continue;
			
			if (mineral.getResources() > 0)
				continue;
			
			if (mineral.getDistance(clearMineralPos) > 48)
				continue;
			
			return mineral;
		}
		
		return null;
	}

	/**
	 * Set the current worker.
	 * @param worker The worker who will clear the mineral patch.
	 */
	public void setWorker(Agent worker)
	{
		this.worker = worker;
	}
	
	/**
	 * Returns the current worker and removes it from this solution.
	 * @return The current worker or null if no worker is present.
	 */
	public Agent pop()
	{
		Agent result = worker;
		worker = null;
		if (result != null)
			result.order(new None(result));
		return result;
	}
	
	/**
	 * Returns true if a worker is needed.
	 * @return Returns true if a worker is needed.
	 */
	public boolean workerNeeded()
	{
		return worker == null;
	}

	/**
	 * The position of the mineral field we wish to clear.
	 * @return The position of the mineral field we wish to clear.
	 */
	public Position getPosition()
	{
		return clearMineralPos;
	}
}
