import java.io.*;
import java.util.*;

public class TurnManager extends Thread {
	public static enum Status {
		Waiting    ( "waiting" ),
		RoleSelect ( "selecting roles" ),
		Playing    ( "playing turn" ),
		Done       ( "game over" );
		
		private String statustext;
		
		Status( String s ) {
			statustext = s;
		}
		
		public String toString() {
			return statustext;
		}
	}
	
	public static final int MsgErr = -1;
	public static final int MsgQuit = 0;
	public static final int MsgTalk = 1;
	
	public Status status;

	private Vector<Player> observers;
	private Player[] players;
	private int numplayers;
	private int numplaying;

	private Random rnd = null;
	private boolean gamestarted;
	private int crown = Roles.unassigned;
	private int turn;
	
	private int[] roles;
	private String[] rolenames;
	
	private void processTurn() {
		switch (status) {
			case Waiting:
				for (Player p : observers) {
					if (p.connected() && (!p.playing())) {
						numplaying++;
						p.setPlaying( true );
						players[ firstFreePlayer() ] = p;
						break;
					}
				}
				
				if (numplaying == numplayers) {
					status = Status.Playing;
					System.out.println( "Players connected. Starting game." );
					
					if (!gamestarted) {
						gamestarted = true;
						crown = getRandomPlayer();
						turn = crown;
						System.out.println( getPlayerName( crown ) +
						                    " has been crowned " + (rolenames[ Roles.monarch ]).toLowerCase() + "." );
					}
				}
				break;
			case RoleSelect:
			case Playing:
				processQueue( turn );
				break;
			default:
				// NOP
		}
	}
	
	public int getRandomPlayer() {
		return rnd.nextInt( numplayers );
	}
	
	public String getPlayerName( int i ) {
		return players[ i ].getName();
	}

	public int getPlayerIndex( String name ) {
		int id = -1;
		
		for (int i = 0; i < numplayers; i++) {
			if (name.equals( players[ i ].getName() )) {
				id = i;
				break;
			}
		}
		
		return id;
	}
	
	public int getIndex( Player p ) {
		int id = -1;
		
		for (int i = 0; i < numplayers; i++) {
			if (p == players[ i ]) {
				// Yes, in this case, I do actually want ==, not .equals()
				id = i;
				break;
			}
		}
		
		return id;
	}
	
	public boolean playerExists( int idx ) {
		return (idx <= players.length);
	}
	
	public Player getPlayer( int idx ) {
		return players[ idx ];
	}

	public TurnManager( Vector<Player> obs, int nplayers ) {
		observers = obs;
		numplayers = nplayers;
		numplaying = 0;
		gamestarted = false;
		rnd = new Random();
		
		initRoles( "roles.dat" );

		players = new Player[ numplayers ];
		for (int i = 0; i < numplayers; i++) {
			players[ i ] = null;
		}
	}
	
	private void waitForInterrupt( long millis ) {
		if (! Thread.interrupted() ) {
			try {
				sleep( millis );
			} catch (InterruptedException e) {
				// NOP, just exit
			}
		}
	}
	
	private int firstFreePlayer() {
		for (int i = 0; i < numplayers; i++) {
			if (players[ i ] == null) {
				return i;
			}
		}
		
		return -1;
	}
	
	private void initRoles( String filename ) {
		BufferedReader rfile;
		String instr;
		
		int numroles = Roles.numRoles( numplayers );
		
		roles = new int[ numroles ];
		rolenames = new String[ numroles ];

		for (int i = 0; i < numroles; i++) {
			roles[ i ] = Roles.unassigned;
		}
		
		try {
			rfile = new BufferedReader( new FileReader( filename ) );
			
			int i = 0;
			while (i < numroles) {
				instr = rfile.readLine();
				if (instr == null) {
					System.out.println( "End of roles file reached." );
					rolenames[ i ] = "role " + i;
				} else if ((instr.trim()).equals( "" ) ||
				  		   instr.startsWith( "#" )) {
					continue;
				} else {
					rolenames[ i ] = instr.trim();
				}
				i++;
			}
			rfile.close();
			System.out.println( numroles + " roles initialized." );
		} catch (IOException e) {
			System.out.println( "Error reading roles file." );
			for (int i = 0; i < numroles; i++) {
				if (rolenames[ i ] == null) {
					rolenames[ i ] = "role " + i;
				}
			}
		}
	}
	
	public String playerFlags( int player ) {
		StringBuilder s = new StringBuilder();
		int numroles = Roles.numRoles( numplayers );
		
		if (player == crown) {
			s.append( "Player is currently crowned " + (rolenames[ Roles.monarch ]).toLowerCase() + ".\n" );
		}
		for (int i = 0; i < numroles; i++) {
			if (roles[ i ] == player) {
				s.append( "Player currently holds role: " + rolenames[ i ] + "\n" );
			}
		}
		
		return s.toString();
	}

	private void processQueue( int player ) {
		// TODO: fill this in!
	}
	
	public void run() {
		status = Status.Waiting;
		
		while (status != Status.Done) {
			waitForInterrupt( 50 );
			processTurn();
		}
	}
}
