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

import java.util.ArrayList;
import com.tyr.builds.AntiIron;
import com.tyr.builds.AntiKill;
import com.tyr.builds.AntiWorkerRush;
import com.tyr.builds.BBS;
import com.tyr.builds.BuildOrder;
import com.tyr.builds.CannonWall;
import com.tyr.builds.DTHarass;
import com.tyr.builds.DTPush;
import com.tyr.builds.DefensiveMech;
import com.tyr.builds.DefensiveTerran;
import com.tyr.builds.DragoonPush;
import com.tyr.builds.GatewayPush;
import com.tyr.builds.Mech;
import com.tyr.builds.OneBaseMech;
import com.tyr.builds.OneBaseTank;
import com.tyr.builds.ProtossFE;
import com.tyr.builds.PvIron;
import com.tyr.builds.PvT;
import com.tyr.builds.SafeTwoGate;
import com.tyr.builds.TAntiCannon;
import com.tyr.builds.TAntiZealot;
import com.tyr.builds.TFastExpand;
import com.tyr.builds.TankContain;
import com.tyr.builds.TvP;
import com.tyr.builds.TvPGeneric;
import com.tyr.builds.TwoBaseMech;
import com.tyr.builds.ZealotPush;
import com.tyr.tasks.SalesmenMarinesTask;
import com.tyr.tasks.SiegeNaturalTask;
import com.tyr.tasks.Task;
import com.tyr.unitgroups.ScoutGroup;

import bwapi.Game;
import bwapi.Player;
import bwapi.Race;


/**
 * This class manages the selection of builds against specific opponents.
 * @author Simon
 *
 */
public class PlayerProfile 
{
	/**
	 * The race of the opponent.
	 */
	private Race race;
	
	/**
	 * The names by which the opponent is known.
	 * If a name consists of multiple words (e.g. first name, last name) then they can be entered as separate entries of an array.
	 */
	private String[][] names;
	
	/**
	 * List of strategies that can be used to counter this opponent.
	 * Note that you can only either use this or the counter build order, not both.
	 */
	private Strategy[] strategies;
	
	/**
	 * The build that is used against this opponent.
	 * Note that you can only either use this or the strategy array, not both.
	 */
	private BuildOrder counter;
	
	/**
	 * Is there a strategy that we expect the opponent to be using?
	 * Use the strategies from ScoutGroup.
	 */
	private int opponentStrategy;
	
	/**
	 * At what time do we send out a worker scout?
	 * Can be left as -1 to use default scout timing of the build.
	 */
	private int scoutTiming;
	
	/**
	 * How many worker scouts do we send out?
	 * Can be left as 0 to use default scout timing of the build.
	 */
	private int nscouts;
	
	/**
	 * When this flag is set to true, the name is no longer checked, but the build is automatically selected.
	 */
	public boolean triggerDebug = false;
	
	/**
	 * List of tasks that should be added to the task manager.
	 */
	public Task[] tasks;
	

	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param counter The build that is used against this opponent.
	 * 		  Note that you can only either use this or the strategy array, not both.
	 * @param name The name by which the opponent is known.
	 */
	public PlayerProfile(Race race, BuildOrder counter, String name)
	{
		this(race, counter, new String[][]{new String[]{name}});
	}

	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param counter The build that is used against this opponent.
	 * 		  Note that you can only either use this or the strategy array, not both.
	 * @param names The names by which the opponent is known.
	 * 		If a name consists of multiple words (e.g. first name, last name) then they can be entered as separate entries of an array.
	 */
	public PlayerProfile(Race race, BuildOrder counter, String[][] names)
	{
		this(race, counter, names, ScoutGroup.unknown);
	}
	
	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param strategies List of strategies that can be used to counter this opponent.
	 * 		  Note that you can only either use this or the counter build order, not both.
	 * @param name The name by which the opponent is known.
	 */
	public PlayerProfile(Race race, Strategy[] strategies, String name)
	{
		this(race, strategies, new String[][]{new String[]{name}});
	}

	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param strategies List of strategies that can be used to counter this opponent.
	 * 		  Note that you can only either use this or the counter build order, not both.
	 * @param names The names by which the opponent is known.
	 * 		If a name consists of multiple words (e.g. first name, last name) then they can be entered as separate entries of an array.
	 */
	public PlayerProfile(Race race, Strategy[] strategies, String[][] names)
	{
		this.race = race;
		this.strategies = strategies;
		
		for(int i=0; i<names.length; i++)
		{
			for(int j=0; j<names[i].length; j++)
				names[i][j] = names[i][j].toLowerCase();
		}
		
		this.names = names;
	}
	
	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param counter The build that is used against this opponent.
	 * 		  Note that you can only either use this or the strategy array, not both.
	 * @param names The names by which the opponent is known.
	 * 		If a name consists of multiple words (e.g. first name, last name) then they can be entered as separate entries of an array.
	 * @param opponentStrategy Is there a strategy that we expect the opponent to be using?
	 * 		Use the strategies from ScoutGroup.
	 */
	public PlayerProfile(Race race, BuildOrder counter, String[][] names, int opponentStrategy)
	{
		this(race, counter, names, opponentStrategy, -1, 0, new Task[0]);
	}

	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param counter The build that is used against this opponent.
	 * 		  Note that you can only either use this or the strategy array, not both.
	 * @param names The names by which the opponent is known.
	 * 		If a name consists of multiple words (e.g. first name, last name) then they can be entered as separate entries of an array.
	 * @param opponentStrategy Is there a strategy that we expect the opponent to be using?
	 * 		Use the strategies from ScoutGroup.
	 * @param tasks List of tasks that should be added to the task manager.
	 */
	public PlayerProfile(Race race, BuildOrder counter, String[][] names, int opponentStrategy, Task[] tasks) 
	{
		this(race, counter, names, opponentStrategy, -1, 0, tasks);
	}
	
	/**
	 * This class manages the selection of builds against specific opponents.
	 * @param race The race of the opponent.
	 * @param counter The build that is used against this opponent.
	 * 		  Note that you can only either use this or the strategy array, not both.
	 * @param names The names by which the opponent is known.
	 * 		If a name consists of multiple words (e.g. first name, last name) then they can be entered as separate entries of an array.
	 * @param opponentStrategy Is there a strategy that we expect the opponent to be using?
	 * 		Use the strategies from ScoutGroup.
	 * @param scoutTiming At what time do we send out a worker scout?
	 * 		Can be left as -1 to use default scout timing of the build.
	 * @param nscouts How many worker scouts do we send out?
	 * 		Can be left as 0 to use default scout timing of the build.
	 * @param tasks List of tasks that should be added to the task manager.
	 */
	public PlayerProfile(Race race, BuildOrder counter, String[][] names, int opponentStrategy, int scoutTiming, int nscouts, Task[] tasks)
	{
		this.race = race;
		this.names = names;
		this.counter = counter;
		
		for(int i=0; i<names.length; i++)
		{
			for(int j=0; j<names[i].length; j++)
				names[i][j] = names[i][j].toLowerCase();
		}
		
		this.opponentStrategy = opponentStrategy;
		this.scoutTiming = scoutTiming;
		this.nscouts = nscouts;
		
		this.tasks = tasks;
	}
	
	/**
	 * Does the current opponent match this player profile?
	 * If it does, the settings for countering that player are set.
	 * @param game The current game.
	 * @param bot The bot.
	 * @return Whether the current opponent matches this player profile.
	 */
	public boolean match(Game game, Tyr bot)
	{	
		Player enemy = game.enemy();
		if (enemy.getRace() != race)
			return false;
		
		final String nameLower = DebugMessages.getEnemyName().toLowerCase();
		
		// Each array in names represents a name the opponent bot is known by.
		for (String[] name : names)
		{
			boolean matches = true;
			// A name matches if all name parts are present in the name of the opponent.
			for (String namePart : name)
			{
				if (!nameLower.contains(namePart))
				{
					matches = false;
					break;
				}
			}
			
			if (triggerDebug)
				matches = true;
			
			if (matches)
			{
				DebugMessages.log("Picked: " + this.names[0][0]);
				if (strategies != null)
				{
					Strategy pickedStrategy = Strategy.pickStrategy(strategies);
					pickedStrategy.set();
					DebugMessages.log("Strategy: " + pickedStrategy.getClass());
					return true;
				}
				
				// If this profile indeed matches the opponent, we set the settings to counter him.
				bot.build = counter;
				bot.scout.opponentStrategy = opponentStrategy;
				if(nscouts != 0)
				{
					bot.scout.nscouts = nscouts;
					bot.scout.workerScoutTiming = scoutTiming;
				}

				for (Task task : tasks)
					Tyr.bot.taskManager.potentialTasks.add(task);
				
				return true;
			}
		}
		
		return false;
	}
	
	/**
	 * Returns a list of all enemies for which we have a specific counter.
	 * @return A list of all enemies for which we have a specific counter.
	 */
	public static ArrayList<PlayerProfile> getProfiles()
	{
		if (Tyr.self.getRace() == Race.Terran)
			return getTerranProfiles();
		else if (Tyr.self.getRace() == Race.Protoss)
			return getProtossProfiles();
		else if (Tyr.self.getRace() == Race.Zerg)
			return getZergProfiles();
		else return new ArrayList<PlayerProfile>();
	}
	
	/**
	 * Returns a list of all enemies for which we have a specific counter.
	 * @return A list of all enemies for which we have a specific counter.
	 */
	public static ArrayList<PlayerProfile> getZergProfiles()
	{
		ArrayList<PlayerProfile> result = new ArrayList<PlayerProfile>();
		
		return result;
	}
	
	/**
	 * Returns a list of all enemies for which we have a specific counter.
	 * @return A list of all enemies for which we have a specific counter.
	 */
	public static ArrayList<PlayerProfile> getProtossProfiles()
	{
		final ArrayList<PlayerProfile> result = new ArrayList<PlayerProfile>();


		result.add(new PlayerProfile(Race.Protoss,  new Strategy[] {
				new Strategy("DT", new DTPush()),
				new Strategy("PvT", new PvT(25)),
				new Strategy("CANNONS", new CannonWall())
				}, new String[][]{ 
			new String[]{"Mega"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss,  new Strategy[] {
				new Strategy("DT", new DTPush()),
				new Strategy("PvT", new PvT(25)),
				new Strategy("CANNONS", new CannonWall())
				}, new String[][]{ 
				new String[]{"Skynet"},
				new String[]{"Andrew", "Smith"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss,  new Strategy[] {
				new Strategy("DT", new DTPush()),
				new Strategy("PvT", new PvT(25)),
				new Strategy("CANNONS", new CannonWall())
				}, new String[][]{ 
				new String[]{"Xelnaga"}
		}));

		result.add(new PlayerProfile(Race.Protoss, new DTPush(), new String[][]{ 
			new String[]{"Skynet"},
			new String[]{"Andrew", "Smith"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new ProtossFE(ProtossFE.DRAGOON_ONLY, false), new String[][]{ 
			new String[]{"Tomas", "Vajda"},
			new String[]{"Thomas", "Vajda"},
			new String[] {"XIMP"}
		}));
		
		final boolean skipHardcodedBuilds = false;
		if (skipHardcodedBuilds)
			return result;
		
		// Plasma has zerg eggs blocking the path to the enemy and requires a special build. 
		if (Tyr.game.mapFileName().contains("Plasma"))
		{
			return result;
		}

		// Blue Storm has an annoying choke that gets bigger units stuck.
		// We use a special build.
		if (Tyr.game.mapFileName().contains("Blue") && Tyr.game.mapFileName().contains("Storm"))
		{
			return result;
		}
		
		result.add(new PlayerProfile(Race.Zerg,
				new Strategy[] {
				//new Strategy("PvR", new PvT(25).setLargeInvasionDist(640))
				new Strategy("CANNONS", new CannonWall())
				},
				new String[][]{ 
			new String[]{"Neo", "Edmund"}
		}));
		
		result.add(new PlayerProfile(Race.Terran,
				new Strategy[] {
				//new Strategy("DTHARASS", new DTHarass()),
				new Strategy("PvIron", new PvIron().fullAssault().noCarriers())

				/*new Strategy("PvR", new PvT(25).delayUpgrades()
						.limitDefendingGoons()
						.counterAttackTanks()
						.useArbiters(false)
						.dragoonsFirst()
						.setExtraDragoons(-3))
				
				*/
				},
				new String[][]{ 
			new String[]{"Iron"}
		}));
		
		
		result.add(new PlayerProfile(Race.Terran,
				new Strategy[] {
				new Strategy("PvR", new PvT(40).delayUpgrades()
						.limitDefendingGoons()
						.counterAttackTanks()
						.useArbiters(false)
						.dragoonsFirst()
						.setExtraDragoons(-8))
				},
				new String[][]{ 
			new String[]{"Krasi"}
		}));

		result.add(new PlayerProfile(Race.Terran, new ProtossFE(ProtossFE.ZEALOT_ONLY, false), new String[][]{ 
			new String[]{"ICE"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new Strategy[] {
				new Strategy("GATEWAYTIMING", new DragoonPush(25, true, false, false, true, false, false, false)),
				new Strategy("ZP", new ZealotPush(false, false))
				}, new String[][]{ 
			new String[]{"Kaon"}
		}));
		
		if (Settings.getDebug())
		{

			result.add(new PlayerProfile(Race.Terran, new Strategy[] {
					new Strategy("FEZEALOTS", new ProtossFE(ProtossFE.ZEALOT_ONLY, false))
					/*
					new Strategy("PvR", new PvT(40).delayUpgrades()
							.limitDefendingGoons()
							.counterAttackTanks()
							.useArbiters(false)
							.dragoonsFirst()
							.setExtraDragoons(-8))
					*/
			}, new String[][]{ 
				new String[]{"leta"},
				new String[]{"Martin", "Rooijackers"}
			}));
		}
		else
		{
			result.add(new PlayerProfile(Race.Terran, new Strategy[] {
					new Strategy("FEZEALOTS", new ProtossFE(ProtossFE.ZEALOT_ONLY, false))
			}, new String[][]{ 
				new String[]{"leta"},
				new String[]{"Martin", "Rooijackers"}
			}));
		}
		
		result.add(new PlayerProfile(Race.Protoss, new Strategy[] {
				new Strategy("FECANNONS", new CannonWall(true)),
				new Strategy("DT", new DTPush())
		}, new String[][] {
				new String[] {"AIUR"},
				new String[] {"Florian", "Richoux"}
		}));

		result.add(new PlayerProfile(Race.Protoss, new ProtossFE(ProtossFE.NO_REAVER, true), new String[][]{ 
			new String[]{"Bereaver"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, //new SafeTwoGate(20, true, false, false, false)
				new Strategy[] {
				new Strategy("DTHARASS", new DTHarass())
		}
				, new String[][]{ 
			new String[]{"PurpleWave"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss,
				new CannonWall()
				, new String[][]{ 
			new String[]{"PurpleCheese"}
		}));

		result.add(new PlayerProfile(Race.Unknown, new CannonWall(false, 2), new String[][]{
			new String[]{"steamhammer"},
			new String[]{"randomhammer"}
		}));
		
		result.add(new PlayerProfile(Race.Zerg, new CannonWall(false, 2), new String[][] {
			new String[]{"steamhammer"},
			new String[]{"randomhammer"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new CannonWall(false, 2), new String[][] {
			new String[]{"steamhammer"},
			new String[]{"randomhammer"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new CannonWall(false, 2), new String[][] {
			new String[]{"steamhammer"},
			new String[]{"randomhammer"}
		}));
		
		result.add(new PlayerProfile(Race.Zerg, new Strategy[] {
				new Strategy("SAFETWOGATE", new SafeTwoGate(20, false, false, false, true, false))
		}, new String[][]{ 
			new String[]{"Overkill"},
			new String[]{"Sijia", "Xu"}
		}));
		
		/*
		result.add(new PlayerProfile(Race.Zerg, new CannonWall(true, 4, false, true), new String[][]{ 
			new String[]{"arrak"}
		}));
		
		result.add(new PlayerProfile(Race.Zerg, new SafeTwoGate(15, false, false, false, true), new String[][]{ 
			new String[]{"arrak"}
		}));
		*/
		
		result.add(new PlayerProfile(Race.Zerg, new PvT(25), new String[][]{ 
			new String[]{"arrak"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, 
			new Strategy[] {
				new Strategy("FECANNONS", new CannonWall(true)),
				new Strategy("CANNONS", new CannonWall()
				.noCannonDefense()
				.dragoonOnly()
				.doNotExpand()),
				new Strategy("PvT", new PvT(25))
			}
			, new String[][] {
			new String[]{"YuanhengZhu"},
			new String[]{"Yuanheng", "Zhu"}, 
			new String[]{"Juno"}
		}));
		
		if (Settings.getDebug())
		{
			result.add(new PlayerProfile(Race.Protoss, new ZealotPush(), new String[][]{ 
				new String[]{"BigEyes"}
			}));
			
			result.add(new PlayerProfile(Race.Terran, new ZealotPush(), new String[][]{ 
				new String[]{"HannesBredberg"}
			}));
			
			result.add(new PlayerProfile(Race.Protoss, new ZealotPush(), new String[][]{ 
				new String[]{"Pinfel"}
			}));
			
			result.add(new PlayerProfile(Race.Zerg, new CannonWall(), new String[][]{ 
				new String[]{"Peregrine"}
			}));
			
			result.add(new PlayerProfile(Race.Protoss, new CannonWall(), new String[][]{ 
				new String[]{"PurpleCheese"}
			}));

			result.add(new PlayerProfile(Race.Terran, new CannonWall(), new String[][]{ 
				new String[]{"MadMix"}, 
				new String[]{"Oyvind", "Johannessen"}
			}));

			result.add(new PlayerProfile(Race.Protoss, new CannonWall(), new String[][]{ 
				new String[]{"MadMix"}, 
				new String[]{"Oyvind", "Johannessen"}
			}));

			result.add(new PlayerProfile(Race.Zerg, new CannonWall(), new String[][]{ 
				new String[]{"MadMix"}, 
				new String[]{"Oyvind", "Johannessen"}
			}));
			
			result.add(new PlayerProfile(Race.Zerg, new PvT(25), new String[][]{ 
				new String[]{"AIlien"}
			}));
			
			result.add(new PlayerProfile(Race.Zerg, new CannonWall(), new String[][]{ 
				new String[]{"KillAll"}
			}));

			result.add(new PlayerProfile(Race.Zerg, new CannonWall(), new String[][]{
				new String[]{"Zia"}
			},
			ScoutGroup.unknown));

			result.add(new PlayerProfile(Race.Zerg, new CannonWall(), new String[][]{
				new String[]{"CasiaBot"}
			},
			ScoutGroup.unknown));
			
			result.add(new PlayerProfile(Race.Unknown, new CannonWall(), new String[][]{
				new String[]{"UAlberta"},
				new String[]{"Dave", "Churchill"},
				new String[]{"David", "Churchill"}
			}, ScoutGroup.unknown));
		}

		result.add(new PlayerProfile(Race.Zerg, new CannonWall(true), new String[][]{ 
			new String[]{"ZurZurZur"}
		}));

		
		if (Settings.getDebug())
		{
			result.add(new PlayerProfile(Race.Zerg, new CannonWall(true), new String[][]{ 
				new String[]{"Microwave"}
			}));
		}
		else
		{
			result.add(new PlayerProfile(Race.Zerg, new Strategy[]{
					new Strategy("FECANNONS", new CannonWall(true)),
					new Strategy("PvT", new PvT(25))
			}, new String[][]{ 
				new String[]{"Microwave"}
			}));
		}

		result.add(new PlayerProfile(Race.Protoss, new CannonWall(true, 6, true), new String[][]{ 
			new String[]{"Lukas", "Moravec"}
		}));
		
		result.add(new PlayerProfile(Race.Zerg, 
				new PvT(25).expandPush().delayUpgrades().prioritizeDragoons()
		, new String[][]{
			new String[]{"Marian", "Devecka"},
			new String[]{"Killer"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new Strategy[] {
				//new Strategy("GATEWAYTIMING", new DragoonPush(25, true, true, false, false, true, false)),
				new Strategy("GATEWAYTIMING", new GatewayPush()),
				}, new String[][]{ 
			new String[]{"tscmoo"}
		}));
		
		result.add(new PlayerProfile(Race.Zerg, 
				//new DragoonPush(25, false, true, true, false, true, false)
				new GatewayPush()
			, new String[][]{ 
			new String[]{"tscmoo"}
		}));

		if (Settings.getDebug())
		{
			result.add(new PlayerProfile(Race.Terran, new Strategy[] {
					new Strategy("PvT", new PvT(25)),
					new Strategy("GATEWAYTIMING", new GatewayPush())
					}, new String[][]{ 
				new String[]{"tscmoo"}
			}));
		}
		else
		{
			result.add(new PlayerProfile(Race.Terran,
					new GatewayPush()
				, new String[][]{ 
				new String[]{"tscmoo"}
			}));
		}
		
		result.add(new PlayerProfile(Race.Unknown, new Strategy[] {
				new Strategy("GATEWAYTIMING", new GatewayPush()),
				new Strategy("ZP", new ZealotPush()),
				new Strategy("CANNONS", new CannonWall(false, 2))
		}, new String[][]{ 
			new String[]{"tscmoo"}
		}));
		
		return result;
	}
	
	/**
	 * Returns a list of all enemies for which we have a specific counter.
	 * @return A list of all enemies for which we have a specific counter.
	 */
	public static ArrayList<PlayerProfile> getTerranProfiles()
	{
		ArrayList<PlayerProfile> result = new ArrayList<PlayerProfile>();
		
		
		/****************
		 **** Terran ****
		 ****************
		 */
		
		result.add(new PlayerProfile(Race.Terran, new TFastExpand(new DefensiveMech()), new String[][]{ 
			new String[]{"Igor", "Lacik"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new TFastExpand(new Mech(true)), new String[][]{ 
			new String[]{"Marek", "Kadek"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new TFastExpand(new DefensiveMech(true)), new String[][]{ 
			new String[]{"Henri", "Kumpulainen"}
		},
		ScoutGroup.unknown,
		new Task[] {new SalesmenMarinesTask()}));
		
		result.add(new PlayerProfile(Race.Terran, new TFastExpand(new Mech(true)), new String[][]{ 
			new String[]{"Rafal", "Poniatowski"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new Strategy[]{
				new Strategy("BBS", new BBS()),
				new Strategy("MPUSH", new TAntiZealot(true, false, true, true))
				}, new String[][]{
			new String[]{"tscmoo"}
		}));
		
	
		result.add(new PlayerProfile(Race.Terran, new BBS(), new String[][]{ 
			new String[]{"ICE"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new Strategy[]{
				new Strategy("BBS", new BBS()),
				new Strategy("TvP", new TvPGeneric())
				}, new String[][]{
				new String[]{"leta"}, 
				new String[]{"Martin", "Rooijackers"}
		}));
		
		result.add(new PlayerProfile(Race.Terran, new Strategy[]{
				new Strategy("BBS", new BBS())
				}, new String[][]{
				new String[]{"Krasi"},
		}));

		result.add(new PlayerProfile(Race.Terran, new DefensiveMech(true, false, false), new String[][]{ 
			new String[]{"TerranUAB"}
		},
		ScoutGroup.unknown));

		result.add(new PlayerProfile(Race.Terran, new DefensiveMech(), new String[][]{ 
			new String[]{"Oritaka"}
		},
		ScoutGroup.unknown));

		result.add(new PlayerProfile(Race.Terran, new DefensiveMech(), new String[][]{ 
			new String[]{"Yarmouk"}
		},
		ScoutGroup.unknown));

		result.add(new PlayerProfile(Race.Terran, new TFastExpand(new DefensiveMech(DefensiveMech.EARLY_PUSH, false, false, true)), new String[][]{ 
			new String[]{"Radim", "Bobek"}
		},
		ScoutGroup.unknown));

		result.add(new PlayerProfile(Race.Terran, new AntiWorkerRush(), new String[][]{ 
			new String[]{"Stone"}
		},
		ScoutGroup.unknown));
		
		result.add(new PlayerProfile(Race.Terran, new Strategy[]{
				new Strategy("DROP", new AntiIron()),
				new Strategy("MPUSH", new TAntiZealot(true, false, true, true))
				}, new String[][]{
				new String[]{"Iron"},
				new String[]{"Igor", "Dimitrijevic"}
		}));

		/*
		result.add(new PlayerProfile(Race.Terran, new TFastExpand(new DefensiveMech()), new String[][]{ 
			new String[]{"Soeren", "Klett"},
			new String[]{"Soren", "Klett"},
			new String[]{"Sren", "Klett"},
			new String[]{"W.O.P.R."},
			new String[]{"WOPR"}
		}));
		*/
		result.add(new PlayerProfile(Race.Terran, new BBS(), new String[][]{ 
			new String[]{"Soeren", "Klett"},
			new String[]{"Soren", "Klett"},
			new String[]{"Sren", "Klett"},
			new String[]{"W.O.P.R."},
			new String[]{"WOPR"}
		}));
		
		
		/****************
		 **** Protoss ***
		 ****************
		 */
		
		result.add(new PlayerProfile(Race.Protoss, new Strategy[]{
				new Strategy("BBS", new BBS())
				}, new String[][]{
				new String[]{"Bereaver"},
		}));

		result.add(new PlayerProfile(Race.Protoss, new TwoBaseMech(), new String[][]{ 
			new String[]{"Aiur"}, 
			new String[]{"Florian", "Richoux"}
		}));

		result.add(new PlayerProfile(Race.Protoss, new DefensiveTerran(), new String[][]{ 
			new String[]{"humanTest"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new TwoBaseMech(), new String[][]{
			new String[]{"Vladimir", "Jurenka"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new TwoBaseMech(), new String[][]{ 
			new String[]{"Roman", "Danielis"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new TFastExpand(new DefensiveMech(true)), new String[][]{ 
			new String[]{"Skynet"}, 
			new String[]{"Andrew", "Smith"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss,
			new Strategy[] {
				new Strategy("MPUSH", new TAntiZealot(true, false, true, true)),
				new Strategy("FE", new TFastExpand(new TvPGeneric()))
			}, new String[][]{
			new String[]{"Tomas", "Cere"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new OneBaseMech(), new String[][]{ 
			new String[]{"Xelnaga"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new DefensiveMech(), new String[][]{ 
			new String[]{"Susanoo"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, new Strategy[]{
				new Strategy("TC", new TankContain()),
				new Strategy("MPUSH", new TAntiZealot(true, false, true, true))
				}, new String[][]{
			new String[]{"tscmoo"}
		}));
		
		/****************
		 **** Cannons ***
		 ****************
		 */
		
		result.add(new PlayerProfile(Race.Protoss, (BuildOrder)new TAntiCannon(true), new String[][]{ 
			new String[]{"Tomas", "Vajda"},
			new String[]{"Thomas", "Vajda"},
			new String[] {"XIMP"}
		}));
		
		result.add(new PlayerProfile(Race.Protoss, (BuildOrder)new TvP(), new String[][]{ 
			new String[]{"Jakub", "Trancik"}
		},
		ScoutGroup.cannons));
		
		/****************
		 ***** Zerg *****
		 ****************
		 */

		/*
		 * Hardcoded strategies disabled because marcodbaa wants to see how my Anti Killerbot strategy does against other zerg.
		result.add(new PlayerProfile(Race.Zerg, new Strategy[] {
				new Strategy("ANTIPOOL", new AntiPool())
				}, new String[][]{
				new String[]{"5", "pool"},
				new String[]{"muukzor"},
		}));
		
		result.add(new PlayerProfile(Race.Zerg, new Strategy[]{
				new Strategy("ANTIZ", new Bio(Bio.DEFENSIVE))
				}, new String[][]{
				new String[]{"Newbie Zerg"},
		}));
		
		result.add(new PlayerProfile(Race.Zerg, new Strategy[]{
				new Strategy("BIO", new TFastExpand(new Bio(Bio.GREEDY, 201, true, false, 4)), ScoutGroup.unknown, new Task[] {new SalesmenMarinesTask(UnitType.Terran_Marine, 25, 8, true, 0),
					new PokeTask()}),
				new Strategy("MECH", new AntiMutaMech())
				}, new String[][]{
			new String[]{"tscmoo"}
		}));
		
		result.add(new PlayerProfile(Race.Zerg, new AntiKill(false), new String[][]{
			new String[]{"Marian", "Devecka"},
			new String[]{"Killer"}
		},
		ScoutGroup.unknown));
		
		result.add(new PlayerProfile(Race.Zerg, new Bio(Bio.GREEDY), new String[][]{
			new String[]{"Zia"}
		},
		ScoutGroup.unknown));
		
		result.add(new PlayerProfile(Race.Zerg, new Bio(Bio.DEFENSIVE, 25, true, false, 0), new String[][]{ 
			new String[]{"Overkill"},
			new String[]{"Sijia", "Xu"}
		},
		ScoutGroup.unknown));
		
		result.add(new PlayerProfile(Race.Zerg, new TFastExpand(new Bio(Bio.DEFENSIVE, 205, 205)), new String[][]{ 
			new String[]{"Garm"},
			new String[]{"Aurelien", "Lermant"}
		},
		ScoutGroup.unknown,
		new Task[] {new SalesmenMarinesTask(UnitType.Terran_Marine)}));
		
		result.add(new PlayerProfile(Race.Zerg, new Bio(Bio.GREEDY), new String[][]{ 
			new String[]{"Cimex"}
		},
		ScoutGroup.unknown));
		*/
		
		/****************
		 **** Random ****
		 ****************
		 */
		
		result.add(new PlayerProfile(Race.Unknown, new OneBaseTank(), new String[][]{
			new String[]{"UAlberta"},
			new String[]{"Dave", "Churchill"},
			new String[]{"David", "Churchill"}
		}, ScoutGroup.unknown
		, new Task[] {new SiegeNaturalTask()}));

		/*
		if (Settings.getTournament() || Settings.getDebug())
		{
			result.add(new PlayerProfile(Race.Unknown, new TAntiZealot(true, false, true, true), new String[][]{
				new String[]{"Travis", "Shelton"}
			}));
		}
		else
		{
			result.add(new PlayerProfile(Race.Unknown, new DefensiveTerran(), new String[][]{
				new String[]{"Travis", "Shelton"}
			}));
		}
		*/
		
		result.add(new PlayerProfile(Race.Unknown, new AntiKill(true), new String[][]{ 
			new String[]{"Opprimo"}
		}));
		
		return result;
	}
	
	/**
	 * Sets triggerDebug to true for the last added player profile in the list.
	 * @param result The list of player profiles.
	 */
	protected static void debug(ArrayList<PlayerProfile> result) 
	{
		if (Settings.getDebug())
			result.get(result.size()-1).triggerDebug = true;
	}
}