package tournament;

import admin.Output;
import admin.utils.AdminDocumentHandler;
import admin.utils.Game.GameType;
import edu.neu.ccs.demeterf.demfgen.lib.List;
import edu.neu.ccs.demeterf.demfgen.lib.List.Comp;
import edu.neu.ccs.demeterf.demfgen.lib.List.Pred;
import gen.*;

public class Tournament{
	private List<Standing> results;
	private List<Player> players;
	private List<Match> matches;
	Output o;
	GameType gt;
	
	public Tournament(List<Player> players, String outputFile, GameType gt){
		this.players = players;
		generateMatches();
		o = Output.htmlOutput(outputFile);
		this.gt = gt;
	}
	
	private void generateMatches(){
		Result init = new Pending();
		matches = List.<Match>create();
		for(Player p : players){
			for(Player p2 : players){
				if(!p.equals(p2)){
					matches = matches.append(new Match(p, p2, init));
				}
			}
		}
	}
	
	public void runTournament(){
		o.header();
		matches = new edu.neu.ccs.demeterf.stackless.HeapTrav(new TournamentTrav(gt, matches.length())).traverse(matches);
		results = edu.neu.ccs.demeterf.TUCombiner.traverse(matches, new GatherResults());
		results = results.sort(new ResultsByWinsAndDraws());
		o.footer();
	}
	
	public List<Standing> getResults() { return results; }
	public List<Match> getMatches() { return matches; }
	
	private class TournamentTrav extends edu.neu.ccs.demeterf.Bc
	{
		int gamesPlayed;
		int numGames;
		private admin.TournAdmin ta = new admin.TournAdmin(o);
		@SuppressWarnings("unchecked")
		private Store emptyStore = new Store(List.<Pair<PlayerID, PlayerStore>>create());
		private GameType gt;
		
		public TournamentTrav(GameType gt, int numGames)
		{
			this.gt = gt;
			this.numGames = numGames;
			gamesPlayed = 0;
		}
		
		public Match combine(Match m, Player white, Player black)
		{
			//Empty the store before each competition

			AdminDocumentHandler.commitStore(emptyStore);
			AdminDocumentHandler.deletePlayerTrans(white);
			AdminDocumentHandler.deletePlayerTrans(black);
			Result r = ta.runMatch(white, black, gt);
			o.playerStart();
			o.println("White: " + white.print());
			o.println("Black: " + black.print());
			o.println("Result: " + r.print());
			o.playerEnd();
			System.err.println("Games played: " + ++gamesPlayed + " of " + numGames);
			return new Match(white, black, r);
		}
	}
	
	private class GatherResults extends edu.neu.ccs.demeterf.TUCombiner<List<Standing>>
	{
		List<Standing> empty = List.<Standing>create();
		Player fakePlayer = new Player(new PlayerID(0), "Bob");
		private Standing win = new Standing(fakePlayer, 1, 0, 0);
		private Standing loss = new Standing(fakePlayer, 0, 1, 0);
		private Standing draw = new Standing(fakePlayer, 0, 0, 1);
		
		public List<Standing> combine()
		{
			return empty;
		}
		public List<Standing> combine(Match m)
		{
			List<Standing> answer = empty;
			if(m.r.isWhite())
			{
				answer = answer.push(win.setPlayer(m.white));
				answer = answer.push(loss.setPlayer(m.black));
			}
			else if(m.r.isBlack())
			{
				answer = answer.push(loss.setPlayer(m.white));
				answer = answer.push(win.setPlayer(m.black));
			}
			else
			{
				answer = answer.push(draw.setPlayer(m.white));
				answer = answer.push(draw.setPlayer(m.black));
			}
			return answer;
		}
		public List<Standing> fold(List<Standing> a, List<Standing> b){
			List<Standing> answer = List.<Standing>create();
			for(Standing s : a){
				StandingByPlayer sbp = new StandingByPlayer(s);
				answer = answer.push(b.contains(sbp)?s.sum(b.find(sbp)):s);
			}
			for(Standing s : b){
				StandingByPlayer sbp = new StandingByPlayer(s);
				if(!answer.contains(sbp))
				    answer = answer.push(s);
			}
			return answer;
		}
		
		private class StandingByPlayer extends Pred<Standing>{
			Standing s;
			public StandingByPlayer(Standing s){
				this.s = s;
			}
			public boolean huh(Standing arg0){
				return s.player.equals(arg0.player);
			}
			
		}
	}
	
	private class ResultsByWinsAndDraws extends Comp<Standing>{
		/** a before b? */
		public boolean comp(Standing a, Standing b){
			return (a.wins > b.wins || (a.wins == b.wins && a.draws > b.draws));
		}
		
	}
}