package jrummikub.model;

import static jrummikub.model.StoneColor.*;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import jrummikub.model.PlayerSettings.Type;

/**
 * The overall game settings
 */
public class GameSettings implements Serializable {
	private static final long serialVersionUID = -7221346125938175643L;

	private ArrayList<PlayerSettings> players = new ArrayList<PlayerSettings>();

	private int initialMeldThreshold;
	private int jokerPoints;
	private int jokerNumber;
	private int highestValue;
	private int stoneSetNumber;
	private int numberOfStonesDealt;
	private int totalTime;
	private boolean noLimits;
	private HashSet<StoneColor> stoneColors;
	private boolean seeHandSize;

	/**
	 * Creates new GameSettings with default values
	 */
	public GameSettings() {
		reset();
	}

	/**
	 * Reset the game settings to the default values
	 */
	public void reset() {
		initialMeldThreshold = 30;
		jokerPoints = 50;
		jokerNumber = 2;
		highestValue = 13;
		stoneSetNumber = 2;
		numberOfStonesDealt = 14;
		totalTime = 60;
		noLimits = false;
		seeHandSize = false;
		stoneColors = new HashSet<StoneColor>(Arrays.asList(BLACK, BLUE, ORANGE,
				RED));
	}

	/**
	 * Returns the list containing the settings of all players
	 * 
	 * @return the player settings list
	 */
	public List<PlayerSettings> getPlayerList() {
		return players;
	}

	/**
	 * Sets the initial meld threshold
	 * 
	 * @param value
	 *          the value to set
	 */
	public void setInitialMeldThreshold(int value) {
		initialMeldThreshold = value;
	}

	/**
	 * Returns the initial meld threshold
	 * 
	 * @return the threshold
	 */
	public int getInitialMeldThreshold() {
		return initialMeldThreshold;
	}

	/**
	 * Sets the points counted for a joker
	 * 
	 * @param value
	 *          the value to set
	 */
	public void setJokerPoints(int value) {
		jokerPoints = value;
	}

	/**
	 * Returns the points counted for a joker
	 * 
	 * @return the points
	 */
	public int getJokerPoints() {
		return jokerPoints;
	}

	/**
	 * Sets the number of jokers in game
	 * 
	 * @param value
	 *          how many jokers will be used
	 */
	public void setJokerNumber(int value) {
		jokerNumber = value;
	}

	/**
	 * Returns the number of jokers
	 * 
	 * @return the number of jokers
	 */
	public int getJokerNumber() {
		return jokerNumber;
	}

	/**
	 * Return the highest stone value in use
	 * 
	 * @return highest stone value
	 */
	public int getHighestValue() {
		return highestValue;
	}

	/**
	 * Set the highest stone value in use
	 * 
	 * @param highestValue
	 *          highest stone value
	 */
	public void setHighestValue(int highestValue) {
		this.highestValue = highestValue;
	}

	/**
	 * Get the number of sets of stones in use
	 * 
	 * @return sets of stones in use
	 */
	public int getStoneSetNumber() {
		return stoneSetNumber;
	}

	/**
	 * Set the number of sets of stones in use
	 * 
	 * @param stoneSets
	 *          sets of stones in use
	 */
	public void setStoneSetNumber(int stoneSets) {
		this.stoneSetNumber = stoneSets;
	}

	/**
	 * Getter for the time for a turn
	 * 
	 * @return time for a turn
	 */
	public int getTotalTime() {
		return totalTime;
	}

	/**
	 * Setter for the time for a turn
	 * 
	 * @param totalTime
	 *          for a turn
	 */
	public void setTotalTime(int totalTime) {
		this.totalTime = totalTime;
	}

	/**
	 * Use "No-Limits" rules
	 * 
	 * @return whether No-Limits rules are used
	 */
	public boolean isNoLimits() {
		return noLimits;
	}

	/**
	 * Returns the visibility of the hand size
	 * 
	 * @return whether the hand size is visible
	 */
	public boolean getSeeHandSize() {
		return seeHandSize;
	}

	/**
	 * Set whether the hand size is visible
	 * 
	 * @param see
	 *          whether the hand size is visible
	 */
	public void setSeeHandSize(boolean see) {
		seeHandSize = see;
	}

	/**
	 * Set whether "No-Limits" rules are used
	 * 
	 * @param noLimits
	 *          use no limit rules
	 */
	public void setNoLimits(boolean noLimits) {
		this.noLimits = noLimits;
	}

	/**
	 * Get stone colors used
	 * 
	 * @return used stone colors
	 */
	public Set<StoneColor> getStoneColors() {
		return stoneColors;
	}

	/**
	 * Set stone colors used
	 * 
	 * @param stoneColors
	 *          used stone colors
	 */
	public void setStoneColors(Set<StoneColor> stoneColors) {
		this.stoneColors = new HashSet<StoneColor>(stoneColors);
	}

	/**
	 * Get number of stones dealt at game start
	 * 
	 * @return numberOfStonesDealt
	 */
	public int getNumberOfStonesDealt() {
		return numberOfStonesDealt;
	}

	/**
	 * Set number of stones dealt at game start
	 * 
	 * @param number
	 *          how many Stones will be dealt initially
	 */
	public void setNumberOfStonesDealt(int number) {
		numberOfStonesDealt = number;
	}

	/**
	 * Check if there is only one human player
	 * 
	 * @return one human player
	 */
	public boolean oneHuman() {
		int humans = 0;
		for (PlayerSettings s : players) {
			if (s.getType() == Type.HUMAN) {
				humans++;
			}
		}
		return (humans == 1);

	}

	/**
	 * Calculate the total number of stones in game
	 * 
	 * @return total number of stones
	 */
	public int getTotalStones() {
		return getHighestValue() * getStoneSetNumber() * getStoneColors().size()
				+ getJokerNumber();
	}
}
