/*******************************************************************************
Program:			Concentration

Author:				Rebecca Hasti, hasti@cs.wisc.edu
					copyright 2000, all rights reserved
Course:				CS 302, Summer 2000

Compiler:			Metrowerks CodeWarrior (JDK 1.2)
Platform:			Windows NT 4.0 (or Windows 95)
*******************************************************************************/

import java.io.*;

/**
 * This program plays a game of concentration (aka memory) for two players.
 *
 * Bugs: none known
 **/
public class Concentration {

	private static BufferedReader stdin; // for console input
	private static Board board;          // the playing board

	public static void main(String args[]) throws IOException {
	
		String player1Name, player2Name, line;
		int player1 = 0, player2 = 0;
		
		// Get the players' names
		
		stdin = new BufferedReader(new InputStreamReader(System.in));
		System.out.print("Enter player 1's name: ");
		player1Name = stdin.readLine();
		System.out.print("Enter player 2's name: ");
		player2Name = stdin.readLine();
		
		// Set up the board
		
		Card.setGraphicSuit(true);
		board = new Board();
		System.out.print(board);
		
		// Give each player a turn until all the cards have been removed
		// from the board.
		
		do {
			player1 += playerTurn(player1Name);
			player2 += playerTurn(player2Name);
		} while (!board.isEmpty());
		
		// Print out final results
		
		System.out.println(player1Name + " finished with " + player1 + 
		                   " matches.");
		System.out.println(player2Name + " finished with " + player2 + 
		                   " matches.");
	}
	
	/**
	 * Completes one turn for the player whose name is given.  During a turn,
	 * the player is prompted for the location of two cards.  These cards are
	 * flipped over and if they match, the cards are removed from the board,
	 * the player earns one point, and the player chooses two more cards.
	 * The total number of points earned during the turn is returned.
	 *  
	 * @param name the name of the player
	 * @return number of points earned during this turn
	 **/
	private static int playerTurn(String name) throws IOException {
		int points = 0;
		boolean goAgain = false;
		GameCard card1, card2;
		
		System.out.println(name + "'s Turn");
		do {
		
			// Select and flip over the first card
			card1 = selectCard();
			card1.flip();
			System.out.print(board);
			
			// Select the second card, make sure it's not the same card as the
			// first card, and flip it over
			card2 = selectCard();
			while (card1.equals(card2)) { 
				System.out.println("You cannot select the same card twice");
				card2 = selectCard();
			}
			card2.flip();
			System.out.print(board);
		
			// If there is a match, remove the cards from the board and let the
			// player go again
			if (match(card1, card2)) {
				System.out.println("Match -- go again");
				stdin.readLine();  // wait for user to hit enter
				points++;
				board.removeCard(card1);
				board.removeCard(card2);
				goAgain = true;
			}
			
			// If there is not a match, flip the cards back over and
			// end the turn
			else {
				System.out.println("No match -- turn over");
				stdin.readLine();  // wait for user to hit enter
				card1.flip();
				card2.flip();				
				goAgain = false;
			}
			
			System.out.print(board);
			
		} while (goAgain);
		
		return points; // return the number of matches made during this turn
	}
	
	/** 
	 * Returns true if the two cards match and false otherwise.
	 * Two cards match if they have the same face value and the same suit color.
	 *
	 * @param card1,card2  the cards to compare 
	 * @return true if the cards match, false otherwise
	 **/
	public static boolean match(GameCard card1, GameCard card2) {
		return (card1.getFace() == card2.getFace() && 
		        card1.getSuitColor() == card2.getSuitColor());
		        
		// An alternative matching strategy that makes it easier to get
		// matches quickly.  Useful for debugging.
		//return (card1.getSuit() == card2.getSuit()); 
	}
	
	/**
	 * Prompts the user for a row and column and returns the card in that
	 * position on the board.  If the user tries to select a card in an
	 * invalid position (i.e. off the board) or in an empty spot (i.e. there
	 * is no card in that position on the board), the user is prompted for
	 * a new position.
	 *
	 * The method also checks to make sure the user enters integer values
	 * for the row and column numbers and re-prompts until integer values
	 * have been entered.
	 *
	 * @return a card chosen by the user (null if the board is empty)
	 **/
	private static GameCard selectCard() throws IOException {
		int row = 0, col = 0;
		GameCard card = null;
		boolean askAgain = true, badValue;
	
		// If there are no cards on the board, nothing can be selected
		if (board.isEmpty())  return null;
		
		do {
			
			// Get the row number from the user
			do {
				try {
					System.out.print("\tChoose card: row ");
					row = Integer.parseInt(stdin.readLine()) - 1;
					badValue = false;
				} catch (NumberFormatException e) {
					System.out.println("Please enter an integer value");
					badValue = true;
				}
			} while (badValue);
			
			// Get the column number from the user
			do {
				try {
					System.out.print("\t          column ");
					col = Integer.parseInt(stdin.readLine()) - 1;
					badValue = false;
				} catch (NumberFormatException e) {
					System.out.println("Please enter an integer value");
					badValue = true;;
				}
			} while (badValue);
			
			// If (row, col) is a valid choice, select the card
			if (!board.invalidBoardPosition(row, col)) {
				card = board.getCard(row, col);
				askAgain = false;
			}
			
			// Otherwise, print an error message and repeat the process
			else {
				System.out.println("ERROR: invalid board position");
			}
		} while (askAgain);
		
		return card;
	}
}
