package core;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import core.Board;
import core.Pawn;

import exception.OutOfBoardException;
import exception.TakenSquareException;

public class TestBoard {

	private Board board;

	/**
	 * Crée un plateau 3x4 case avec une case "bonus" en (0,1) et ajoute 2 pions
	 * sur le plateau, respectivement en (0,0) et (1,2)
	 */
	@Before
	public void initBoard() throws TakenSquareException, OutOfBoardException {
		board = new Board(2, 4, 0, 1);
		board.addPawn(new Pawn('1', 1, 2, board));
		board.addPawn(new Pawn('2', 0, 0, board));
	}

	/**
	 * Test du constructeur avec un nombre de pions égal au nombre de cases du
	 * plateau
	 */
	@Test
	public void boardFullPawns() {
		assertEquals(6, new Board(2, 3, 6).numberOfPawns());
	}

	/**
	 * Test du constructeur avec un nombre de pions négatif
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithZeroPawn() {
		new Board(2, 3, -1);
	}

	/**
	 * Test du constructeur avec un nombre de pions trop grand par rapport à la
	 * taille du plateau
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithTooManyPawns() {
		new Board(2, 3, 7);
	}

	/**
	 * Test du constructeur avec un nombre de cases nul sur l'axe x
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithNullXSize() {
		new Board(0, 2, -1, 0);
	}

	/**
	 * Test du constructeur avec un nombre de cases négatif sur l'axe x
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithNegativeXSize() {
		new Board(-2, 2, -3, 0);
	}

	/**
	 * Test du constructeur avec un nombre de cases nul sur l'axe y
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithNullYSize() {
		new Board(2, 0, 0, -1);
	}

	/**
	 * Test du constructeur avec un nombre de cases négatif sur l'axe y
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithNegativeYSize() {
		new Board(2, -2, 0, -3);
	}

	/**
	 * Test du constructeur avec une case "bonus" hors du plateau (à gauche)
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithBonusSquareOutOfBoardLeft() {
		new Board(2, 2, -1, 1);
	}

	/**
	 * Test du constructeur avec une case "bonus" hors du plateau (à droite)
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithBonusSquareOutOfBoardRight() {
		new Board(2, 2, 2, 1);
	}

	/**
	 * Test du constructeur avec une case "bonus" hors du plateau (en haut)
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithBonusSquareOutOfBoardTop() {
		new Board(2, 2, 1, 2);
	}

	/**
	 * Test du constructeur avec une case "bonus" hors du plateau (en bas)
	 */
	@Test(expected = IllegalArgumentException.class)
	public void boardWithBonusSquareOutOfBoardBottom() {
		new Board(2, 2, 1, -1);
	}

	/**
	 * Test de la méthode getXSize
	 */
	@Test
	public void getXSize() {
		assertEquals(2, board.getXSize());
	}

	/**
	 * Test de la méthode getYSize
	 */
	@Test
	public void getYSize() {
		assertEquals(4, board.getYSize());
	}

	/**
	 * Test de la méthode numberOfPawns
	 */
	@Test
	public void numberOfPawns() {
		assertEquals(2, board.numberOfPawns());
	}

	/**
	 * Test de la méthode isBonusSquare pour une position correspondant à la
	 * case "bonus"
	 */
	@Test
	public void isBonusSquareTrue() {
		assertTrue(board.isBonusSquare(0, 1));
	}

	/**
	 * Test de la méthode isBonusSquare pour une position ne correspondant à la
	 * case "bonus" sur l'axe x
	 */
	@Test
	public void isBonusSquareFalseForX() {
		assertFalse(board.isBonusSquare(1, 2));
	}

	/**
	 * Test de la méthode isBonusSquare pour une position ne correspondant à la
	 * case "bonus" sur l'axe y
	 */
	@Test
	public void isBonusSquareFalseForY() {
		assertFalse(board.isBonusSquare(2, 1));
	}

	/**
	 * Test de la méthode addPawn pour l'ajout d'un pion valide
	 */
	@Test
	public void addValidPawn() throws TakenSquareException, OutOfBoardException {
		board.addPawn(new Pawn('3', 0, 3, board));
		assertEquals(3, board.numberOfPawns());
	}

	/**
	 * Test de la méthode addPawn pour l'ajout d'une pion sur une case occupée
	 */
	@Test(expected = TakenSquareException.class)
	public void addPawnOnTakenSquare() throws TakenSquareException,
			OutOfBoardException {
		board.addPawn(new Pawn('3', 0, 0, board));
	}

	/**
	 * Test de la méthode addPawn pour l'ajout d'une pion sur une case hors du
	 * plateau (bordure gauche)
	 */
	@Test(expected = OutOfBoardException.class)
	public void addPawnOutOfBoardLeft() throws TakenSquareException,
			OutOfBoardException {
		board.addPawn(new Pawn('3', -1, 0, board));
	}

	/**
	 * Test de la méthode addPawn pour l'ajout d'une pion sur une case hors du
	 * plateau (bordure droite)
	 */
	@Test(expected = OutOfBoardException.class)
	public void addPawnOutOfBoardRight() throws TakenSquareException,
			OutOfBoardException {
		board.addPawn(new Pawn('3', board.getXSize(), 0, board));
	}

	/**
	 * Test de la méthode addPawn pour l'ajout d'une pion sur une case hors du
	 * plateau (bordure haut)
	 */
	@Test(expected = OutOfBoardException.class)
	public void addPawnOutOfBoardTop() throws TakenSquareException,
			OutOfBoardException {
		board.addPawn(new Pawn('3', 0, board.getYSize(), board));
	}

	/**
	 * Test de la méthode addPawn pour l'ajout d'une pion sur une case hors du
	 * plateau (bordure bas)
	 */
	@Test(expected = OutOfBoardException.class)
	public void addPawnOutOfBoardBottom() throws TakenSquareException,
			OutOfBoardException {
		board.addPawn(new Pawn('3', 0, -1, board));
	}

	/**
	 * Test de la méthode removeAllPawns
	 */
	@Test
	public void removeAllPawns() {
		board.removeAllPawns();
		assertEquals(0, board.numberOfPawns());
	}

	/**
	 * Test de la suppression d'un pion à sa mort
	 */
	@Test
	public void deadPawn() {
		Pawn pawn = board.getNextPawn();
		board.removePawn(pawn);
		assertEquals(1, board.numberOfPawns());
		assertNull(board.getSquareContent(pawn.getX(), pawn.getY()));
	}

	/**
	 * Test de la méthode maxGold
	 */
	@Test
	public void maxGold() throws OutOfBoardException, TakenSquareException {
		Pawn p3 = new Pawn('3', 0, 1, board);
		Pawn p4 = new Pawn('4', 0, 2, board);
		board.addPawn(p3);
		board.addPawn(p4);
		p4.move(Direction.DROITE);
		p4.move(Direction.DROITE);
		p3.move(Direction.BAS);
		assertEquals(1, board.maxGold());
	}

	/**
	 * Test de la méthode getNextPawn
	 */
	@Test
	public void getNextPawn() {
		assertEquals('1', board.getNextPawn().getLetter());
		assertEquals('2', board.getNextPawn().getLetter());
		assertEquals('1', board.getNextPawn().getLetter());
	}

	/**
	 * Test de la méthode bonusSquareSprite pour la case "bonus"
	 */
	@Test
	public void bonusSquareSprite() {
		assertEquals('#', board.squareContentSprite(0, 1));
	}

	/**
	 * Test de la méthode bonusSquareSprite pour une case vide
	 */
	@Test
	public void emptySquareSprite() {
		assertEquals('.', board.squareContentSprite(0, 2));
	}

	/**
	 * Test de la méthode bonusSquareSprite pour le pion dont c'est le tour
	 */
	@Test
	public void currentPawnSprite() {
		assertEquals('x', board.squareContentSprite(1, 2));
	}

	/**
	 * Test de la méthode bonusSquareSprite pour un pion dont ce n'est pas le
	 * tour
	 */
	@Test
	public void nonCurrentPawnSprite() {
		assertEquals('2', board.squareContentSprite(0, 0));
	}

	/**
	 * Test de la méthode toString
	 */
	@Test
	public void boardToString() {
		assertEquals("..\n.x\n#.\n2.\n", board.toString());
	}

}
