package breakout;
import java.io.*;
import java.net.*;
import java.util.*;
import gamefinder.*;

/**
 *
 * A class which creates a Socket to listen on and can communicate with multiple clients. 
 * Works with BOClient.java and ClientHandler.java.
 * Uses Gamefinder, created by Mike Wessler, so the game can be connected to by people.
 * It implements Runnable.
 *
 * @author  Jennifer Shieh
 * @see		java.lang.Runnable
 * @see		breakout.BOClient
 * @see		breakout.ClientHandler
 *
 */

public class BOServer implements Runnable
{
	/**
	 *	A Vector of ClientHandlers
	 */
	private Vector clientHandlers;
	/**
	 *	A ServerSocket
	 */
	private ServerSocket ss;
	/**
	 *	A Thread
	 */
	private Thread runner;
	/**
	 * This is a field to keep track of the current number of players playing Breakout!
	 */
	public int currentPlayerCount = 0;
	/**
	 *	A GameFinder
	 */
	//	private GameFinder gf;
	
	/**
	 *	Constructor takes no arguments; creates a new ServerSocket on port 4321
	 * 	Creates and starts a new Thread on this Object.
	 *
	 *	Catches IOException.
	 */
	public BOServer()
	{	
		try
		{
			this.ss = new ServerSocket(6667);
			System.out.println("Creating new ServerSocket on port 6667");
		}
		catch(IOException ioe)
		{
			System.out.println("I caught an IOException in BOServer constructor"
			   					+ ioe);
		}	
		
		//		this.gf = GameFinder.announce("Breakout!", 
		//				"Not your ordinary game of bricks...", 4321, 2);
		this.clientHandlers = new Vector();
		this.runner = new Thread(this);
		this.runner.start();
	}
	
	/**
	 *	Runnable's run() method. Accepts a connection, creating a Socket to listen on.
	 *	If a Socket has been created, a new ClientHandler will be created and connected to that Socket and this BOServer.
	 *	That ClientHandler is then added to a vector of ClientHandlers.
	 *	Also increases the currentPlayerCount field by 1 to keep track of number of opened Sockets/ Clients.
	 *	Catches IOException.
	 *
	 *	@see #currentPlayerCount
	 *	@see #writeOneInt(int i, ClientHandler ch)
	 *	@see java.net.Socket#accept()
	 */
	public void run()
	{
		while(true)
		{	
			Socket s;
			ClientHandler ch;

			try
			{
				s = this.ss.accept();
				System.out.println("Creating Socket to listen on" + s);
				
				if(s != null)
				{ 				
					this.currentPlayerCount = this.currentPlayerCount + 1;
					ch = new ClientHandler( s, this );
					System.out.println("Created new ClientHandler");
					this.clientHandlers.addElement(ch);	
					if (this.currentPlayerCount == 2)
					{
						this.writeOneInt(this.currentPlayerCount, ch);
						System.out.println("Server wrote currentPlayerCount " + this.currentPlayerCount);
					}
				}			

			}
			catch(IOException ioe)
			{
				System.out.println("I caught an IOException in BOServer run");
			}			
					
			//			this.gf.setPlayerCount(this.currentPlayerCount);
		}	
	}
		
	/**
	 *	Method to send the center coordinates of balls, represented by ints.  Sends information to all ClientHandlers
	 *	except the ClientHandler passed in as an argument, meant to be the ClientHandler that sent the information.
	 *	Uses ClientHandler's sendCoords(int x, int y) method.
	 *
	 *	@param  x  the x coordinate of the ball
	 * 	@param 	y  the y coordinate of the ball
	 *  @param	ClientHandler  the ClientHandler that sent the x and y coordinates
	 *
	 *	@see ClientHandler#sendCoords(int x, int y)
	 */
	public synchronized void writeToAllExcept(int x, int y, ClientHandler ch)
	{
		int index;
		int size = this.clientHandlers.size();
		for(index = 0; index < size; index++)
		{
			ClientHandler clienth = (ClientHandler)this.clientHandlers.elementAt(index);
			if(clienth != ch)
			{
				clienth.sendCoords(x, y);
				System.out.println("Server sending coordinates");
			}
		}
	}
	
	/**
	 *	Method to send one int to all the clients, used to send player ID to Clients.  Sends information to all ClientHandlers.
	 *	Sent by the ClientHandler that 
	 *	Uses ClientHandler's send(int i) method.
	 *
	 *	@param i  any integer that should be sent to all ClientHandlers
	 *	@param ClientHandler  the ClientHandler that should send the data, generally the one that produced the number
	 *
	 *	@see ClientHandler#send(int i)
	 */
	public synchronized void writeOneInt(int i, ClientHandler ch)
	{
		ch.send(i);
		System.out.println("Server sending one int");
	}
	
	/**
	 *	Method to send one int to all the clients except client that generated the int.
	 *	Not sent to ClientHandler passed in as a parameter, which is meant to be the ClientHandler whose client is sending the int.
	 *	Uses ClientHandler's send(int i) method.
	 *
	 *	@param i  any integer that should be sent to other players
	 *	@param ClientHandler  the ClientHandler that sent the data and should be excluded from being sent this information again
	 *
	 *	@see ClientHandler#send(int i)
	 */
	public synchronized void writeOne(int i, ClientHandler ch)
	{
		int index;
		int size = this.clientHandlers.size();
		for(index = 0; index < size; index++)
		{
			ClientHandler clienth = (ClientHandler)this.clientHandlers.elementAt(index);
			if(clienth != ch)
			{
				clienth.send(i);
				System.out.println("Server sending one");
			}	
		}
	}
		
	/**
	 *	Method to remove the ClientHandler specified as a parameter from the vector of ClientHandlers.
	 */
	public void removeClientHandler(ClientHandler ch) 
	{
		this.clientHandlers.removeElement(ch);
	}
	
}		
	
