package fr.iut_fbleau.GameAPI;

import java.util.EnumMap;

/**
 * The abstract class for an Abstract Game.
 * All inheriting classes should be turn taking games (see method run).
 *
 * The abstract game knows the model of the current game state (something implementing
 * an IBoard). It handles the players by providing a map from the Player class
 * (an enum for the player order in the game) to the abstractGamePlayer class
 * (a class that can choose a Ply from any given position). 
 *
 * The control loop in the run method selects the appropriate player, sends him
 * what should be a copy of the current game state to help him make his decision.
 * If a player returns an illegal move, an exception is thrown and the game stops.
 * Otherwise, when the game finishes the method returns the result.
 *
 * The logic of the game rule is handled in the class IBoard.
 * In particular, it is possible that the turn taking does not take form of a round
 * robin and switches between players in a non uniform ad hoc fashion.
 *
 * Potential evolution of this class could take into account clocks for the players,
 * which would be better handled here than in the Abstractboard class.
 *
 */
public abstract class AbstractGame {

    // board this game is played on
    private IBoard currentBoard;

    // a map from the enum Player to the genuine Player AbstractGamePlayer
    private EnumMap<Player, AbstractGamePlayer> mapPlayers;
    
    // constructeur à appeler dans le constructeur d'un fils concret avec super.
    public AbstractGame(IBoard b, EnumMap<Player,AbstractGamePlayer> m){
        this.currentBoard=b;
        this.mapPlayers=m;
    }

    /**
     * boucle de contrôle du jeu.
     *
     * @throws IllegalStateException if a player proposes an IllegalMove at some point
     * @return the Result of the game from the perspective of the first player.
     */
    public Result run(){
	while(! currentBoard.isGameOver()) {
	    AbstractGamePlayer player = mapPlayers.get(currentBoard.getCurrentPlayer());
	    IBoard board = currentBoard.safeCopy();
	    AbstractPly ply = player.giveYourMove(board);

	    if (currentBoard.isLegal(ply)) {
		currentBoard.doPly(ply);
	    }
	    else throw new IllegalStateException("Player "+ player + " is a bloody cheat. I give up.");
	}

	return currentBoard.getResult();
    }
}
