

public class Partie {

  // jeux de carte des Milles bornes
  Jeux jeux;

  // les deux pioches
  Pioche pioche; // contiendra, des le depart, ttes les cartes du jeux
  Pioche pioche_jetee; // contiendra les cartes jetees par les joueurs

  // les joueurs
  int n_joueurs; // nombre de joueurs
  int joueur_courant = 1; // joueur courant
  Joueur joueurs[]; // contient les objets joueurs

  // constructeur
  public Partie( ) {
    System.out.println("[Partie::Partie]");
    // creation du jeux de cartes
    jeux = new Jeux();
  }

  // initialise une partie
  public void ResetPartie( int nbre_joueurs, String[] nom_joueurs ) {
    System.out.println("[Partie::ResetPartie("+nbre_joueurs+")]");
    // creation des pioches
       pioche = new Pioche( jeux );  // la pioche est creee a partir d'un jeu
       pioche_jetee = new Pioche();  // la pioche ne contient aucune carte
    // creation des joueurs
       n_joueurs = nbre_joueurs;
       joueurs = new Joueur[ n_joueurs + 1 ];
       for ( int i=0 ; i < n_joueurs ; i++ )
	 joueurs[i] = new Joueur( nom_joueurs[i] );
       joueurs[ n_joueurs ] = null;
    // distribution des 6 premieres cartes a chacun des joueurs
       for ( int i=0 ; i < 6 ; i++ )
	 for ( int j=0 ; j < n_joueurs ; j++ )
	   joueurs[ j ].RecoitCarte( pioche.GetCarte() );
  }


  // retourne le nom de chacun des joueurs
  public String[] GetNomsJoueurs( ) {
    String[] NomsJoueurs = new String[ n_joueurs + 1 ];
    for ( int i=0; i < n_joueurs ; i++ )
      NomsJoueurs[ i ] = joueurs[i].GetPseudo();
    NomsJoueurs[ n_joueurs ] = null;
    return NomsJoueurs;
  }



  // retourne les cartes possedees par le joueur
  int GetNoJoueur( String Pseudo ) {
    for ( int i=0 ; i < n_joueurs ; i++ )
      if ( Pseudo.compareTo( joueurs[i].GetPseudo() ) == 0 )
	return i;
    return -1; // le joueur n'est pas trouve ???
  }
  public String[] GetAtoutsJoueur( String Pseudo ) {
    return  joueurs[ GetNoJoueur( Pseudo ) ].GetAtouts();
  }
  public String[] GetKMJoueur( String Pseudo ) {
    return  joueurs[ GetNoJoueur( Pseudo ) ].GetCollectionKM();
  }
  public String GetHandicapJoueur( String Pseudo ) {
    return  joueurs[ GetNoJoueur( Pseudo ) ].GetHandicap();
  }
  public String[] GetCartesJoueur( String Pseudo ) {
    return  joueurs[ GetNoJoueur( Pseudo ) ].GetCartes();
  }


  // methode pour stopper ou demarrer un joueur
  public boolean IsStopped( String Pseudo ) {
    return ( joueurs[ GetNoJoueur( Pseudo ) ].IsStopped() );
  }
  public void Stopper( String Pseudo ) {
    joueurs[ GetNoJoueur( Pseudo ) ].Stopper();
  }
  public void Rouler( String Pseudo ) {
    joueurs[ GetNoJoueur( Pseudo ) ].Rouler();
  }

  
  /*
    Essaye de transferer la carte nomCarte possedee par le joueur j1 vers le joueur j2
    Si j1 != j2
      la carte doit etre une carte de type Handicap
    Si j1 == j2
      un joueur ne peut que se rajouter un atout/KM dont il dispose ds ses cartes
  */
  public boolean Transfert( String PseudoJ1, String nomCarte, String PseudoJ2 ) {
    System.out.print("[Partie::Transfert("+PseudoJ1+","+nomCarte+","+PseudoJ2+")]");
    Joueur j1 = joueurs[ GetNoJoueur( PseudoJ1 ) ];
    Joueur j2 = joueurs[ GetNoJoueur( PseudoJ2 ) ];
    System.out.println("de "+j1+" a "+j2);
    if ( j1 == j2 ) { // il s'agit du meme joueur
      if ( jeux.EstUnAtout( nomCarte ) ) { // qui veut s'ajouter un Atout
	j1.JouerCarte( nomCarte );
	j1.NouvelAtout( nomCarte );
	// teste si l'atout enleve l'handicap du joueur (si j1 a un handicape)
	if ( j1.IsHandicaped() )
	  if ( jeux.AtoutEstSolution( nomCarte, j1.GetHandicap() ) ) // leve l'handicap
	    j1.LeveHandicap();
	// cas du RIGHT WAY qui leve le feux rouge
	if ( j1.IsStopped() && nomCarte.compareTo( "rightway" ) == 0 )
	  j1.Rouler();
	return true;
      }
      int valCarte = jeux.GetValeurCarte( nomCarte );
      if ( ( ! j1.IsStopped() )  && ( valCarte > 0 ) ) { // qui veut s'ajouter une carte KM
	// J1 peut-il se rajouter une carte Kilometrique ?
	if ( j1.IsHandicaped() ) {// le joueur a un handicap
	  if ( (j1.GetHandicap()).compareTo( "spdlimit" ) == 0 ) {// il est limite a 50
	    if ( valCarte > 50 )
	      return false; // non,  J1 ne peut pas depasser 50 Km/h
	  } else // le joueur handicape ne peut pas se deplacer
	    return false;
	}
	// une autre regle, mais qui bloque trop le jeu :
	//  if ( ( j1.GetScore() + valCarte ) > 1000 ) // ne pas depasser 1000 km !!!
	//     return false;

	// J1 peut jouer sa carte
	j1.JouerCarte( nomCarte );
	j1.NouveauKM( nomCarte, valCarte );
	return true;
      }
      if ( jeux.EstUnFeuxVert( nomCarte ) ) { // qui veut s'ajouter un feu vert
	if ( j1.IsHandicaped() ) // J1 doit d'abord lever son handicap
	  return false;
	if ( j1.IsStopped() ) {
	  j1.JouerCarte( nomCarte );
	  j1.Rouler();
	  return true;
	}
      }
      if ( jeux.EstSolution( nomCarte ) ) { // qui veut lever son handicap
	if ( j1.IsHandicaped() ) // et J1 a un handicape
	  if ( jeux.LeveHandicap( j1.GetHandicap(), nomCarte ) ) {
	    j1.JouerCarte( nomCarte );
	    j1.LeveHandicap();
	    return true;
	  }
      }
    } else { // j1 ---> Carte ---> j2
      if ( jeux.EstUnHandicap( nomCarte ) ) { // j1 veut handicaper j2
	if ( j2.IsStopped() ) // j2 est stoppe, on ne peut pas l'handicaper
	  return false;
	if ( j2.IsHandicaped() ) { // j2 est deja handicape
	  if ( (j2.GetHandicap()).compareTo( "spdlimit" ) != 0 ) // son handicap n'est pas speed limit
	    return false;
	  if ( nomCarte.compareTo( "spdlimit" ) == 0 ) // le nouvel handicap est aussi speed limit : pas possible
	    return false;
	}
	// enfin, peut-on handicaper avec les atouts que possede j2 ?
	if ( ! jeux.Handicaper( nomCarte, j2.GetAtouts() ) )
	  return false;
	j1.JouerCarte( nomCarte );
	j2.Handicape( nomCarte );
	return true;
      }
      if ( jeux.EstUnStop( nomCarte ) ) { // j1 veut STOPPER j2
	if ( ! j2.IsStopped() ) { // j2 n'est pas deja stoppe
	  // teste le cas du STOP alors que j2 possede l'atout RIGHT WAY
	  String[] AtoutsJ2 = j2.GetAtouts();
	  for( int i=0 ; AtoutsJ2[ i ] != null ; i++ )
	    if ( AtoutsJ2[ i ].compareTo( "rightway" ) == 0 )
	      return false;
	  if ( j2.IsHandicaped() && (j2.GetHandicap()).compareTo( "spdlimit" ) != 0 )
	    return false;
	  else
	    j2.LeveHandicap();
	  j1.JouerCarte( nomCarte );
	  j2.Stopper();
	  return true;
	}
      }
    }
    return false;
  }



  // le joueur jette une carte ds la pioche_jetee
  public void JeteCarte( String Pseudo, String nomCarte ) {
    System.out.println("[Partie::JeteCarte(" +Pseudo+" , "+nomCarte+" )]");
    joueurs[ GetNoJoueur( Pseudo ) ].JouerCarte( nomCarte );
    pioche_jetee.AjouteCarte( nomCarte );
  }



  // pioche une carte (dans la pioche normale)
  // s'il ne reste plus de carte, alors il y a transvasement des 2 pioches
  public String PiocheCarte( ) {
    if ( pioche.EstVide() ) { // il faut regenerer la pioche
      pioche = new Pioche( jeux );
      pioche_jetee = new Pioche();
      System.out.println("Pioche vide => Pioche regeneree");
    }
    return pioche.GetCarte();
  }

  // prend la derniere carte jetee (ds la pioche_jetee)
  public String PiocheCarteJetee( ) {
    return pioche_jetee.GetDerniereCarteAjoutee();
  }


  // teste si le joueur  a comptabilise les 1000 points
  public boolean Gagnant( String Pseudo ) {
    return (  joueurs[ GetNoJoueur( Pseudo ) ].GetScore() >= 1000 );
  }


  // retourne l'objet carte associe au nomCarte
  public Carte GetCarte( String nomCarte ) {
    return jeux.GetCarte( nomCarte );
  }


  // debuggage : teste les composants d'une Partie
  public void Debug( ) {
    System.out.println("[Partie::Debug]");
    System.out.println(" Le jeux de carte (ordre de creation) : ");
    jeux.Debug();
    System.out.println(" Les cartes retirees de la pioche (ordre aleatoire) :");
    pioche.Debug();
    System.out.println(" Test des concordances entre types de cartes :");
    {
      System.out.print("Handicaper  punc_prf drv_ace rightway  avec  outofgaz ??? :");
      String Atouts[] = { "punc_prf","drv_ace","rightway", null };
      System.out.println( jeux.Handicaper( "outofgaz",  Atouts ) );
    }
    {
      System.out.print("Handicaper  punc_prf drv_ace xtratank rightway  avec  outofgaz ??? :");
      String Atouts[] = { "punc_prf","drv_ace","rightway", "xtratank", null };
      System.out.println( jeux.Handicaper( "outofgaz",  Atouts ) );
    }
    System.out.print("Lever handicap flattire avec spartire ??? :");
    System.out.println( jeux.LeveHandicap( "flattire",  "spartire" ) );
  }

  
  // prog principal
  public static void main(String argv[]) {
    String[] NonJoueurs = { "Gilles", "Laurent" };
    Partie p = new Partie();
    p.ResetPartie( 2, NonJoueurs );
    System.out.println(" Fin du test d'une partie ");
    p.Debug();
  }

}

