package com.charego.lingo.common;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

public class Game {

	public static final int INCORRECT_CHARACTER = 0;
	public static final int INCORRECT_POSITION = 1;
	public static final int CORRECT_CHARACTER_POSITION = 2;

	private static final AtomicInteger idCounter = new AtomicInteger(0);

	private int id;

	private Player playerOne;

	private Player playerTwo;

	private Set<String> acceptableGuesses;

	private List<String> possibleWords;

	private String word;

	private int wordIndex = 0;

	private int wordLength;

	private int[] invalidGuess;

	public Game() {
		// Empty constructor required for serialization
	}

	public Game(Player host, int wordLength) {
		this.id = idCounter.incrementAndGet();
		this.playerOne = host;
		setWordLength(wordLength);
	}

	private int indexOf(char[] array, char searchTerm) {
		for (int i = 0; i < wordLength; i++) {
			if (array[i] == searchTerm) {
				return i;
			}
		}
		return -1;
	}

	public boolean isCorrect(int[] result) {
		for (int i = 0; i < wordLength; i++) {
			if (result[i] != CORRECT_CHARACTER_POSITION) {
				return false;
			}
		}
		return true;
	}

	public boolean isInvalid(int[] result) {
		return Arrays.equals(result, invalidGuess);
	}

	public int[] evaluate(String guess) {
		if (!acceptableGuesses.contains(guess)) {
			return invalidGuess;
		}

		// the guess is acceptable
		int[] result = new int[wordLength];
		char[] remaining = new char[wordLength];
		for (int i = 0; i < wordLength; i++) {
			if (guess.charAt(i) == word.charAt(i)) {
				result[i] = CORRECT_CHARACTER_POSITION;
			} else {
				result[i] = INCORRECT_CHARACTER;
				remaining[i] = word.charAt(i);
			}
		}
		for (int i = 0; i < wordLength; i++) {
			if (result[i] == INCORRECT_CHARACTER) {
				int index = indexOf(remaining, guess.charAt(i));
				if (index != -1) {
					result[i] = INCORRECT_POSITION;
					remaining[index] = 0;
				}
			}
		}
		return result;
	}

	public int getId() {
		return id;
	}

	public Player getPlayerOne() {
		return playerOne;
	}

	public Player getPlayerTwo() {
		return playerTwo;
	}

	public int getWordLength() {
		return wordLength;
	}

	public String newGame() {
		Collections.shuffle(possibleWords);
		wordIndex = 0;
		return newWord();
	}

	public String newWord() {
		word = possibleWords.get(wordIndex++);
		return word;
	}

	public void setAcceptableGuesses(Set<String> value) {
		this.acceptableGuesses = value;
	}

	public void setId(int value) {
		this.id = value;
	}

	public void setPlayerOne(Player value) {
		this.playerOne = value;
	}

	public void setPlayerTwo(Player value) {
		this.playerTwo = value;
	}

	public void setPossibleWords(List<String> value) {
		this.possibleWords = value;
	}

	public void setWordLength(int value) {
		this.wordLength = value;
		this.invalidGuess = new int[value];
		for (int i = 0; i < value; i++) {
			/* Nein nein nein nein nein! */
			this.invalidGuess[i] = 9;
		}
	}

}
