/**
 * 
 */
var EventSource = {
    CellClick: 0,
    ClueClick: 1,
    KeyInput: 2
};

var PuzzleDirection = {
    UP: 0,
    RIGHT: 1,
    DOWN: 2,
    LEFT: 3
};

/**
 * Object definition for handling keyboard events
 */
var PuzzleInput = {
    /**
     * Returns true if a valid puzzle input key is pressed
     */
    isValidInput: function () {
        return true;
    },
    /**
     * Returns true is backspace is pressed
     */
    isBackspace: function (event) {
        return (event.keyCode === 8 || event.which === 8);
    },
    /**
     * Returns true is delete key is pressed
     */
    isDeleteKey: function (event) {
        return (event.keyCode === 46 || event.which === 46);
    },
    /**
     * Returns true if LEFT Arrow is pressed
     */
    isLeft: function (event) {
        return (event.keyCode === 37 || event.which === 37);
    },
    /**
     * Returns true if RIGHT Arrow is pressed
     */
    isRight: function (event) {
        return (event.keyCode === 39 || event.which === 39);
    },
    /**
     * Returns true if UP Arrow is pressed
     */
    isUp: function (event) {
        return (event.keyCode === 38 || event.which === 38);
    },
    /**
     * Returns true if DOWN Arrow is pressed
     */
    isDown: function (event) {
        return (event.keyCode === 40 || event.which === 40);
    },
    /**
     * Returns true if iPhone Done button is pressed
     */
    isDone: function (event) {
        return (event.keyCode == 13 || event.which == 13);
    },
    setDeleteHack: function (enable)
    {
        PuzzleInput.deleteHack = enable;
    },
    getUserInput: function (event, inputId) {
        var userInput = "";
        //Mobile Chrome Browser handles key events differently, so we have to check the user agent
        if (!PuzzleInput.isBrowserAndroidChrome)
        {
            userInput = String.fromCharCode(event.which);
            this.latestInputValue = userInput;
            this.currentInputId = inputId;
            $(inputId).val("");
        } else
        {
            var currentInputValue = $(inputId).val();

            this.currentInputId = inputId;

            if (currentInputValue.length > this.latestInputValue.length)
            {
                //In this case, user has inputted a character
                this.latestInputValue = currentInputValue;
                userInput = this.latestInputValue.charAt(this.latestInputValue.length - 1);
                event.which = userInput.charCodeAt(0);
                event.keyCode = userInput.charCodeAt(0);

            } else if (currentInputValue.length < this.latestInputValue.length)
            {
                //In this case, user input is Backspace
                this.latestInputValue = currentInputValue;
                userInput = "";
                event.which = 8;
                event.keyCode = 8;
            }

        }

        return userInput.toUpperCase();
    },
    hasValueChanged: function (inputId) {
        if ($(inputId).val() != this.latestInputValue)
            return true;

        return false;
    },
    deleteHack: false,
    latestInputValue: "",
    currentInputId: "",
    isBrowserAndroidChrome: (navigator.userAgent.toLowerCase().indexOf("android") > -1 && navigator.userAgent.toLowerCase().indexOf("chrome") > -1),
    backspaceInterval: setInterval(function () {
        if (!PuzzleInput.deleteHack)
            return;

        if (PuzzleInput.currentInputId != '')
        {
            var currentInput = $(PuzzleInput.currentInputId).val();

            if (currentInput.length < PuzzleInput.latestInputValue.length)
            {
                $('.cell.active > .cell-input').text('');
                PuzzleInput.latestInputValue = $(PuzzleInput.currentInputId).val();
            }

        }
    }, 500)

};

/**
 * Object definition for base puzzle
 */
var Puzzle = {
    /**
     * Sets the grid size of the puzzle
     */
    setSize: function (width, height) {
        this.size.width = width;
        this.size.height = height;
    },
    zoomIn: function () {
        var zoomLevel = parseFloat($(Puzzle.defaults.gridId).css("zoom"));

        if (!zoomLevel || zoomLevel.length === 0)
            zoomLevel = 1;

        if (zoomLevel < 3) {
            zoomLevel += 0.1;
            $(Puzzle.defaults.gridId).css("zoom", zoomLevel);
        }
    },
    zoomOut: function () {
        var zoomLevel = parseFloat($(Puzzle.defaults.gridId).css("zoom"));

        if (!zoomLevel || zoomLevel.length === 0)
            zoomLevel = 1;

        if (zoomLevel > 1) {
            zoomLevel -= 0.1;
            $(Puzzle.defaults.gridId).css("zoom", zoomLevel);
        }
    },
    checkAnswers: function () {
        //Get all cells
        var allCells = $(Puzzle.defaults.cellsId);

        //Iterate through cells
        for (var i = 0; i < allCells.length; i++) {
            var value = $(allCells[i]).children(Puzzle.defaults.cellInputId).html();
            var solution = $(allCells[i]).children(Puzzle.defaults.cellInputId).data("solution");

            if (value != solution)
                return false;
        }

        return true;
    },
    checkPuzzleCompletion: function () {
        if (Puzzle.checkAnswers()) {
            Puzzle.showMessageBox("Congratulations! You have completed the puzzle.", Puzzle.messageType.INFO);
        } else {
            Puzzle.showMessageBox("All answers must be correct. Please check your answers.", Puzzle.messageType.WARNING);
        }
    },
    validateCellAnswers: function () {
        var hintNumber = 0;

        $(Puzzle.defaults.cellsId).each(function () {
            var value = $(this).children(Puzzle.defaults.cellInputId).html();
            var solution = $(this).children(Puzzle.defaults.cellInputId).data("solution");

            if (value == "")
                return;

            if (value != solution) {
                $(this).addClass(Puzzle.defaults.invalidCellClass);
                hintNumber++;
            }
        });

        //Penalize user for using hint button
        if (puzzleTimer)
            puzzleTimer.addSeconds(hintNumber * 10);
    },
    giveHint: function () {
        var hintNumber = 0;

        if (Puzzle.lastSelected.cell) {
            var cell = Puzzle.lastSelected.cell;
            var solution = $(cell).children(Puzzle.defaults.cellInputId).data("solution");
            var currentVal = $(cell).children(Puzzle.defaults.cellInputId).html();

            if (solution != currentVal) {
                Puzzle.setCellValue(cell, solution);
                hintNumber++;
            }
        }

        Puzzle.moveToNextHintCell();
        //Penalize user for using hint button
        if (puzzleTimer)
            puzzleTimer.addSeconds(hintNumber * 10);
    },
    giveWordHint: function () {
        var hintNumber = 0;

        if (Puzzle.lastSelected.cellGroup) {
            for (var i = 0; i < Puzzle.lastSelected.cellGroup.length; i++) {
                var nextCellId = "#cell-" + Puzzle.lastSelected.cellGroup[i][0] + "-" + Puzzle.lastSelected.cellGroup[i][1];
                var nextCell = $(nextCellId);

                //Get solution and current value
                var solution = $(nextCell).children(Puzzle.defaults.cellInputId).data("solution");
                var currentVal = $(nextCell).children(Puzzle.defaults.cellInputId).html();

                //For each wrong or incomplete answer, set solution
                if (solution != currentVal) {
                    Puzzle.setCellValue(nextCell, solution);
                    hintNumber++;
                }
            }

            //Penalize user for using word hint button
            if (puzzleTimer)
                puzzleTimer.addSeconds(hintNumber * 10);
        }
    },
    solvePuzzle: function () {
        var hintNumber = 0;

        $(Puzzle.defaults.cellsId).each(function () {
            $(this).removeClass(Puzzle.defaults.invalidCellClass);

            //Get solution and current value
            var solution = $(this).children(Puzzle.defaults.cellInputId).data("solution");
            var currentVal = $(this).children(Puzzle.defaults.cellInputId).html();

            //For each wrong or incomplete answer, set solution
            if (solution != currentVal) {
                $(this).children(Puzzle.defaults.cellInputId).html(solution);
                hintNumber++;
            }
        });

        //Penalize user for using each incorrect or incomplete button
        if (puzzleTimer)
            puzzleTimer.addSeconds(hintNumber * 10);

        if (Puzzle.solutionTimeout !== undefined) {
            Puzzle.createSolutionTimeout();
        }
    },
    invokeSubmitScore: function () {
        if (!puzzleId || puzzleId.length === 0)
        {
            alert("This feature cannot be used in preview mode");
            return;
        }

        //Show submit score dialog, if all the answers are correct
        if (this.checkAnswers())
            showSubmitScore();
        else
            showGameIncomplete();
    },
    invokeToplist: function () {
        if (!puzzleId || puzzleId.length === 0) {
            alert("This feature cannot be used in preview mode");
            return;
        }

        showToplist(puzzleId);
    },
    updateOrientation: function () {
        if (isClientiOS) {
            if (window.orientation === 0 || window.orientation === 180) {
                document.getElementById("viewport").setAttribute("content", "width=device-width, maximum-scale=1.0, initial-scale=1.0, user-scalable=no");
            } else {
                document.getElementById("viewport").setAttribute("content", "width=device-height, maximum-scale=1.0, initial-scale=1.0, user-scalable=no");
            }

            if (Puzzle.repositionUserInputField) {
                Puzzle.repositionUserInputField();
            }
        }
    },
    showMessageBox: function (message, messageType, callback) {
        var timeoutAmount = 2000;
        var gameCompletionMessage = $("#puzzle-info-message");

        Puzzle.lastMessageCallback = callback;

        if (gameCompletionMessage.length === 0)
        {
            gameCompletionMessage = $("<div id='puzzle-info-message' class='puzzle-box'>\n\
                                           <div id='puzzle-info-message-content'></div>\n\
                                       </div>");

            gameCompletionMessage.css({
                "color": "#FFF",
                "font-weight": "bold",
                "font-size": "18px",
                "padding": "30px",
                "top": "75px",
                "border": "2px solid #FFF",
                "border-radius": "10px",
                "cursor": "pointer"
            });

            gameCompletionMessage.click(function () {
                gameCompletionMessage.fadeOut();

                //Click even is only setup once, thus callback is not changed if a new one is sent later on.
                if (typeof Puzzle.lastMessageCallback != 'undefined')
                {
                    var callback_func = eval(Puzzle.lastMessageCallback);

                    if ($.isFunction(callback_func))
                    {
                        if (Puzzle.lastTimeoutRef != -1) {

                            callback_func();

                            clearTimeout(Puzzle.lastTimeoutRef);
                            Puzzle.lastTimeoutRef = -1;
                        }
                    }
                }
            });

        }

        if (messageType === Puzzle.messageType.INFO) {
            timeoutAmount = 10000;
            gameCompletionMessage.css({
                "background-color": "#088A08"
            });
        } else if (messageType === Puzzle.messageType.WARNING) {
            timeoutAmount = 5000;
            gameCompletionMessage.css({
                "background-color": "#B40404"
            });
        } else if (messageType === Puzzle.messageType.TEXT) {
            timeoutAmount = 5000;
            gameCompletionMessage.css({
                "background-color": "#FFFFFF",
                "color": "#000000"
            });
        }

        gameCompletionMessage.find("#puzzle-info-message-content").text(message);
        gameCompletionMessage.appendTo($("div.puzzle"));
        gameCompletionMessage.fadeIn();

        if (Puzzle.lastTimeoutRef != -1) {
            clearTimeout(Puzzle.lastTimeoutRef);
            Puzzle.lastTimeoutRef = -1;
        }

        //Auto-hide message
        Puzzle.lastTimeoutRef = setTimeout(function () {
            gameCompletionMessage.fadeOut();

            if (typeof Puzzle.lastMessageCallback != 'undefined')
            {
                var callback_func = eval(Puzzle.lastMessageCallback);

                if ($.isFunction(callback_func))
                {
                    callback_func();
                }
            }

            Puzzle.lastTimeoutRef = -1;

        }, timeoutAmount);
    },
    keepAlive: function () {
        $.ajax({
            dataType: "json",
            type: "POST",
            url: keepAliveURL,
            async: true,
            timeout: 5000,
            data: {
                game_token: gameToken
            },
            success: function (response) {
                //returnVal = response.success;
            }
        });
    },
    createSolutionTimeout: function ()
    {
        if (this.solutionTimeout != -1)
        {
            clearTimeout(this.solutionTimeout);
            this.solutionTimeout = -1;
        }

        var _puzzle = this;
        this.solutionTimeout = setTimeout(function ()//function(_puzzle) 
        {
            //See puzzle.js (invokeSubmitScore) && arrowword.js (setCellValue)
            if (_puzzle.checkAnswers())
            {
                if (!puzzleId || puzzleId.length === 0)
                {
                    alert("This feature cannot be used in preview mode");
                    return;
                } else if (isScoreEnabled)
                {
                    showSubmitScore();
                } else
                {
                    Puzzle.showMessageBox("Congratulations! You have completed the puzzle.", Puzzle.messageType.INFO);
                }

                TrackPuzzle.analyticsEvent("puzzle", "end", "complete");
            }

        }, 200);//, this);
    },

    /**
     * Used for storing last selected elements
     */
    lastSelected: {
        cell: undefined,
        clue: undefined,
        cellGroup: new Array(),
        clueGroup: new Array(),
        cellGroupIndex: 0
    },
    /**
     * Used for storing parent objects (Crossword grid, clue list)
     */
    parentObjects: {
        grid: undefined,
        clues: undefined
    },
    /**
     * Default options for the crossword
     */
    defaults: {
        gridId: "#puzzle-grid",
        cluesId: ".clues li",
        cellsId: ".cell",
        cellInputId: ".cell-input",
        userInputId: "#textInput",
        keywordInputId: ".keyword",
        hintCellId: ".hint",
        cellNumberId: ".cell-number",
        legendCellId: ".legend-cell",
        letterKeyCellId: ".letter-key-letter",
        legendId: "#puzzle-legend",
        letterKeyId: "#puzzle-letter-key",
        blankClass: "blank",
        selectedClass: "active",
        selectedGroupClass: "activegroup",
        invalidCellClass: "invalid",
        inactiveCellClass: "inactive",
        hintCellClass: "hint",
        fontSizeLargeClass: "font-size-large",
        checkButton: "#check-answers",
        hintButton: "#puzzle-hint",
        wordHintButton: "#puzzle-word-hint",
        clearButton: "#puzzle-clear",
        solveButton: "#puzzle-solve",
        submitScoreButton: "#submit-score",
        sendSolutionButton: "#send-solution",
        fontSizeButton: "#change-font-size",
        showToplistButton: "#show-toplist",
        checkGameCompletionButton: "#check-puzzle-complete",
        zoomInButton: "#zoom-in",
        zoomOutButton: "#zoom-out"
    },
    cellEventSource: undefined,
    size: {
        width: 0,
        height: 0
    },
    lastTimeoutRef: -1,
    messageType: {
        INFO: 0,
        WARNING: 1
    }
};

//Below are generic functions shared by all puzzles.

var userInitiatedTutorial = false;
function showTutorial(force) {
    if (hasTutorial == '0')
        return;

    var animate = false;
    if (force)
    {
        animate = true;
        if (GameState && GameState.isCookiesSupported())
            GameState.setCookie(getTutorialCookieName(), "");
    } else if (GameState && GameState.isCookiesSupported())
    {
        var cookieName = getTutorialCookieName();
        var cookieResult = GameState.getCookie(cookieName);
        if (cookieResult != false)
            return;
    }


    userInitiatedTutorial = animate;

    if (puzzleTimer && (!userInitiatedTutorial || pauseTutorial))
    {
        puzzleTimer.stop();
    }

    $('#puzzle-tutorial').addClass('visible');

    if (animate)
    {
        $('#puzzle-tutorial').fadeIn();
        $('#puzzle-dimmed-layer-tutorial').fadeIn(function ()
        {
            if (puzzleTimer && (!userInitiatedTutorial || pauseTutorial))
            {
                puzzleTimer.stop();
            }
        });
    } else
    {
        $('#puzzle-tutorial').show();
        $('#puzzle-dimmed-layer-tutorial').show();
    }
}

function hideTutorial() {

    $('#puzzle-tutorial').removeClass('visible');

    $('#puzzle-tutorial').fadeOut();
    $('#puzzle-dimmed-layer-tutorial').fadeOut();

    if (puzzleTimer && (!userInitiatedTutorial || pauseTutorial))
        puzzleTimer.resume();

    if (GameState && GameState.isCookiesSupported())
        GameState.setCookie(getTutorialCookieName(), 1);

    if (typeof (onHideTutorial) == typeof (Function))
    {
        onHideTutorial(userInitiatedTutorial);
    }
}

function getTutorialCookieName()
{
    return puzzleUniqueHash + "_tutorial";
}

function isTutorialVisible() {
    return $("#puzzle-tutorial").hasClass("visible");
}

setTimeout(function ()
{
    showTutorial();
}, 20);

//GS BUG #3893
setInterval(function () {
    $("#save-game").click();
}, 10000);
//GS BUG #3893