package risk.lobby.server;

import risk.engine.Risk;

import risk.engine.core.RiskGame;
import risk.engine.core.Player;

import org.lobby.server.ServerGame;
import org.lobby.server.ServerGameListener;

import java.util.Iterator;
import java.util.Vector;

import risk.ui.Increment1GUI.Increment1Frame;
import risk.ui.SimpleGUI.RiskGUI;

import java.util.Map;
import java.util.HashMap;

public class ServerGameRisk extends Risk implements ServerGame {

	//private String myguid;
	private ServerGameListener listoner;
	private String[] myplayers;
	private Map playersMap;
	private Map startgameMap;
	private Vector spectators;

	public ServerGameRisk() {

		super(null);

		playersMap = new HashMap();
		startgameMap = new HashMap();

		spectators = new Vector();

		// POP UP DEBUG WINDOW
		//Increment1Frame gui = new Increment1Frame( this );
		//RiskGUI gui = new RiskGUI( this );
        	//gui.setVisible(true);

	}

	public void startGame(String startGameOptions, String[] players) {

		//System.out.println("\tNEW GAME STARTING FOR RISK: "+gameid);

		//myguid = gameid;

		try {

			game = new RiskGame();

		}
		catch (Exception ex) {

			throw new RuntimeException("unable to make game!",ex);

		}

		String[] options = startGameOptions.split("\\n");

		int aicrap = Integer.parseInt(options[0]);
		int aieasy = Integer.parseInt(options[1]);
		int aihard = Integer.parseInt(options[2]);

		if ((players.length+aicrap+aieasy+aihard)>RiskGame.MAX_PLAYERS ) { throw new RuntimeException("player number missmatch for startgame"); }

		myplayers = players;


		parser(options[3]); // set the map file to use

		Vector colorString = new Vector();
		colorString.add( riskconfig.get("default.player1.color") );
		colorString.add( riskconfig.get("default.player2.color") );
		colorString.add( riskconfig.get("default.player3.color") );
		colorString.add( riskconfig.get("default.player4.color") );
		colorString.add( riskconfig.get("default.player5.color") );
		colorString.add( riskconfig.get("default.player6.color") );
		Iterator it = colorString.iterator();

		for (int c=0;c<players.length;c++) {

			it.hasNext();
			String color = (String)it.next();

			playersMap.put(players[c], "player"+(c+1));

			messageFromUser(players[c] , "newplayer human "+color + " " + players[c]);

		}

		for (int c=0;c<aicrap;c++) {


			it.hasNext();
			String color = (String)it.next();

			parser("newplayer ai crap "+color + " CrapBot" + (c+1));

		}

		for (int c=0;c<aieasy;c++) {

			it.hasNext();
			String color = (String)it.next();

			parser("newplayer ai easy "+color + " EasyBot" + (c+1));
		}

		for (int c=0;c<aihard;c++) {

			it.hasNext();
			String color = (String)it.next();

			parser("newplayer ai hard "+color + " HardBot" + (c+1));
		}

		parser(options[4]); // start the game

	}

	public void addServerGameListener(ServerGameListener l) {

		listoner = l;

	}

	public synchronized String clientJoined(String username) {

		spectators.add(username);

		// @todo later needs to be moved into the server code
		listoner.sendChatroomMessage(username+" has joined the table");

		StringBuffer buffer = new StringBuffer();

		buffer.append("GAME_JOIN_1");

		String playerid = (String)playersMap.get(username);

		if (playerid == null) {

			playerid = "spectator";

		}

		buffer.append( "\n" +playerid );

		for (Iterator it = game.getCommands().iterator();it.hasNext();) {

			buffer.append("\n"+it.next().toString());

		}

		return buffer.toString();

	}

	public void clientLeaves(String username) { // all close games are caught and sent here

		spectators.remove(username);

		// @todo later needs to be moved into the server code
		listoner.sendChatroomMessage(username+" has left the table");

		String Addr = (String)playersMap.get(username);

		if (Addr != null && game!=null) { // if its a actual player of the game that has left

			//int count=0;

			// get all the players and make all with the ip of the leaver become nutral
			Vector leavers = game.getPlayers();

			for (int c=0; c< leavers.size() ; c++) {

				Player player = ((Player)leavers.elementAt(c));

				// AI will never have players addr for lobby game
				if ( player.getAddress().equals(Addr) ) {

					player.setType( Player.PLAYER_AI_CRAP );

					player.setAddress( myAddress );

				}

				//if (player.getType() == Player.PLAYER_HUMAN) {

				//	count++;

				//}

			}

			//@todo this is wrong, just bot games wont work and otehr things wont
			//if (count==0) {
			// close everything (but this is wrong)
			//}

		}


		// server sends to that user to close there game
		//listoner.messageFromGame(myAddress+" closegame", new String[] { username } );
		// this is now done on the client after the call to leave

		//YURA@todo when the last client/player/spactator has gone, shut down the thread and inform the lobby server
		// if there r no spectators left, and the game has kicked off
		//@todo again wont work if just AI games
		if ( spectators.isEmpty() && startgameMap.size()==myplayers.length) {

			parser("closegame");
			listoner.gameFinished();

		}


	}

	// get message from the user
	public synchronized void messageFromUser(String username, String message) {

		System.out.print("\tGOT: "+message+"\n");

		// this is that crazy button, basically a LOBBY only command, there will be more
		if ( message.equals("STARTGAME") ) {

			startgameMap.put(username,message);

			//System.out.print("\tRisk: "+username+" has clicked startgame\n");

			listoner.sendChatroomMessage(username+" has clicked startgame");

			if (startgameMap.size()==myplayers.length) {

				// when we have all the players let the game start
				this.notify();

			}

			return;
		}


		String address = (String)playersMap.get(username);

		//if (game.getCurrentPlayer()!=null) { System.out.print( "\t"+game.getCurrentPlayer().getAddress()+" "+address ); }

		// game not started OR game IS started and it is there go
		if (message.trim().equals("closegame")) {

			System.out.println("\tCLOSEGAME NOT ALLOWED TO BE SENT TO CORE: "+username);

		}
		else if ((game.getState() == RiskGame.STATE_NEW_GAME) || ( game.getCurrentPlayer()!=null && game.getCurrentPlayer().getAddress().equals( address ) )) {

			// creates the players with the correct address
			inbox.add(address+" "+message);
			this.notify();

		}
		else {

			System.out.print("\tCHEATING!!!!: "+username+" "+message+"\n");

			listoner.sendChatroomMessage(username+" is trying to cheat!");

		}

	}

	// must catch all messages from the ais
	public synchronized void parser(String m) {

		//System.out.print("\tGOT: "+m+"\n");

		// address must match for ai to know when to take its turn
		inbox.add(myAddress+" "+m);
		this.notify();

	}

	// pass things from the inbot to the GameParser
	public void run() {

		String message;

		while (true) {

			synchronized(this) {

				// dont go on if this is in catch all and dont run mode!!!!!
				if( inbox.isEmpty() ||

					( startgameMap.size()!=myplayers.length && (game.getState() != RiskGame.STATE_NEW_GAME) )

				) {
					try { this.wait(); }
					catch(InterruptedException e){}
				}

				message = (String)inbox.remove(0);

			}

			GameParser(message);

		}
	}

	// catch all things and send it to the clients
	// game kicks off and messages are sent to here
	public void GameParser(String mem) {

		System.out.println("\tRISK "+mem);

		//if not all players hit start and the game is started, just store the commands, do not run them
		if ( startgameMap.size()!=myplayers.length && (game.getState() != RiskGame.STATE_NEW_GAME) ) {

			inbox.add(mem);
			return;
		}

		// send out to all clients
		listoner.messageFromGame(mem, (String[])spectators.toArray( new String[spectators.size()] ) );

		super.GameParser(mem);

	}

	// calls messageToClients(uuid,message,towho)
	//messageToClients(String gameuuid,String message,String[] towho)

}
