package jrummikub.model;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jrummikub.util.Pair;

import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

/**
 * Tests for {@link StoneHeap}
 */
@RunWith(Theories.class)
public class StoneHeapTest {

	private static Pair<GameSettings, StoneHeap> createHeap(
			GameSettings settings) {
		return new Pair<GameSettings, StoneHeap>(settings, new StoneHeap(
				settings));
	}

	/**
	 * @return the data points
	 */
	@DataPoints
	public static Pair<GameSettings, StoneHeap>[] createDataPoints() {
		GameSettings testSettings1 = new GameSettings();

		GameSettings testSettings2 = new GameSettings();
		testSettings2.setJokerNumber(10);

		GameSettings testSettings3 = new GameSettings();
		testSettings3.setStoneSetNumber(1);

		GameSettings testSettings4 = new GameSettings();
		testSettings4.setJokerNumber(5);
		testSettings4.setStoneSetNumber(5);

		@SuppressWarnings("unchecked")
		Pair<GameSettings, StoneHeap>[] ret = new Pair[4];
		ret[0] = createHeap(testSettings1);
		ret[1] = createHeap(testSettings2);
		ret[2] = createHeap(testSettings3);
		ret[3] = createHeap(testSettings4);

		return ret;
	}

	private int calculateTotalNumberOfStones(GameSettings testSettings) {
		int totalStones = testSettings.getHighestValue()
				* testSettings.getStoneSetNumber()
				* testSettings.getStoneColors().size()
				+ testSettings.getJokerNumber();
		return totalStones;
	}

	/**
	 * Is the right number of Stones in heap?
	 * 
	 * @param data
	 *            data
	 */
	@Theory
	public void fullStoneHeap(Pair<GameSettings, StoneHeap> data) {
		assertEquals(calculateTotalNumberOfStones(data.getFirst()),
				data.getSecond().heap.size());
	}

	/**
	 * Enough stones of each color in heap?
	 * 
	 * @param data
	 *            data
	 */
	@Theory
	public void fullColor(Pair<GameSettings, StoneHeap> data) {
		int stonesOfAColor = data.getFirst().getHighestValue()
				* data.getFirst().getStoneSetNumber();
		Map<StoneColor, Integer> counters = new HashMap<StoneColor, Integer>();
		for (StoneColor c : data.getFirst().getStoneColors()) {
			counters.put(c, 0);
		}
		for (Stone i : data.getSecond().heap) {
			if (i.isJoker())
				continue;
			int count = counters.get(i.getColor());
			counters.put(i.getColor(), count + 1);
		}
		for (StoneColor c : data.getFirst().getStoneColors()) {
			assertEquals(stonesOfAColor, (long) counters.get(c));
		}
	}

	/**
	 * Enough Jokers?
	 * 
	 * @param data
	 *            data
	 */
	@Theory
	public void fullJoker(Pair<GameSettings, StoneHeap> data) {
		int countJoker = 0;
		for (Stone i : data.getSecond().heap) {
			if (i.isJoker())
				countJoker++;
		}
		assertEquals(data.getFirst().getJokerNumber(), countJoker);
	}

	/**
	 * @param data
	 *            data
	 */
	@Theory
	public void drawStoneTest(Pair<GameSettings, StoneHeap> data) {
		assertNotNull(data.getSecond().drawStone());
		assertEquals(calculateTotalNumberOfStones(data.getFirst()) - 1,
				data.getSecond().heap.size());
	}

	/**
	 * @param data
	 *            data
	 */
	@Theory
	public void drawStonesTest(Pair<GameSettings, StoneHeap> data) {
		List<Stone> testStones = data.getSecond().drawStones(5);
		assertEquals(5, testStones.size());
		assertEquals(calculateTotalNumberOfStones(data.getFirst()) - 5,
				data.getSecond().heap.size());
	}
}