/*
 * Created on Apr 9, 2005
 *
 */

/**
 * @author Nicole Sullivan
 */
public class JoueurProgramme {
	//===============================================================
	//  variables d'instance
	//===============================================================	
	int round;
	PaquetDeCartes Plis = new PaquetDeCartes();
	static Couleur trump;
	PaquetDeCartes monPaquet;
	boolean jePrend;
	boolean campPrend;
	//===============================================================
	//  the constructor
	//===============================================================	
	public JoueurProgramme(){
		this.monPaquet = new PaquetDeCartes();
		this.jePrend = false;
		this.campPrend = false;
		this.round = 0;
	}
	//===============================================================
	//  methods - as defined by prof.
	//===============================================================	
	
	//  adds a card to the players hand
	//  c: card to add
	void recoitCarte(Carte c){
		this.monPaquet.ajoute(c);
	}
	//  Returns true if the player wants to take the trump in the first round
	boolean prend1erTour(Carte carteRetournee){
		if (Arbitre.comptePointsPaquet(this.monPaquet, carteRetournee.couleur)> 23){
			this.jePrend = true;
			Terminal.ecrireStringln("The trump is " + carteRetournee.couleur.nom);
			return true;
		}else{
			return false;
		}
	}
	
	//  Returns true if the player wants to take the trump in the second round
	//  sets the variable choix to indicate what the player would like the trump to be
	//  carteRetournee: potential trump card
	//  choix: couleur the player would like the trump to be
	boolean prend2ndTour(Carte carteRetournee, Couleur choix){
		String [] couleurs = {"Coeur", "Pique", "Carreau", "Trefle"};
		//  Determine most advantageous trump color (choix)
		int color = -1;
		int maxPoints = -1;
		for (int c=0; c<4; c++){
			int currentPoints = Arbitre.comptePointsPaquet(this.monPaquet, new Couleur(couleurs[c]));
			if (currentPoints > maxPoints){
				maxPoints = currentPoints;
				color = c;
			}
		}
		choix.nom = couleurs[color];
		//  If the hand is worth more than 20 take the trump, otherwise not.
		if (Arbitre.comptePointsPaquet(this.monPaquet, choix) > 20){
			this.jePrend = true;
			Terminal.ecrireStringln("The trump is " + choix.nom);
			return true;
		}else{
			return false;
		}
	}
	//  tells the player what the trump card is
	//  c1: trump couleur
	//  partenairePrend: true if players partner has chosen to take the trump
	void informeAtout(Couleur c1, boolean partenairePrend){
		trump = c1;
		if (partenairePrend){
			this.campPrend = true;
		}
	}
	//  Informs the players of previously played 
	//  cards, waits to allow time for the user to see cards.!!!
	//  tapis: cards already played
	void informePlisJouee(PaquetDeCartes tapis){
		for (int c=0; c<4; c++){
			Plis.ajoute(tapis.lesCartes[c]);
		}
	}
	//  Returns the card the player would like to play if they start the round.  Random for now.
	Carte carteJoueEnPremier(){
		int x = (int)Math.round(Math.random()* (this.monPaquet.longueur-1));
		return this.monPaquet.prendIeme(x);
	}
	//  Returns the card the player would like to play
	//  tapis: cards already played
	Carte carteJouee(PaquetDeCartes tapis){
		//  If trump has NOT been thrown
		if (!(trumpThrown(tapis))){
			if (haveMatchingCouleur(tapis)){
				//  play card which matches first card thrown
				if (canWin(tapis)){
					//  play lowest winning card
					Terminal.ecrireString(" using method 1, ");
					return playLowestWinning(tapis);
				}else{
					Terminal.ecrireString(" using method 2, ");
					return lowestCard();
				}
			}else if(this.monPaquet.haveTrump(trump)){
				//  play a trump card
				if (canWin(tapis)){
					//  play lowest winning trump
					Terminal.ecrireString(" using method 3, ");
					return playLowestWinningTrump(tapis);
				}else{
					Terminal.ecrireString(" using method 4, ");
					return lowestCard();
				}
			}else{
				//  play lowest card in hand
				Terminal.ecrireString(" using method 5, ");
				return lowestCard();
			}
				
			}
		//  If a trump has been thrown
		else if (this.monPaquet.haveTrump(trump)){
			//  play a trump card
			if (canWin(tapis)){
				//  play lowest winning trump
				Terminal.ecrireString(" using method 6, ");
				return playLowestWinningTrump(tapis);
			}else{
				Terminal.ecrireString(" using method 7, ");
				return lowestCard();
			}
		}else {
			//  play lowest card in hand
			Terminal.ecrireString(" using method 8, ");
			return lowestCard();
		}
	}
	//================================================================
	//  LOGIC / TESTS 
	//================================================================
	
	//  Determine if a trump card has already been thrown.
	//  tapis: cards already played
	boolean trumpThrown(PaquetDeCartes tapis){
		for (int c=0; c<tapis.longueur; c++){
			if (tapis.lesCartes[c].couleur.nom == trump.nom){
				return true;
			}
		}return false;
	}
	//  Determine if player has a card matching the couleur of the first card thrown
	//  tapis: cards already played
	boolean haveMatchingCouleur(PaquetDeCartes tapis){
		for (int c=0; c<this.monPaquet.longueur; c++){
			if (this.monPaquet.lesCartes[c].couleur.nom == tapis.lesCartes[0].couleur.nom){
				return true;
			}
		}return false;
	}
	/*
	 * Moved to PQDeCartes
	 * //  Determine if player has a trump
	boolean haveTrump(){
		for (int c=0; c<this.monPaquet.longueur; c++){
			if (this.monPaquet.lesCartes[c].couleur.nom == trump.nom){
				return true;
			}
		}return false;
	}*/
	// Find lowest card in the hand
	Carte lowestCard(){
		int lowest = 0;
		for (int c=1; c<this.monPaquet.longueur-1; c++){
			if (Arbitre.pointsCarte(this.monPaquet.lesCartes[c-1], trump) > Arbitre.pointsCarte(this.monPaquet.lesCartes[c], trump)){
				 lowest = c;
			}
		}return this.monPaquet.lesCartes[lowest];
	}
	//  determine if player has a card in his hand that can beat those already thrown
	boolean canWin(PaquetDeCartes tapis){
		
		int myMax = Arbitre.pointsCarte(this.monPaquet.lesCartes[this.monPaquet.highestCard(trump)], trump);
		for (int i=0; i<tapis.longueur; i++){
			if (myMax > Arbitre.pointsCarte(tapis.lesCartes[i], trump)){
				return true;
			}
		}
		return false;
	}

	//  play lowest winning card
	//  tapis: cards already played
	Carte playLowestWinning(PaquetDeCartes tapis){
		int [] winners = new int[8];//8 max potential cards in hand when this function is called.
		int counter = 0;
		int chosenCardNo = 0;
		for (int c=0; c<this.monPaquet.longueur; c++){
			if (winningCard(tapis, this.monPaquet.lesCartes[c])){
				winners[counter] = c;
				counter++;
			}
		}
		int pointsFromWinningCard = -1;
		for (int winTab=0; winTab<winners.length-1; winTab++){	
			int pointsFromCurrentCard = Arbitre.pointsCarte(this.monPaquet.lesCartes[winners[winTab]], trump);
			if (pointsFromCurrentCard > pointsFromWinningCard){
				chosenCardNo = winners[winTab];
			}
		}return this.monPaquet.lesCartes[chosenCardNo];
	}
	//  Determine if a card can win
	//  tapis: cards already played
	//  card: the card you are verifying can win or not
	boolean winningCard(PaquetDeCartes tapis, Carte card){
		int pointsCard = Arbitre.pointsCarte(card, trump);
		int pointsHighestCardThrown = Arbitre.pointsCarte(tapis.lesCartes[tapis.highestCard(trump)], trump);
		if (pointsCard > pointsHighestCardThrown){
			return true;
		}else {
			return false;
		}
	}
	//================================================================
	//   Choosing card to play - methods called by carteJouee
	//================================================================
	/*
	 * dernier etape, ce functions prend le plus bas qui gagne
	 */
	//  returns the lowest winning Trump card
	//  tapis: cards already played
	Carte playLowestWinningTrump(PaquetDeCartes tapis){
		return extractLowest(extractWinners(this.extractTrump(), tapis));
	}
	//  returns the lowest winning card that matches the first card played
	//  tapis: cards already played
	Carte playLowestWinningMatch(PaquetDeCartes tapis){
		return extractLowest(extractWinners(this.extractMatching(tapis.lesCartes[0]), tapis));
	}
	//================================================================
	/*
	 *   Premier etape, ce functions prend les carte qui sont meme couleur 
	 * 	 que l'atout ou le premier carte
	 */
	
	//  Removes all the trumps from a players hand and puts them in another pack
	PaquetDeCartes extractTrump(){
		PaquetDeCartes p2 = new PaquetDeCartes();
		for (int c=0; c<this.monPaquet.longueur; c++){
			if (this.monPaquet.lesCartes[c].couleur.nom == trump.nom){
				p2.ajoute(this.monPaquet.prendIeme(c));
			}
		}return p2;
	}
	//  extracts the cards that match the first card thrown
	//  firstPlayed: first card on the tapis
	PaquetDeCartes extractMatching(Carte firstPlayed){
		PaquetDeCartes p2 = new PaquetDeCartes();
		for (int c=0; c<this.monPaquet.longueur; c++){
			if (this.monPaquet.lesCartes[c].couleur.nom == firstPlayed.couleur.nom){
				p2.ajoute(this.monPaquet.prendIeme(c));
			}
		}return p2;
	}
	//================================================================
	/*
	 *   2nd etape, ce function extrait les cartes qui sont assez fort 
	 *   a gagner
	 */
	//  Extracts winning cards from the PQDeCartes p2
	//  p2: hand
	//  tapis: cards already played
	PaquetDeCartes extractWinners(PaquetDeCartes p2, PaquetDeCartes tapis){
		if (p2.longueur>2){
			return p2;
		}else{
			PaquetDeCartes p3 = new PaquetDeCartes();
			int x = this.monPaquet.highestCard(trump);
			if (x == -1){
				p3.ajoute(p2.prendIeme(0));
			} else {
			
				int maxTapis = Arbitre.pointsCarte(this.monPaquet.lesCartes[x], trump);
				for (int c=0; c<p2.longueur; c++){
					//  put all cards that win into p3
					if (Arbitre.pointsCarte(this.monPaquet.lesCartes[c], trump) > maxTapis){
						p3.ajoute(p2.prendIeme(c));
					}
				}
			}	
			for (int c=0; c<p2.longueur; c++){
				//  Put unused cards back in players hand
				this.monPaquet.ajoute(p2.lesCartes[c]);
			}
			return p3;
		}	
	}

	/*
	 *   Dernier etape, ce function trouve le plus bas des cartes dans
	 *   une paquet  -- utilizer pour trouver le plus bas de ce qui sont assez
	 *   fort a gagner
	 */
	
	//  returns the lowest card in a players hand.
	//  p3: the pack/hand
	Carte extractLowest(PaquetDeCartes p3){
		int lowestScore = 9999;
		int lowestCard = -1;
		for (int c=0; c<p3.longueur; c++){
			int currentScore = Arbitre.pointsCarte(p3.lesCartes[c], trump);
			if (currentScore < lowestScore){
				 lowestCard = c;
				 lowestScore = currentScore; 
			}
		}
		for (int c=0; c<p3.longueur; c++){
			//  Put unused cards back in players hand
			this.monPaquet.ajoute(p3.lesCartes[c]);
		}
		if (lowestCard >= 0){
			return p3.lesCartes[lowestCard];
		}else return this.monPaquet.prendIeme(0);
		
	}
}
