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

import com.tyr.DebugMessages;
import com.tyr.Settings;
import com.tyr.Tyr;
import com.tyr.UnitTracker;
import com.tyr.agents.Agent;
import com.tyr.agents.Attack;
import com.tyr.buildingplacement.SpaceManager;
import com.tyr.tasks.ClearExpandsTask;
import com.tyr.tasks.ConstantPushTask;
import com.tyr.tasks.DefendMainTask;
import com.tyr.tasks.DragoonSquadTask;
import com.tyr.tasks.LocalDefenseTask;
import com.tyr.unitgroups.DistributeAttackGroup;

import bwapi.Game;
import bwapi.Player;
import bwapi.TechType;
import bwapi.UnitType;
import bwapi.UpgradeType;
import bwta.BWTA;


public class MassRecall extends CompositeBuildOrder
{
	private LocalDefenseTask localDefenseTask;
	private LocalDefenseTask naturalDefenseTask;
	private LocalDefenseTask thirdDefenseTask;
	
	@Override
	public void initialize(Game game, Player self, Tyr bot)
	{
		DefendMainTask.keepZealotsBack = true;
		
		addTask(new DragoonSquadTask());
		
		localDefenseTask = new LocalDefenseTask(BWTA.getRegion(Tyr.getStartLocation()), 0);
		addTask(localDefenseTask);

		naturalDefenseTask = new LocalDefenseTask(null, 0);
		addTask(naturalDefenseTask);
		thirdDefenseTask = new LocalDefenseTask(null, 0);
		addTask(thirdDefenseTask);
		
		DistributeAttackGroup.waitDistance = 800;
		
		Settings.setRequiredSize(100);
		Settings.setMaximumSize(100);
		Settings.setMaximumWorkers(7);
		Settings.setWorkersPerGas(2);
		Settings.setLargeInvasionDist(768);
		ExpandPart.maximumCcs = 2;
		ClearExpandsTask.allowFullAssault = false;

		this.add(new WorkerScoutPart(1600));
		this.add(new ExpandPart(true));
		
		Attack.requiredAtCannon = 0;
		
		ConstantPushTask.prioritizeExpands = true;
		ConstantPushTask.reinforcementSize = 5;
		
		super.initialize(game, self, bot);
	}

	private static int armySize()
	{
		return completed(ZEALOT) + completed(DRAGOON);
	}

	@Override
	public void onFrame(Game game, Player self, Tyr bot) 
	{
		DebugMessages.addMessage("Army size: " + armySize());
		
		if (armySize() >= 16)
		{
			localDefenseTask.setDefendersNeeded(1);
		}

		if (naturalDefenseTask != null && naturalDefenseTask.getDefendersNeeded() == 0 && Tyr.bot.workForce.mineralWorkers.size() >= 2)
		{
			naturalDefenseTask.setDefendersNeeded(2);
			naturalDefenseTask.setDefendedPosition(Tyr.bot.workForce.mineralWorkers.get(1).resourceDepot.getPosition());
		}

		if (thirdDefenseTask != null && thirdDefenseTask.getDefendersNeeded() == 0 && Tyr.bot.workForce.mineralWorkers.size() >= 3)
		{
			thirdDefenseTask.setDefendersNeeded(3);
			thirdDefenseTask.setDefendedPosition(Tyr.bot.workForce.mineralWorkers.get(2).resourceDepot.getPosition());
		}
		
		super.onFrame(game, self, bot);

		if (gas() >= 400)
			Settings.setWorkersPerGas(2);
		else if ((gas() < 250 && count(GATEWAY) >= 12) 
				|| gas() + 400 < minerals())
			Settings.setWorkersPerGas(3);
		
		
		if (count(NEXUS) > 1)
			Settings.setMaximumWorkers(40);
		else if (UnitTracker.count(UnitType.Protoss_Cybernetics_Core) > 0)
			Settings.setMaximumWorkers(30);
		else if (UnitTracker.count(UnitType.Protoss_Gateway) >= 4)
			Settings.setMaximumWorkers(25);
		else if (UnitTracker.count(UnitType.Protoss_Gateway) >= 2)
			Settings.setMaximumWorkers(9);
		if (armySize() >= 2 && UnitTracker.count(UnitType.Protoss_Gateway) < 4)
			Settings.setMaximumWorkers(20);
		
		if (UnitTracker.count(UnitType.Protoss_Probe) >= 7 && UnitTracker.count(UnitType.Protoss_Pylon) == 0 && bot.getAvailableMinerals() >= 100)
		{
			bot.spaceManager.build(UnitType.Protoss_Pylon);
		}

		if (SpaceManager.noPower
				&& minerals() >= 100
				&& count(PYLON) == completed(PYLON))
			bot.spaceManager.build(PYLON);
		
		if (self.completedUnitCount(UnitType.Protoss_Pylon) > 0
				&& bot.getAvailableMinerals() >= 125 
				&& UnitTracker.count(UnitType.Protoss_Gateway) == 0
				&& count(NEXUS) > 1)
		{
			bot.spaceManager.build(UnitType.Protoss_Gateway);
		}
			
		if (UnitTracker.count(UnitType.Protoss_Gateway) == 1 
				&& bot.getAvailableMinerals() >= 100
				&& count(CYBERNETICS_CORE) > 0
				&& count(ASSIMILATOR) > 0
				&& count(NEXUS) > 1)
		{
			bot.spaceManager.build(UnitType.Protoss_Gateway);
		}
		
		if (!pauseProduction())
		{
			if (UnitTracker.count(UnitType.Protoss_Gateway) < 4
					&& bot.getAvailableMinerals() >= 300
					&& UnitTracker.count(UnitType.Protoss_Cybernetics_Core) > 0)
			{
				bot.spaceManager.build(UnitType.Protoss_Gateway);
			}
			
			if (UnitTracker.count(UnitType.Protoss_Gateway) >= 3
					&& UnitTracker.count(UnitType.Protoss_Gateway) < 6
					&& bot.getAvailableMinerals() >= 300
					&& count(ZEALOT) + count(DRAGOON) >= 7)
			{
				bot.spaceManager.build(UnitType.Protoss_Gateway);
			}
		}
		
		//if we're running out of supply and have enough minerals ...
		if ((self.supplyTotal() + UnitTracker.getSupplyConstructing() - self.supplyUsed() 
					<= UnitTracker.count(UnitType.Protoss_Gateway)*3 + UnitTracker.getCcCount() * 3)
				&& (bot.getAvailableMinerals() >= 100)
				&& self.supplyTotal() + UnitTracker.getSupplyConstructing() < 400
				&& UnitTracker.count(UnitType.Protoss_Pylon) >= 1
				&& (armySize() >= 2 || self.supplyTotal() + UnitTracker.getSupplyConstructing() - self.supplyUsed() < 4))
		{
			bot.spaceManager.build(UnitType.Protoss_Pylon);
		}
		
		if(UnitTracker.count(UnitType.Protoss_Assimilator) < 2
				&& bot.getAvailableMinerals() >= 100 
				&& UnitTracker.getGeyserCount() > 0
				&& (count(CYBERNETICS_CORE) > 0 || minerals() >= 300)
				&& count(NEXUS) >= 2)
		{
			bot.spaceManager.build(UnitType.Protoss_Assimilator);
		}
		
		if (bot.getAvailableMinerals() >= 200 
				&& UnitTracker.count(UnitType.Protoss_Cybernetics_Core) < 1
				&& completed(GATEWAY) > 0)
		{
			bot.spaceManager.build(UnitType.Protoss_Cybernetics_Core);
		}
		
		if (bot.getAvailableMinerals() >= 150
				&& UnitTracker.count(UnitType.Protoss_Dragoon) + UnitTracker.count(UnitType.Protoss_Zealot) >= 15
				&& UnitTracker.count(UnitType.Protoss_Forge) == 0)
		{
			bot.spaceManager.build(UnitType.Protoss_Forge);
		}
		
		if (bot.getAvailableMinerals() >= 300
				&& UnitTracker.count(UnitType.Protoss_Nexus) >= 2
				&& UnitTracker.count(UnitType.Protoss_Cybernetics_Core) > 0
				&& UnitTracker.count(UnitType.Protoss_Forge) < 2)
		{
			bot.spaceManager.build(UnitType.Protoss_Forge);
		}
		
		if (bot.getAvailableMinerals() >= 150
				&& bot.getAvailableGas() >= 100
				&& UnitTracker.count(UnitType.Protoss_Citadel_of_Adun) == 0
				&& self.completedUnitCount(UnitType.Protoss_Cybernetics_Core) > 0
				&& UnitTracker.count(UnitType.Protoss_Gateway) >= 4
				&& count(DRAGOON) >= 5)
		{
			bot.spaceManager.build(UnitType.Protoss_Citadel_of_Adun);
		}
		
		if (gas() >= 150
				&& minerals() >= 200
				&& count(TEMPLAR_ARCHIVES) == 0
				&& completed(CITADEL) > 0
				&& count(DRAGOON) >= 8)
		{
			build(TEMPLAR_ARCHIVES);
		}
		
		if (gas() >= 200 && minerals() >= 200
				&& count(ROBOTICS_FACILITY) < 1
				&& count(GATEWAY) >= 2)
		{
			bot.spaceManager.build(ROBOTICS_FACILITY);
		}
		
		if (gas() >= 50 && minerals() >= 100
				&& completed(ROBOTICS_FACILITY) > 0
				&& count(OBSERVATORY) == 0)
		{
			bot.spaceManager.build(OBSERVATORY);
		}
		
		if (minerals() >= 150
			&& gas() >= 100
			&& count(STARGATE) == 0
			&& completed(CYBERNETICS_CORE) > 0
			&& count(DRAGOON) >= 8)
		{
			build(STARGATE);
		}
		
		if (minerals() >= 200
				&& gas() >= 150
				&& completed(STARGATE) > 0
				&& completed(TEMPLAR_ARCHIVES) > 0
				&& count(ARBITER_TRIBUNAL) == 0)
		{
			build(ARBITER_TRIBUNAL);
		}
	}
	
	private boolean pauseProduction()
	{
		if (gas() > 250 && minerals() > 400)
			return false;

		if (count(DRAGOON) >= 2
				&& count(GATEWAY) > 2
				&& completed(CYBERNETICS_CORE) > 0
				&& count(ROBOTICS_FACILITY) == 0
				&& count(ARBITER_TRIBUNAL) > 0)
			return true;
		if (armySize() >= 2
				&& completed(CYBERNETICS_CORE) > 0
				&& completed(ROBOTICS_FACILITY) == 1
				&& count(OBSERVATORY) == 0)
			return true;
		if (armySize() >= 2
				&& completed(CYBERNETICS_CORE) > 0
				&& completed(OBSERVATORY) == 1
				&& count(OBSERVER) < 3
				&& completed(OBSERVER) == count(OBSERVER))
			return true;
		
		if (completed(STARGATE) > 0
				&& count(SCOUT) == 0)
			return true;
		
		if (UnitTracker.count(CITADEL) == 0
				&& completed(CYBERNETICS_CORE) > 0
				&& count(GATEWAY) >= 4
				&& count(ZEALOT) + count(DRAGOON) >= 20)
			return true;
		
		if (minerals() < 400
				&& count(NEXUS) <= 2
				&& count(NEXUS) < ExpandPart.maximumCcs)
			return true;
		
		if (minerals() >= 300)
			return false;
		if (count(ZEALOT) >= 2 && count(CYBERNETICS_CORE) == 0)
			return true;
		if (count(ZEALOT) >= 2 && count(ASSIMILATOR) == 0)
			return true;
		return false;
	}
	
	@Override
	public boolean overrideStructureOrder(Game game, Player self, Tyr bot, Agent agent)
	{
		if (agent.unit.getType() == UnitType.Protoss_Gateway && !agent.unit.isTraining())
		{
			if (count(DRAGOON) <= 10
					&& !pauseProduction())
			{
				if (bot.getAvailableMinerals() >= 125 && bot.getAvailableGas() >= 50)
					agent.unit.build(DRAGOON);
				return true;
			}
			if ((!pauseProduction() || minerals() >= 300)
					&& (count(ZEALOT) + 3 <= count(DRAGOON) || count(DRAGOON) >= 20)
					&& count(DRAGOON) >= 10
					&& bot.getAvailableMinerals() >= 100)
				agent.unit.build(ZEALOT);
			else if (!pauseProduction()
					&& (count(ZEALOT)  + 3 > count(DRAGOON))
					&& bot.getAvailableMinerals() >= 125 && bot.getAvailableGas() >= 50)
				agent.unit.build(DRAGOON);
			return true;
		}
		else if (agent.unit.getType() == UnitType.Protoss_Cybernetics_Core && !agent.unit.isUpgrading())
		{
			if(bot.getAvailableMinerals() >= UpgradeType.Singularity_Charge.mineralPrice()
					&& count(DRAGOON) >= 3
					&& bot.getAvailableGas() >= UpgradeType.Singularity_Charge.gasPrice())
				agent.unit.upgrade(UpgradeType.Singularity_Charge);
		}
		else if (agent.unit.getType() == UnitType.Protoss_Forge && !agent.unit.isUpgrading())
		{
			if(bot.getAvailableMinerals() >= UpgradeType.Protoss_Ground_Weapons.mineralPrice()
					&& bot.getAvailableGas() >= UpgradeType.Protoss_Ground_Weapons.gasPrice())
				agent.unit.upgrade(UpgradeType.Protoss_Ground_Weapons);
			
			if(bot.getAvailableMinerals() >= UpgradeType.Protoss_Ground_Armor.mineralPrice()
					&& bot.getAvailableGas() >= UpgradeType.Protoss_Ground_Armor.gasPrice())
				agent.unit.upgrade(UpgradeType.Protoss_Ground_Armor);
		}
		else if (agent.unit.getType() == CITADEL && !agent.unit.isUpgrading())
		{
			if (gas() >= UpgradeType.Leg_Enhancements.gasPrice()
					&& minerals() >= UpgradeType.Leg_Enhancements.mineralPrice())
				agent.unit.upgrade(UpgradeType.Leg_Enhancements);
		}
		else if (agent.unit.getType() == ROBOTICS_FACILITY)
		{
			if ((count(OBSERVER) < 3)
					&& minerals() >= 25
					&& gas() >= 75
					&& !agent.unit.isTraining())
				agent.unit.build(OBSERVER);
			if (minerals() >= 600
					&& !agent.unit.isTraining())
				agent.unit.build(SHUTTLE);
			return true;
		}
		else if (agent.unit.getType() == STARGATE)
		{
			if (completed(ARBITER_TRIBUNAL) > 0
					&& minerals() >= 100
					&& gas() >= 350
					&& !agent.unit.isTraining())
				agent.unit.train(ARBITER);
			return true;
		}
		else if (agent.unit.getType() == ARBITER_TRIBUNAL)
		{
			if (self.hasResearched(TechType.Recall)
					&& minerals() >= 150
					&& gas() >= 150)
				agent.unit.research(TechtType.Recall);
		}
		return false;
	}
}
