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

import java.util.ArrayList;
import java.util.List;

import com.tyr.BWTAProxy;
import com.tyr.EnemyManager;
import com.tyr.Tyr;
import com.tyr.unitgroups.MineralWorkers;

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


/**
 * This is an agent for managing a wraith.
 * @author Simon
 *
 */
public class WraithAgent extends Agent
{
	/**
	 * The position of the current target in the list of expands, prepended with the list of suspected enemy bases. 
	 */
	public int current = -1;
	
	/**
	 * The target location we are currently attacking.
	 */
	private Position target = null;
	
	/**
	 * The state this agent is currently in.
	 */
	private int state = AttackState;
	
	/**
	 * The attacking state.
	 */
	private static final int AttackState = 0;
	
	/**
	 * The fleeing state.
	 */
	private static final int FleeState = 1;
	
	private int dir = 1;
	
	private static ArrayList<Position> orderedExpands;
	
	/**
	 * The next enemy we intend to kill.
	 */
	private Unit killEnemy;
	
	
	/**
	 * This is an agent for managing a wraith.
	 * @param wraith The wraith that will be managed.
	 */
	public WraithAgent(Unit wraith)
	{
		super(wraith);
	}
	
	@SuppressWarnings("unchecked")
	public void onFrame(Game game, Player self, Tyr bot)
	{
		if (!BWTAProxy.initialized)
			return;
		
		if (current == -1)
			current = EnemyManager.getManager().getSelfPos();
		
		if (orderedExpands == null || orderedExpands.size() == 0)
		{
			orderedExpands = (ArrayList<Position>)EnemyManager.getManager().getOrderedExpands().clone();
			if (bot.suspectedEnemy.size() == 1)
				orderedExpands.add(bot.suspectedEnemy.get(0).getPosition());
		}
		
		List<Unit> inRange = game.getUnitsInRadius(unit.getPosition(), UnitType.Terran_Wraith.sightRange()*2);
		
		//See if there is an enemy closeby.
		Unit closestEnemy = null;
		double closestDistance = UnitType.Terran_Wraith.sightRange() + 100;
		for(Unit enemy: inRange)
		{
			if(enemy.getPlayer() == self)
				continue;
			
			// We do not worry about enemies who cannot attack the wraith.
			if(enemy.getType().airWeapon() == WeaponType.None)
				continue;
			
			double dist = unit.getDistance(enemy);
			if (dist < closestDistance)
			{
				closestDistance = dist;
				closestEnemy = enemy;
			}
		}
		
		if (closestEnemy != null && self.hasResearched(TechType.Cloaking_Field) && !unit.isCloaked())
		{
			unit.useTech(TechType.Cloaking_Field);
			closestEnemy = null;
		}
		
		if (closestEnemy == null || unit.isCloaked())
		{
			// There is no enemy close, so we can continue the attack.
			if (state != AttackState)
			{
				state = AttackState;

				// We will attack the previous base, in case the unit we previously fled from is still in the direction of the current target.
				dir *= -1;
				current+=dir;

				if (current >= orderedExpands.size())
					current = 0;
				if (current < 0)
					current += orderedExpands.size();
			}
			
			if (killEnemy != null && killEnemy.getHitPoints() > 0 && killEnemy.getRemoveTimer() == 0 && killEnemy.exists() && killEnemy.getPlayer() != Tyr.game.self())
			{
				if (this.unit.isIdle())
					attack(killEnemy);
				game.drawLineMap(unit.getX(), unit.getY(), killEnemy.getX(), killEnemy.getY(), Color.Red);
				return;
			}
			else
				killEnemy = null;
			for (Unit enemy : EnemyManager.getEnemyUnits())
			{
				if (enemy.getType().isWorker() && distanceSquared(enemy) < 320*320)
				{
					killEnemy = enemy;
					attack(enemy);
					game.drawLineMap(unit.getX(), unit.getY(), killEnemy.getX(), killEnemy.getY(), Color.Red);
					return;
				}
			}
			
			if(unit.isIdle() || distanceSquared(target) <= 10000)
			{
				while(true)
				{
					// Find a new target to attack.
					current+=dir;
					if (current >= orderedExpands.size())
						current = 0;
					if (current < 0)
						current += orderedExpands.size();
					Position newTarget = orderedExpands.get(current);
					
					// Check if we already have a base at the target.
					boolean myBase = false;
					for(MineralWorkers base : bot.workForce.mineralWorkers)
					{
						if (base.resourceDepot.getPosition().getDistance(newTarget) <= 128)
						{
							myBase = true;
							break;
						}
					}
					
					if (myBase)
						continue;
					
					target = newTarget;
					break;
				}
				
				unit.move(target);
			}
		}
		else
		{
			// There is an enemy close, so we flee.
			state = FleeState;
			
			// Determine where we will flee to.
			Position fleeTarget = retreatTarget(closestEnemy.getPosition(), 256);
			
			unit.move(fleeTarget);
			
			game.drawLineMap(closestEnemy.getX(), closestEnemy.getY(), fleeTarget.getX(), fleeTarget.getY(), Color.Red);
		}
	}
}
