/*
* (c) 2000-2009 Carlos G�mez Rodr�guez, todos los derechos reservados / all rights reserved.
* Licencia en license/bsd.txt / License in license/bsd.txt
*/
package eu.irreality.age;
import java.util.*;
import java.net.*;
import java.io.*;
import eu.irreality.age.debug.Debug;
import eu.irreality.age.server.PartidaEnCurso;
//<extends ClientHandler extends Thread?>
public class AGEClientHandler extends Thread {
private static Vector activeClients;
private int maxClients;
private List /*of PartidaEnCurso*/ partidas;
int clientCount;
private short thePort;
public AGEClientHandler( short port )
{
Debug.println("AGEClientHandler started.");
partidas = new Vector();
thePort = port;
setPriority(Thread.MIN_PRIORITY);
start();
}
public AGEClientHandler ( World w , int maxPlayers , short port )
{
Debug.println("AGEClientHandler started.");
thePort = port;
partidas = new Vector();
addPartida ( new PartidaEnCurso ( w , maxPlayers , "Nombre de Partida" , null ) );
maxClients = maxPlayers;
setPriority(Thread.MIN_PRIORITY);
start();
}
//begin: from ClientHandler <create?>
public synchronized void addPartida ( PartidaEnCurso pec )
{
Debug.println("ADDDDDDDDDDDDING GAME");
partidas.add ( pec );
}
public synchronized int getClientCount()
{
return clientCount;
}
public synchronized void incClientCount()
{
clientCount++;
}
public synchronized int getAndIncClientCount()
{
clientCount++;
return ( clientCount-1 );
}
//coge las partidas en curso, protegida de accesos concurrentes
public synchronized List getPartidasEnCurso()
{
Vector result = new Vector();
for ( int i = 0 ; i < partidas.size() ; i++ )
{
result.add ( partidas.get(i) );
}
return result;
}
//end: from ClientHandler <create?>
public void run()
{
activeClients = new Vector();
clientCount = 1;
try
{
ServerSocket s = new ServerSocket ( thePort );
for (;;)
{
final Socket incoming = s.accept();
//hacer un fork, porque la selecci�n de mundo, etc. tiene esperas, y mientras tenemos que poder atender a otros clientes
Thread th = new Thread()
{
public void run()
{
int ccount = getAndIncClientCount(); //synchronized
Debug.println("Spawnin' client proxy " + ccount );
AGEClientSelector acs = new AGEClientSelector ( incoming , ccount );
World mundo = acs.getPartidaSelection( getPartidasEnCurso() ).getMundo();
AGEClientProxy stpc = new AGEClientProxy ( incoming ); //world passed @ bindToWorld()
stpc.bindToWorld ( mundo );
activeClients.addElement ( stpc );
}
};
th.start();
}
}
catch (IOException ioe )
{
System.err.println("Exception on accepting socket.\n");
ioe.printStackTrace();
}
}
}
//obtiene las opciones del cliente. <extends ClientSelector?>
class AGEClientSelector implements ARSPConstants
{
private InputStream is;
private OutputStream os;
private BufferedReader in;
private PrintWriter out;
private Socket incoming;
private int id;
public AGEClientSelector ( java.net.Socket s , int id )
{
this.incoming = s;
this.id = id;
try
{
if (incoming != null)
{
in = new BufferedReader(new InputStreamReader((is=incoming.getInputStream())));
out = new PrintWriter(new OutputStreamWriter((os=incoming.getOutputStream())))
{
public void println(String linea)
{
print(linea);
print("\r\n");
}
}
;
}
}
catch (Exception e)
{
System.err.println("Error: " + e);
}
}
public void escribir ( String s )
{
if ( out != null )
{
Debug.print("Systemoutprinting:"+s);
//print with LF -> CRLF substitution!
//not in AGE client.
//out.print( StringMethods.textualSubstitution ( s , "\n" , "\r\n" ) );
out.print ( s );
out.flush();
}
}
//selector input is always synchronous.
public String getInput ( )
{
try
{
//escribir("> ");
String str = in.readLine();
Debug.println("INPUT GOTTEN: " + str );
return str;
}
catch ( IOException ioe )
{
ioe.printStackTrace();
return null;
}
}
//Do all the protocol stuff until player selects a game.
//Null if failed.
public PartidaEnCurso getPartidaSelection( List partidas )
{
String str;
try
{
str = in.readLine();
}
catch ( IOException ioe )
{
System.err.println(ioe);ioe.printStackTrace();
return null;
}
StringTokenizer st = new StringTokenizer ( str );
String head = st.nextToken();
if ( head.equalsIgnoreCase ( PROTOCOL_VERSION_STATEMENT ) )
{
Debug.println("Version stated.");
String tail = st.nextToken("").trim();
Debug.println("Cola: " + tail);
if ( tail.equalsIgnoreCase("1.0") )
{
out.println ( PROTOCOL_VERSION_ACK + " OK" );
out.flush();
}
else
{
out.println ( PROTOCOL_VERSION_ACK + " NOK" );
return null;
}
}
else
{
out.println( UNRECOGNIZED_MESSAGE + str );
out.println( SERVER_STATE + " expecting " + PROTOCOL_VERSION_STATEMENT );
return null;
}
//Protocol version recognized.
//Now expect commands.
boolean terminamos = false;
while ( !terminamos )
{
try
{
str = in.readLine();
if ( str == null )
{
(new Exception("Received null input.")).printStackTrace();
return null;
}
}
catch ( IOException ioe )
{
Debug.println(ioe);ioe.printStackTrace();
return null;
}
st = new StringTokenizer ( str );
String cmd=null;
if ( st.hasMoreTokens() ) cmd = st.nextToken();
String args = null;
if ( st.hasMoreTokens() ) args = st.nextToken("").trim();
if ( cmd == null )
{
//out.println( UNRECOGNIZED_MESSAGE + " " + "Null command received.");
continue;
}
else if ( cmd.equalsIgnoreCase( GOODBYE ) )
{
out.println ( GOODBYE );
return null;
}
else if ( cmd.equalsIgnoreCase ( SERVICE_LIST_REQUEST ) )
{
out.println ( SERVICE_LIST_BEGIN );
out.println ( SERVICE_LIST_LINE + " gamelist" );
out.println ( SERVICE_LIST_LINE + " gamejoin" );
out.println ( SERVICE_LIST_END );
}
else if ( cmd.equalsIgnoreCase ( CALL_SERVICE ) )
{
StringTokenizer st2 = new StringTokenizer ( args );
String servName = st2.nextToken();
if ( servName.equalsIgnoreCase ( "gamelist" ) )
{
//output game list
out.println ( GAME_LIST_BEGIN );
for ( int i = 0 ; i < partidas.size() ; i++ )
{
PartidaEnCurso pec = (PartidaEnCurso) partidas.get(i);
//current format: id. name (pl/pl)
out.println ( GAME_LIST_LINE + " " + (i+1) + ". " + pec.getNombre() + " " + "(" + pec.getPlayers() + "/" + pec.getMaxPlayers() + ")" );
}
out.println ( GAME_LIST_END );
}
else if ( servName.equalsIgnoreCase ( "gamejoin" ) )
{
String id = st2.nextToken();
int part = -1;
try
{
part = Integer.valueOf ( id ).intValue();
Debug.println("Part: " + part);
}
catch ( NumberFormatException nfe )
{
;
}
if ( part > 0 && part <= partidas.size() )
{
PartidaEnCurso p = (PartidaEnCurso) partidas.get(part-1);
if ( p.getPlayers() < p.getMaxPlayers() )
{
Debug.println("Returning game.");
return p;
}
else
out.println( ERRORMSG + " Esa partida ha alcanzado su n�mero m�ximo de usuarios, no puedes entrar.\n");
}
else
{
out.println( ERRORMSG + " ID incorrecta" );
}
} //end service gamejoin
else
{
out.println( UNSUPPORTED_SERVICE + " " + servName );
} //end unknown service
} //end if callservice
else
{
out.println ( UNRECOGNIZED_MESSAGE + " " + str );
}
out.flush();
} //end while (command-processing) loop
return null;
} //end function
}