var DominoConstants = (function() {
    'use strict';

    // Pip positions for each value (0-6) on a tile half
    // Grid: 3x3, positions numbered 0-8 (top-left to bottom-right)
    // 0 1 2
    // 3 4 5
    // 6 7 8
    var PIP_POSITIONS = {
        0: [],
        1: [4],
        2: [2, 6],
        3: [2, 4, 6],
        4: [0, 2, 6, 8],
        5: [0, 2, 4, 6, 8],
        6: [0, 2, 3, 5, 6, 8]
    };

    function generateAllTiles() {
        var tiles = [];
        for (var i = 0; i <= 6; i++) {
            for (var j = i; j <= 6; j++) {
                tiles.push({ id: 'tile_' + i + '_' + j, left: i, right: j });
            }
        }
        return tiles;
    }

    function shuffleTiles(tiles) {
        var arr = tiles.slice();
        for (var i = arr.length - 1; i > 0; i--) {
            var j = Math.floor(Math.random() * (i + 1));
            var temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
        return arr;
    }

    function dealTiles(mode, playerCount) {
        var tiles = shuffleTiles(generateAllTiles());
        var hands = {};
        for (var p = 0; p < playerCount; p++) {
            hands[p] = tiles.splice(0, 7);
        }
        var boneyard = (mode === '2p') ? tiles : [];
        return { hands: hands, boneyard: boneyard };
    }

    function findFirstPlayer(hands, roundNumber, previousWinner) {
        if (roundNumber > 1 && previousWinner !== null) return previousWinner;

        // Round 1: who has [6|6]?
        for (var idx in hands) {
            for (var t = 0; t < hands[idx].length; t++) {
                if (hands[idx][t].left === 6 && hands[idx][t].right === 6) return parseInt(idx);
            }
        }
        // Highest double
        for (var d = 5; d >= 0; d--) {
            for (var idx2 in hands) {
                for (var t2 = 0; t2 < hands[idx2].length; t2++) {
                    if (hands[idx2][t2].left === d && hands[idx2][t2].right === d) return parseInt(idx2);
                }
            }
        }
        // Highest pip total
        var best = -1, bestIdx = 0;
        for (var idx3 in hands) {
            for (var t3 = 0; t3 < hands[idx3].length; t3++) {
                var total = hands[idx3][t3].left + hands[idx3][t3].right;
                if (total > best) { best = total; bestIdx = parseInt(idx3); }
            }
        }
        return bestIdx;
    }

    function isDouble(tile) {
        return tile.left === tile.right;
    }

    function pipCount(hand) {
        var total = 0;
        for (var i = 0; i < hand.length; i++) {
            total += hand[i].left + hand[i].right;
        }
        return total;
    }

    function tileMatchesEnd(tile, endValue) {
        return tile.left === endValue || tile.right === endValue;
    }

    function getExposedEnd(tile, matchedValue) {
        if (tile.left === matchedValue) return tile.right;
        return tile.left;
    }

    function getPlayableEnds(board, spinner) {
        if (!board || board.length === 0) return { any: true };

        var ends = {};
        var spinnerHasEast = false, spinnerHasWest = false;

        for (var i = 0; i < board.length; i++) {
            if (board[i].side === 'east') spinnerHasEast = true;
            if (board[i].side === 'west') spinnerHasWest = true;
        }

        var eastChain = board.filter(function(e) { return e.side === 'east'; });
        var westChain = board.filter(function(e) { return e.side === 'west'; });
        var northChain = board.filter(function(e) { return e.side === 'north'; });
        var southChain = board.filter(function(e) { return e.side === 'south'; });

        if (eastChain.length > 0) {
            ends.east = eastChain[eastChain.length - 1].exposed_end;
        } else if (spinner) {
            ends.east = spinner.left;
        }

        if (westChain.length > 0) {
            ends.west = westChain[westChain.length - 1].exposed_end;
        } else if (spinner) {
            ends.west = spinner.left;
        }

        if (spinnerHasEast && spinnerHasWest && spinner) {
            if (northChain.length > 0) {
                ends.north = northChain[northChain.length - 1].exposed_end;
            } else {
                ends.north = spinner.left;
            }
            if (southChain.length > 0) {
                ends.south = southChain[southChain.length - 1].exposed_end;
            } else {
                ends.south = spinner.left;
            }
        }

        return ends;
    }

    function canPlayerPlay(hand, ends) {
        if (ends.any) return true;
        for (var i = 0; i < hand.length; i++) {
            for (var side in ends) {
                if (hand[i].left === ends[side] || hand[i].right === ends[side]) return true;
            }
        }
        return false;
    }

    function getValidPlays(hand, ends) {
        if (ends.any) {
            return hand.map(function(t) { return { tile: t, side: 'any' }; });
        }
        var plays = [];
        for (var i = 0; i < hand.length; i++) {
            for (var side in ends) {
                if (tileMatchesEnd(hand[i], ends[side])) {
                    plays.push({ tile: hand[i], side: side });
                }
            }
        }
        return plays;
    }

    return {
        PIP_POSITIONS: PIP_POSITIONS,
        generateAllTiles: generateAllTiles,
        shuffleTiles: shuffleTiles,
        dealTiles: dealTiles,
        findFirstPlayer: findFirstPlayer,
        isDouble: isDouble,
        pipCount: pipCount,
        tileMatchesEnd: tileMatchesEnd,
        getExposedEnd: getExposedEnd,
        getPlayableEnds: getPlayableEnds,
        canPlayerPlay: canPlayerPlay,
        getValidPlays: getValidPlays
    };
})();
