package jp.ac.nii.icpc2010.tournament;

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


public class TournamentRunner {
	// run time test parameters:
	//  1) 3 players: A-team APlayer random-Bits RandomPlayer theS SuicidePlayer
	//  2) 6 players: A-team APlayer justA APlayer random-Bits RandomPlayer random-Marvel RandomPlayer theS SuicidePlayer whereAmI SuicidePlayer
	
	public static void main(String[] args) {
		boolean simulate = false;
				
		int threads = 1;
		
		assert(args.length > 0);
		List<Player> players = new ArrayList<Player>();
		
		for (int argPos = 0; argPos < args.length; argPos++) { 
			if (args[argPos].equals("-threads")) {							
				threads = Integer.parseInt(args[argPos + 1]);
				argPos++;
			} else if (args[argPos].equals("-simulate")) {
				simulate = true;
			} else if (args[argPos].equals("-players")) {
				
				int playerCount = 0;
				for (; playerCount < (args.length - argPos - 1) / 2; playerCount++) {
							
					int basePos = argPos + 1 + 2 * playerCount;
					players.add(new Player(args[basePos], args[basePos + 1]));
				}
				argPos += playerCount * 2;
			} else {
				System.err.println("Unknown argument " + args[argPos]);
			}
		}
		
		randomizeOrder(players);
		
		if (simulate) {
			Logger.log("Simulating");
			simulate(threads);
		} else {
			assert (players.size() > 0);			
			new TournamentMaster(players, threads);
		}
	}
	
	private static void randomizeOrder (List<Player> list) {
		final int size = list.size();
		
		//randomize by carrying out a number of random swaps
		for (int i = 0; i < size * 10; ++i) {
			int pos1 = (int) (Math.random() * size);
			int pos2 = (int) (Math.random() * size);
			Player x = list.get(pos1);			
			list.add(pos1, list.get(pos2));
			list.remove(pos1 + 1);			
			list.add(pos2, x);
			list.remove(pos2 + 1);
		}
	}
	
	private static void simulate(int threads) {
		int teams = 48;
		Logger.log("Estimation: "+estimatedRunningTime(teams, 4, threads));
		
		List<Player> players = new ArrayList<Player>();
		int x = 0; while (x++ < teams) {
			players.add(Math.random() < 0.5 ? new Player("r"+x, "HilbertCurveSelecter") : new Player("s"+x, "CPUDrainer"));
		}
				
		new TournamentMaster(players, threads);
	}
	
	public static long estimatedRunningTime(int teams, int groupSize, int threads) {
		int curTeams = teams; long matches = 0; long groupMatches = factorial(groupSize - 1);
		do {
			int groups = (int)Math.ceil(curTeams / groupSize);
			matches += Math.ceil((groups) * groupMatches / threads);
			curTeams = groups * groupSize / 2;
		} while (curTeams >= groupSize);
		return matches;
	}
	
	public static long factorial(int n) {
        if(n <= 1)     // base case
            return 1;
        else
            return n * factorial(n-1);
    }
}
