package net.woodyfolsom.msproj;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

public class ZobristHashGenerator {
	private static final Map<Integer, ZobristHashGenerator> zhgMap = new HashMap<Integer, ZobristHashGenerator>();

	private long emptyBoardHash;
	private long[] randomBitFields;

	private ZobristHashGenerator(int boardSize) {
		// Fields are 0, BLACK, WHITE
		int nRandomFields = 3 * boardSize * boardSize;

		SecureRandom secureRandom = new SecureRandom();
		randomBitFields = new long[nRandomFields];
		byte[] nextBytes = new byte[8];
		for (int i = 0; i < nRandomFields; i++) {
			secureRandom.nextBytes(nextBytes);
			randomBitFields[i] = new BigInteger(nextBytes).longValue();
		}

		emptyBoardHash = 0L;
		for (int i = 0; i < randomBitFields.length / 3; i++) {
			emptyBoardHash ^= randomBitFields[i * 3];
		}
	}

	public static ZobristHashGenerator getInstance(int boardSize) {

		if (!zhgMap.containsKey(boardSize)) {
			ZobristHashGenerator zobHashGen = new ZobristHashGenerator(
					boardSize);
			// TODO add check for minimum hamming distance/colinearity check
			zhgMap.put(boardSize, zobHashGen);
		}

		return zhgMap.get(boardSize);
	}

	public long getEmptyBoardHash() {
		return emptyBoardHash;
	}

	public long getHashCode(int index, char stoneType) {
		switch (stoneType) {
		case GameBoard.EMPTY_INTERSECTION:
			return randomBitFields[index * 3];
		case GameBoard.BLACK_STONE:
			return randomBitFields[index * 3 + 1];
		case GameBoard.WHITE_STONE:
			return randomBitFields[index * 3 + 2];
		default:
			throw new IllegalArgumentException("No hash code for stone type: "
					+ stoneType);
		}
	}

}
