//
// serveur de requete
//

import java.io.*;
import java.net.*;

public class Serveur1001b extends Thread{
    public final static int DEFAULT_PORT = 6789;
    protected int port;
    protected ServerSocket listen_socket;
  int nbJMax=2; // le nombre de joueurs max
  int nbJCon=0; // le nombre de joueurs connectes
  int nbj=0;
   int idJoueur=0; // le joueur courant
  Socket jSocket[]      = new Socket[4]; // la connection au joueur
  DataInputStream in[]  = new DataInputStream[4]; // flux d'entree
  PrintStream out[]     = new PrintStream[4];     // flux de sortie
  String pseudo[]       = new String[4]; //les pseudo
  int inPlay=0; // >1 quand une partie est en cours
    
  Partie partie=new Partie(); // les regles du jeu

  static final int NEW_GAME=1, PIOCHE=2, JOUE=3, SUIVANT=4, NO_GAME=5, EXIT=6, CONNECT=7, PIOCHEUR=8, ABANDON=9;
  static final int ALL=-1;

    // Exit with an error message, when an exception occurs.
    public static void fail(Exception e, String msg) {
        System.err.println(msg + ": " +  e);
        System.exit(1);
    }
    
    // Create a ServerSocket to listen for connections on;  start the thread.
    public Serveur1001b(int theport, int player) {
      if (theport == 0) port = DEFAULT_PORT;
      nbJMax=player;
      
      try { 
	listen_socket = new ServerSocket(port); 
	inPlay=CONNECT;
	this.start(); // 
	//System.out.println("Server: listening on port " + port);
	//while (inPlay==CONNECT) this.sleep(1000); // attendre que tout le monde soit connecte 
      }catch (IOException e) { fail(e, "Exception creating server socket"); }
      //catch (InterruptedException e) { fail(e, "sleep error"); }

      
      //Connection c = new Connection(client_socket);
    }
    
    // The body of the server thread.  Loop forever, listening for and
    // accepting connections from clients.  For each connection, 
    // create a Connection object to handle communication through the
    // new Socket.
    public void run() {
      try {
	System.out.println("Server: listening on port " + port);
	while(inPlay==CONNECT){
	  if (nbJCon<nbJMax ) {
	    jSocket[nbJCon] = listen_socket.accept();
	    // flux d'entree/sortie
	    in[nbJCon]  = new DataInputStream(jSocket[nbJCon].getInputStream());
	    out[nbJCon] = new PrintStream(jSocket[nbJCon].getOutputStream());
	    //
	    nbJCon++;
	    System.out.println(nbJCon+" connected of "+nbJMax+" ("+")");
	    if (nbJCon==nbJMax) inPlay=NEW_GAME;// on commence a jouer
	  }//else{
	  this.sleep(1000); // attendre que tout le monde soit connecte 
	  //Socket refused = listen_socket.accept();
	  //System.out.println("Connection refused from : "+refused.getInetAddress().getHostName());
	  //refused.close(); // seulement 4 joueur et pas en cours de partie
	  //}
	  // ceux qui quittent
	  //for (int i=0;i<nbJCon;i++){ System.out.println("Socket "+i+"="+jSocket[i].available());}
	}
      }
      catch (IOException e) { 
	fail(e, "Exception while listening for connections");
      }catch (InterruptedException e) { fail(e, "sleep error"); }

      System.out.println("Tous les joueurs sont connectes.");
      //==================================================================================
      while(inPlay!=EXIT){
	
	//on joue
	//inPlay=NEW_GAME;
	int j; String msg;
	for(;;){
	  j=waitMessage(); msg=getMessage(j);
	  if (msg.equalsIgnoreCase("Quitte")) {
	    System.out.println(pseudo[j]+" quitte!! ->> fin des jeux.");
	    inPlay=EXIT; break;	    
	  }
	  playGame(j,msg);
	}
      }// end while
	  
      System.exit(0);
      
    }// end run()
	      

    // Start the server up, listening on an optionally specified port
    public static void main(String[] args) {
        int port=0,player=0;
	try {
	  if (args.length == 1) {
	    player = Integer.parseInt(args[0]); 
	    player = player<2 ? 2 : player;
	    player = player<5 ? player:4;
	    new Serveur1001b(port,player);
	  }else if (args.length == 2) {
            port = Integer.parseInt(args[0]);  
	    player = Integer.parseInt(args[1]); 
	    player = player<2 ? 2 : player;
	    player = player<5 ? player:4;
	    new Serveur1001b(port,player);
	  }

	  
	}catch (NumberFormatException e) {;}
	if(player==0)
	  System.out.println("Syntax error, the good syntax is:\n\n"+
			     "java Serveur1001b [port] nombre_de_joueurs\n\n");
	

    }


  // -------------------------------------------------------- \\


  void playGame(int j, String msg){
   StringBuffer revline;
   int len=0;
   int ind=0;
   String cmd=""; // la commande
   String rep=""; // pour la reponse
   String[] arg=new String[6]; // pour la reponse
 
   if(msg==null)
     inPlay=NO_GAME;
   else{
     // parsing
     ind=msg.indexOf(' ');
     cmd=(ind==-1?msg:msg.substring(0, ind)); // la commande

     if(cmd.equalsIgnoreCase("Abandonne")) // cmd asynchrone
       inPlay=ABANDON;
   }

   switch(inPlay){
   case NEW_GAME:
     // parsing
     //ind=msg.indexOf(' ');
     //cmd=(ind==-1?msg:msg.substring(0, ind)); // la commande
     
     if(cmd.equalsIgnoreCase("NewGame")){
       pseudo[j] = msg.substring(ind+1);// enregitre son pseudo
       System.out.println("Nouvelle partie avec "+pseudo[j]);
       nbj++;
       if(nbj==nbJMax) {
	 System.out.println("Participants enregistres.");
	 // chaqun sait avec qui il joue
	 rep="Joueurs";
	 for(int jj=0;jj<nbJCon;jj++) rep=rep+" "+pseudo[jj];
	 sendTo(ALL,rep);
	 partie.ResetPartie(nbj,pseudo); //---------
	 //distribution des 6 cartes par joueurs
	 
	 for(int jj=0;jj<nbJCon;jj++) {
	   // pioche 6 cartes puis les envoie
	   String[] c=partie.GetCartesJoueur(pseudo[jj]); //---------
	   rep="DistribCartes";
	   for(int i=0;i<6;i++) rep=rep+" "+c[i];
	   sendTo(jj,rep);
	   //sendTo(jj,"DistribCartes roll xtratank flattire stop 200 25");
	 }
	 idJoueur=0; //le premier joueur
	 inPlay=PIOCHEUR;//on passe a l'etape suivante
	 playGame(j,"");
       }
       
     }//else System.out.println("ERR:Joueur:"+j+", etat:"+inPlay+", requete:"+req);
     
     break;
   case ABANDON:
     sendTo(ALL,"Abandonne "+pseudo[j]);
     System.out.println(pseudo[j]+" abandonne!!");
     playGame(j,null);
     break;
   case SUIVANT:
     if(partie.Gagnant(pseudo[idJoueur])) {// joueur gagnant
       sendTo(ALL,"Gagnant "+pseudo[idJoueur]);
       playGame(j,null);
       break;
     }else{ 
       idJoueur=idJoueur+1<nbJCon?idJoueur+1:0; // Joueur suivant
       inPlay=PIOCHEUR;
     }
     //break;
   case PIOCHEUR:
     //System.out.println(pseudo[j]+" : "+msg);
     sendTo(ALL,"Piocheur "+pseudo[idJoueur]);
     inPlay=PIOCHE;
     break;
   case PIOCHE:
     System.out.println(pseudo[j]+" : "+msg);
     // traitement
     if(msg.equalsIgnoreCase("Pioche Nouvelle")){
       sendTo(j,"Carte "+partie.PiocheCarte());
       //sendTo(j,"Carte 75");
     }else { //if(req.equalsIgnoreCase("Pioche Derniere")){
       sendTo(j,"Carte "+partie.PiocheCarteJetee());
       //sendTo(j,"Carte 50");
     }
     inPlay=JOUE;
     break;
   case JOUE:
     System.out.println(pseudo[j]+" : "+msg);
     // parsing
     ind=msg.indexOf(' ');
     cmd=(ind==-1?msg:msg.substring(0, ind)); // la commande
     rep=(ind==-1?"":msg.substring(ind+1));     // les arguments
     ind=rep.indexOf(' ');
     arg[0]=(ind==-1?rep:rep.substring(0,ind));
     arg[1]=(ind==-1?"":rep.substring(ind+1));
     //System.out.println(pseudo[j]+" : "+arg[0],arg[1]);
     // traitement
     if(cmd.equalsIgnoreCase("Joue")){
       if(partie.Transfert(pseudo[j],arg[0],arg[1])){
	 sendTo(ALL,"CarteJouee "+rep);
	 inPlay=SUIVANT; // Next step
	 playGame(j,"");
       }else 
	 sendTo(j,"CarteRefusee "+arg[0]);
     }else if(cmd.equalsIgnoreCase("Jete")){
       partie.JeteCarte(pseudo[j],arg[0]);
       sendTo(ALL,"CarteJetee "+rep);
       inPlay=SUIVANT; // Next step
       playGame(j,"");
     }
     
     break;
   case NO_GAME:
     inPlay=NEW_GAME;
     nbj=0;
     break;
   default:
     System.out.println("Erreur, requete non traitee :Joueur:"+j+", etat:"+inPlay+", requete:"+msg);
   }
   
   
  } // void playGame(...)

  int waitMessage(){
    int j=0;
    try {
      while(true){
	for(j=0;j<nbJCon;j++) { // pour chaque joueur connecte
	  // read in a line
	  if(in[j].available()<0){System.out.println("not available on "+j);}
	  if(in[j].available()>0) return j;
	}
	
      }
      //System.out.println("fin du jeu");
    }catch (IOException e) { try{jSocket[j].close();}catch(Exception e2){;} }
    //finally { ; }
    return 0;
  }  

  String getMessage(int j){
    try {
      String line = in[j].readLine();
      if (line == null) System.out.println("bye bye "+j);
      else return line;
    }catch (IOException e) {try{jSocket[j].close();}catch(Exception e2){;} }
    return "";
  }

  void sendTo(int j, String msg){
    if(j==-1){ //broadcast
      for(int jj=0;jj<nbJCon;jj++) out[jj].println(msg);
    }else{
      out[j].println(msg);
    }
  }


}// fin
