package com.github.apixandru.games.rummikub;

import com.github.apixandru.games.rummikub.model.Card;
import com.github.apixandru.games.rummikub.model2.ImplementationDetails;
import com.github.apixandru.games.rummikub.model2.Player;
import com.github.apixandru.games.rummikub.model2.Rummikub;
import com.github.apixandru.games.rummikub.model2.RummikubFactory;
import org.junit.Before;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

import static com.github.apixandru.games.rummikub.model2.ImplementationDetails.cloneCards;
import static com.github.apixandru.games.rummikub.model2.ImplementationDetails.currentPlayer;
import static com.github.apixandru.games.rummikub.model2.ImplementationDetails.getCards;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;

/**
 * @author Alexandru-Constantin Bledea
 * @since December 25, 2015
 */
public final class RummikubTest2 {

    private Rummikub rummikub;
    private Player player;

    @Before
    public void setup() {
        this.rummikub = RummikubFactory.newInstance();
        this.player = rummikub.addPlayer("Player 1");
    }


    /**
     * @param cards
     */
    @Utility
    private void placeCardsOnFirstSlots(final List<Card> cards) {
        for (int i = 0; i < cards.size(); i++) {
            this.player.placeCardOnBoard(cards.get(i), i, 0);
        }
    }

    /**
     * @return
     */
    @Utility
    private int countCards() {
        return ImplementationDetails.countCards(this.player);
    }

    /**
     * @return
     */
    @Utility
    private Card[][] cardsOnBoard() {
        return ImplementationDetails.cloneBoard(this.rummikub);
    }

    /**
     * @return
     */
    @Utility
    private Card getFirstCard() {
        return ImplementationDetails.getFirstCard(this.player);
    }

    /**
     * @return
     */
    @Utility
    private List<Card> endTurnUntilValidGroup() {
        return ImplementationDetails.endTurnUntilValidGroup(this.player);
    }


    @Test
    public void testGame() {
        final Player player2 = rummikub.addPlayer("Johnny");

        assertSame(player, currentPlayer(rummikub));

        player2.endTurn();
        assertSame(player, currentPlayer(rummikub));

        player.endTurn();
        assertSame(player2, currentPlayer(rummikub));

        player2.endTurn();
        assertSame(player, currentPlayer(rummikub));
    }

    @Test
    public void testPlaceCardOnBoard() {
        final int numberOfCardsBeforeEndTurn = countCards();
        player.endTurn();
        assertEquals(numberOfCardsBeforeEndTurn + 1, countCards());
    }

    @Test
    public void testCommitBoard() {
        final List<Card> group = endTurnUntilValidGroup();
        placeCardsOnFirstSlots(group);
        final List<Card> cardsBeforeEndTurn = cloneCards(player);
        player.endTurn();
        assertEquals(cardsBeforeEndTurn, getCards(player));
    }

    @Test
    public void testPutCardOnBoard() {
        final Card card = getFirstCard();
        final Card[][] cards = cardsOnBoard();
        player.placeCardOnBoard(card, 0, 0);
        assertFalse(Arrays.deepEquals(cardsOnBoard(), cards));
    }

    @Test
    public void testUndo() {
        final Card card = getFirstCard();
        final Card[][] cards = cardsOnBoard();
        player.placeCardOnBoard(card, 0, 0);
        player.endTurn();
        assertTrue(Arrays.deepEquals(cardsOnBoard(), cards));
    }

    @Test
    public void testTakeCardFromBoard() {
        final Card card = getFirstCard();
        final Card[][] cards = cardsOnBoard();
        player.placeCardOnBoard(card, 0, 0);
        player.takeCardFromBoard(card, 0, 0);
        assertTrue(Arrays.deepEquals(cardsOnBoard(), cards));
    }

    @Test
    public void testCannotTakeCardAfterEnd() {
        final List<Card> group = endTurnUntilValidGroup();
        placeCardsOnFirstSlots(group);
        player.endTurn();

        final Card[][] cards = cardsOnBoard();
        player.takeCardFromBoard(group.get(0), 0, 0);
        assertTrue(Arrays.deepEquals(cardsOnBoard(), cards));
    }

    @Test
    public void testLessCardsAfterPlace() {
        final int numCardsBeforePlace = countCards();
        final Card card = getFirstCard();
        player.placeCardOnBoard(card, 0, 0);
        assertEquals(numCardsBeforePlace - 1, countCards());
    }

}

@@ -2085,24 +2085,188 @@
 er);%0A    %7D%0A%0A
+    /**%0A     * @param cards%0A     */%0A    private void assertCardsOnBoard(final Card%5B%5D%5B%5D cards) %7B%0A        assertTrue(Arrays.deepEquals(cards, cardsOnBoard()));%0A    %7D%0A
 %0A    @Test%0A 
@@ -3644,32 +3644,9 @@
 sert
-True(Arrays.deepEquals(c
+C
 ards
@@ -3649,34 +3649,30 @@
 ardsOnBoard(
-), 
 cards)
-)
 ;%0A    %7D%0A%0A   
@@ -3918,32 +3918,9 @@
 sert
-True(Arrays.deepEquals(c
+C
 ards
@@ -3923,34 +3923,30 @@
 ardsOnBoard(
-), 
 cards)
-)
 ;%0A    %7D%0A%0A   
@@ -4481,32 +4481,32 @@
 rd(card, 0, 0);%0A
-
         assertEq
@@ -4557,10 +4557,699 @@
 %0A    %7D%0A%0A
+    /**%0A     * Just moving cards on the board when it's your turn is not enough.%0A     * The changes should rollback and you should get a card.%0A     */%0A    @Test%0A    public void testMoveBoardCardsRollback() %7B%0A        final List%3CCard%3E group = endTurnUntilValidGroup();%0A        placeCardsOnFirstSlots(group);%0A        player.endTurn();%0A%0A        final Card firstCardOnBoard = group.get(0);%0A%0A        final Card%5B%5D%5B%5D cardsOnBoard = cardsOnBoard();%0A        final int cardsInHand = countCards();%0A%0A        player.moveCardOnBoard(firstCardOnBoard, 0, 0, group.size(), 0);%0A        player.endTurn();%0A%0A        assertCardsOnBoard(cardsOnBoard);%0A        assertEquals(cardsInHand + 1, countCards());%0A    %7D%0A%0A
 %7D%0A

add test for just moving around