//SquadAction > SquadManager > Squad > Controller

package edu.berkeley.nlp.starcraft.micro;

import java.util.Random;
import java.util.Set;

import org.apache.log4j.Logger;
import org.bwapi.proxy.model.Color;
import org.bwapi.proxy.model.Game;
import org.bwapi.proxy.model.Position;
import org.bwapi.proxy.model.Unit;

import edu.berkeley.nlp.starcraft.OvermindUnit;
import edu.berkeley.nlp.starcraft.overmind.Underling;
import edu.berkeley.nlp.starcraft.util.Log;

public class ZerglingController  implements Underling {

	private Log logger = Log.getLog("zerglings");
	private final static int REFRESH_RATE = 2;

	private final int randomOffset = new Random().nextInt(REFRESH_RATE);

	public final OvermindUnit unit;
	
	public boolean checkPosition = false;
	public Position lastOrder = null;
	
	public ZerglingController(OvermindUnit unit) {
		this.unit = unit;
	}
	
	public boolean isMoving;
	public Position movePosition;
	
	public boolean isAttacking;
	public boolean keepAttacking;
	public Unit targetEnemyUnit;
	
	public boolean isIdling;
	
	public void setTarget (Unit u)
	{
		targetEnemyUnit = u;
	}
	
	public void setToMoving(Position p)
	{
		movePosition = p;
		isMoving = true;
		isAttacking = false;
		keepAttacking = false;
		isIdling = false;
	}
	
	
	//attack a location
	//the code here is extremely awkward, we need to "leave the zergling alone"
	//because if we keep spamming atk move the zergling freezes up.
	//as a result we need to be convulluted ...
	public void setToAttackPosition(Position p)
	{
		movePosition = p;
		isMoving = false;
		isAttacking = true;
		isIdling = false;
	}
	
	public void setToIdle()
	{
		isMoving = false;
		isAttacking = false;
		keepAttacking = false;
		isIdling = true;
	}
	
	public boolean actionTime(int frameNum)
	{
		return (frameNum % REFRESH_RATE) - randomOffset == 0 ;
	}
	
	@Override
	public void onFrame(int frameNum) {
		if (actionTime(frameNum))
		{
			if (isMoving) 
			{
				unit.rightClick(movePosition);
				return;
			}
			
			if (isAttacking && !keepAttacking)
			{
				//Game.getInstance().printf("RARWARWARARAR!!");
				keepAttacking = true;
				unit.attackMove(movePosition);
				return;
			}
			
			if (unit.isIdle() || unit.getPosition().getDistance(movePosition) > unit.getType().seekRange())
			{
				//Game.getInstance().printf("idling");
				setToIdle();
			}
		}
	}
	
	public static Unit findClosestDangerousEnemyForScout(Position selfPosition, Set<Unit> targetSet, Set<Unit> hiddenSet)
	{
		double minDistance = Double.MAX_VALUE;
		Unit bestTarget = null;
		if (targetSet.size() > 0)
		{
			for (Unit e : targetSet) 
			{
				if (!e.getType().groundWeapon().targetsGround() || e.getType().isWorker() || e.isBeingConstructed() || e.isUnpowered()) 
					{
						continue;
					}
				double d = e.getDistance(selfPosition) - e.getType().groundWeapon().maxRange();
				if (d < minDistance) {
					minDistance = d;
					bestTarget = e;
				}
				Game.getInstance().drawCircleMap(e.getPosition().x(), e.getPosition().y(), e.getType().groundWeapon().maxRange(), Color.BLUE, false);
			}
		}
		if (targetSet.size() == 0)
		{
			for (Unit e : hiddenSet) 
			{
				if (!e.getType().groundWeapon().targetsGround()) 
					{
						continue;
					}
				double d = e.getDistance(selfPosition) - e.getType().groundWeapon().maxRange();
				if (d < minDistance) {
					minDistance = d;
					bestTarget = e;
				}
				Game.getInstance().drawCircleMap(e.getPosition().x(), e.getPosition().y(), e.getType().groundWeapon().maxRange(), Color.BLUE, false);
			}
		}
		return bestTarget;
	}
	
	//finds the closest thing that can kill you
	public Unit findClosestDangerousEnemy(Position selfPosition, Set<Unit> targetSet, Set<Unit> hiddenSet) {
		double minDistance = Double.MAX_VALUE;
		Unit bestTarget = null;
		if (targetSet.size() > 0)
		{
			for (Unit e : targetSet) 
			{
				if (!e.getType().groundWeapon().targetsGround() || e.getType().isWorker() || e.isBeingConstructed() || e.isUnpowered()) 
					{
						continue;
					}
				double d = e.getDistance(selfPosition) - e.getType().groundWeapon().maxRange();
				if (d < minDistance) {
					minDistance = d;
					bestTarget = e;
				}
				Game.getInstance().drawCircleMap(e.getPosition().x(), e.getPosition().y(), e.getType().groundWeapon().maxRange(), Color.BLUE, false);
			}
		}
		if (targetSet.size() == 0)
		{
			for (Unit e : hiddenSet) 
			{
				if (!e.getType().groundWeapon().targetsGround()) 
					{
						continue;
					}
				double d = e.getDistance(selfPosition) - e.getType().groundWeapon().maxRange();
				if (d < minDistance) {
					minDistance = d;
					bestTarget = e;
				}
				Game.getInstance().drawCircleMap(e.getPosition().x(), e.getPosition().y(), e.getType().groundWeapon().maxRange(), Color.BLUE, false);
			}
		}
		return bestTarget;
	}
	
	//find the closest friendly unit in that set
	public OvermindUnit findClosestFriend(OvermindUnit myself, Set<OvermindUnit> targetSet) {
		double minDistance = Double.MAX_VALUE;
		OvermindUnit bestTarget = null;
		Position selfPosition = myself.getPosition();
		for (OvermindUnit e : targetSet) 
		{
			if (e != myself)
			{
				double d = e.getDistance(selfPosition);
				if (d < minDistance && d > 0) 
				{
					minDistance = d;
					bestTarget = e;
				}
			}
		}
		Game.getInstance().drawLineMap(selfPosition.x(), selfPosition.y(), bestTarget.getPosition().x(), bestTarget.getPosition().y(), Color.PURPLE);
		return bestTarget;
	}
	
	//finds the closest thing that you can kill
	public Unit findClosestTargetEnemy(Position selfPosition, Set<Unit> targetSet) {
		double minDistance = Double.MAX_VALUE;
		Unit bestTarget = null;
		for (Unit e : targetSet) {
			if (!e.getType().isFlyer())
			{
				double d = e.getDistance(selfPosition);
				if (d < minDistance) {
					minDistance = d;
					bestTarget = e;
				}
			}
		}
		return bestTarget;
	}
	
	public static Unit findClosestTargetEnemyPrioritizeProbe_public(Position selfPosition, Set<Unit> targetSet)
	{
		double minDistance = Double.MAX_VALUE;
		Unit bestTarget = null;
		for (Unit e : targetSet) {
			if (!e.getType().isFlyer())
			{
				double d = e.getDistance(selfPosition);
				//prioritize worker
				if (e.getType().isWorker() && (bestTarget == null || !bestTarget.getType().isWorker()))
				{
					minDistance = d;
					bestTarget = e;
				}
				//if both worker, distance counts
				else if (e.getType().isWorker() && bestTarget.getType().isWorker() && d < minDistance)
				{
					minDistance = d;
					bestTarget = e;
				}
				//all else fails, get closest dude
				else if (d < minDistance) 
				{
					minDistance = d;
					bestTarget = e;
				}
			}
		}
		return bestTarget;
	}
	
	//finds the closest thing that you can kill
	public Unit findClosestTargetEnemyPrioritizeProbe(Position selfPosition, Set<Unit> targetSet) {
		double minDistance = Double.MAX_VALUE;
		Unit bestTarget = null;
		for (Unit e : targetSet) {
			if (!e.getType().isFlyer())
			{
				double d = e.getDistance(selfPosition);
				//prioritize worker
				if (e.getType().isWorker() && (bestTarget == null || !bestTarget.getType().isWorker()))
				{
					minDistance = d;
					bestTarget = e;
				}
				//if both worker, distance counts
				else if (e.getType().isWorker() && bestTarget.getType().isWorker() && d < minDistance)
				{
					minDistance = d;
					bestTarget = e;
				}
				//all else fails, get closest dude
				else if (d < minDistance) 
				{
					minDistance = d;
					bestTarget = e;
				}
			}
		}
		return bestTarget;
	}
}

