package me.abeyta.deckmanager.delegates.shuffle;

import static me.abeyta.deckmanager.delegates.shuffle.ShufflerUtils.convertCardArrayIntoSet;
import static me.abeyta.deckmanager.delegates.shuffle.ShufflerUtils.convertDeckIntoCardArray;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.RandomUtils;

import me.abeyta.deckmanager.model.Card;
import me.abeyta.deckmanager.model.Deck;

public class HandShuffler implements Shuffler {

	/**
	 * Hand shuffling technique that weaves a half of a deck over each other
	 * 
	 * https://en.wikipedia.org/wiki/Faro_shuffle
	 */
	@Override
	public void shuffle(Deck deck) {
		Card[] cards = convertDeckIntoCardArray(deck);

		Deck baseDeck = new Deck(deck.getName());
		do {
			Card[] shuffledCards = shuffleDeck(cards);
			deck.setCards(convertCardArrayIntoSet(shuffledCards));
		} while(baseDeck.equals(deck));//ensure we never return a deck that is in original order
	}

	private Card[] shuffleDeck(Card[] cards) {
		int numberOfShuffles = getRandomShuffleCountThatDoesntResetDeck();

		Card[] shuffledCards = shuffleCards(cards);
		for(int x = 0; x < numberOfShuffles; x++) {
			shuffledCards = shuffleCards(shuffledCards);
		}
		return shuffledCards;
	}

	private int getRandomShuffleCountThatDoesntResetDeck() {
		int numberOfShuffles = 0;
		
		do {
			numberOfShuffles = RandomUtils.nextInt(1, 100) + 1; //account for previous shuffle already done
		} while(numberOfShuffles % 8 == 0); //ensure we do not reset the deck to the starting point with an 8
		
		return numberOfShuffles;
	}

	private Card[] shuffleCards(Card[] cards) {
		Card[] leftSide = splitCards(cards, false);
		Card[] rightSide = splitCards(cards, true);

		List<Card> shuffledList = new ArrayList<>();
		for(int x = 0; x < leftSide.length; x ++) {
			shuffledList.add(leftSide[x]);
			shuffledList.add(rightSide[x]);
		}

		return shuffledList.toArray(new Card[shuffledList.size()]);
	}

	private Card[] splitCards(Card[] cards, boolean topHalf) {
		int halfCount = cards.length / 2;
		Card[] cardHalf = new Card[halfCount];
		int cardIndex = 0;
		if (topHalf) {
			cardIndex = halfCount;
		}
		for (int x = 0; x < halfCount; x++, cardIndex++) {
			cardHalf[x] = cards[cardIndex];
		}
		return cardHalf;
	}

}

@@ -317,21 +317,161 @@
 lang
-3.RandomUtils
+.ArrayUtils;%0Aimport org.apache.commons.lang3.RandomUtils;%0Aimport org.apache.commons.lang3.tuple.ImmutablePair;%0Aimport org.apache.commons.lang3.tuple.Pair
 ;%0A%0Ai
@@ -1752,49 +1752,104 @@
 %7B%0A%09%09
+Pair%3C
 Card%5B%5D
- leftSide = splitCards(cards, false
+, Card%5B%5D%3E cardHalves = splitCards(cards); %0A%09%09%0A%09%09Card%5B%5D leftSide = cardHalves.getLeft(
 );%0A%09
@@ -1872,30 +1872,28 @@
 e = 
-splitCards(cards, true
+cardHalves.getRight(
 );%0A%0A
@@ -2134,22 +2134,36 @@
 private 
+Pair%3C
 Card%5B%5D
+, Card%5B%5D%3E
  splitCa
@@ -2182,25 +2182,8 @@
 ards
-, boolean topHalf
 ) %7B%0A
@@ -2218,16 +2218,19 @@
 th / 2;%0A
+%09%09%0A
 %09%09Card%5B%5D
@@ -2234,92 +2234,55 @@
 d%5B%5D 
-cardHalf = new Card%5BhalfCount%5D;%0A%09%09int cardIndex = 0;%0A%09%09if (topHalf) %7B%0A%09%09%09cardIndex =
+bottom = (Card%5B%5D) ArrayUtils.subarray(cards, 0,
  hal
@@ -2291,123 +2291,130 @@
 ount
+)
 ;%0A%09%09
-%7D%0A%09%09for (int x = 0; x %3C halfCount; x++, cardIndex++) %7B%0A%09%09%09cardHalf%5Bx%5D = cards%5BcardIndex%5D;%0A%09%09%7D%0A%09%09return cardHalf
+Card%5B%5D top = (Card%5B%5D) ArrayUtils.subarray(cards, halfCount, cards.length);%0A%0A%09%09return new ImmutablePair%3C%3E(bottom, top)
 ;%0A%09%7D

return pair of array halves instead of calling split twice. removed some unnecessary logic and a method call