/*
 *     This file is part of KONRI.com iPgames.
 *
 *     KONRI.com iPgames is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     KONRI.com iPgames is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 *     This file is part of KONRI.com iPgames.
 *
 *     KONRI.com iPgames is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     KONRI.com iPgames is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

var numberOfColumns = 19;
var numberOfRows = 16;

var currentLevel = 0;
var movesCounter = 0;

var grid;
var workerPosition = [0, 0];

var levelDefinition;

function removeAllChildren(parent) {
    while (parent.hasChildNodes())
        parent.removeChild(parent.firstChild);
}

function resetGrid(level) {
    movesCounter = 0;
    levelDefinition = levels[level];

    grid = new Array(numberOfColumns);

    for (var x = 0; x < numberOfColumns; x++) {
        grid[x] = new Array(numberOfRows);

        for (var y = 0; y < numberOfRows; y++) {
            grid[x][y] = levelDefinition[y].charAt(x);

            if (grid[x][y] == "*")
                workerPosition = [x, y]
        }
    }
}

function gridElementToImageName(gridElement) {
    switch (gridElement) {
        case ".":
            return "empty.png";
        case "X":
            return "brick.png";
        case "o":
            return "package.png";
        case "#":
            return "package_place.png";
        case "*":
            return "worker.png";
    }
    return "empty.png";
}

function setup() {
    currentLevel = readGameLevel();
    if (currentLevel == null)
        currentLevel = 0;
    initNewLevel();
}

function initNewLevel() {
    storeGameData(currentLevel);
    resetGrid(currentLevel);
    updateCounter();

    var gridTable = document.getElementById('grid');
    removeAllChildren(gridTable);

    for (var y = 0; y < numberOfRows; y++) {
        var row = document.createElement('tr');
        row.setAttribute("height", "15px");
        for (var x = 0; x < numberOfColumns; x++) {
            var col = document.createElement('td');

            var img = document.createElement('img');
            img.setAttribute("onclick", "click(" + x + "," + y + ")");
            img.setAttribute("src", gridElementToImageName(grid[x][y]));
            img.setAttribute("id", x + "_" + y);
            img.setAttribute("width", "15px");
            img.setAttribute("height", "15px");
            col.appendChild(img);
            row.appendChild(col);
        }
        gridTable.appendChild(row);
    }
}

function updateCell(x, y) {
    document.images[x + "_" + y].src = gridElementToImageName(grid[x][y]);
}

function click(x, y) {
    var levelCompleted = checkIfCompleted()

    var oldWorkerX = workerPosition[0];
    var oldWorkerY = workerPosition[1];

    var horizontalMove = x - oldWorkerX;
    var verticalMove = y - oldWorkerY;
    if (Math.abs(horizontalMove) > Math.abs(verticalMove))
        verticalMove = 0;
    else
        horizontalMove = 0;

    horizontalMove = Math.min(Math.max(horizontalMove, -1), 1);
    verticalMove = Math.min(Math.max(verticalMove, -1), 1);
    //    alert("Move: " + horizontalMove + ", " + verticalMove);

    var newWorkerX = oldWorkerX + horizontalMove;
    var newWorkerY = oldWorkerY + verticalMove;

    switch (grid[newWorkerX][newWorkerY]) {
        case "o":
        // push ?
            var canPush = grid[newWorkerX + horizontalMove][newWorkerY + verticalMove] == "." ||
                          grid[newWorkerX + horizontalMove][newWorkerY + verticalMove] == "#";

            if (canPush) {
                grid[newWorkerX + horizontalMove][newWorkerY + verticalMove] = "o";
                updateCell(newWorkerX + horizontalMove, newWorkerY + verticalMove);
                grid[oldWorkerX][oldWorkerY] = levelDefinition[oldWorkerY].charAt(oldWorkerX) == "#" ? "#" : ".";
                grid[newWorkerX][newWorkerY] = "*";

                updateCell(oldWorkerX, oldWorkerY);
                updateCell(newWorkerX, newWorkerY);

                workerPosition[0] += horizontalMove;
                workerPosition[1] += verticalMove;

                if (!levelCompleted)
                    movesCounter++;
            }
            break;
        case "#":
        case ".":
        // walk
            grid[oldWorkerX][oldWorkerY] = levelDefinition[oldWorkerY].charAt(oldWorkerX) == "#" ? "#" : ".";
            grid[newWorkerX][newWorkerY] = "*";

            updateCell(oldWorkerX, oldWorkerY);
            updateCell(newWorkerX, newWorkerY);

            workerPosition[0] += horizontalMove;
            workerPosition[1] += verticalMove;

            if (!levelCompleted)
                movesCounter++;
            break;
        case "X":
        // beep ?
            break;
    }

    updateCounter();
}

function updateCounter() {
    if (checkIfCompleted())
        document.getElementById("movesCounter").innerHTML = "Completed in: " + movesCounter;
    else
        document.getElementById("movesCounter").innerHTML = "Moves: " + movesCounter;
}

function checkIfCompleted() {
    for (var x = 0; x < numberOfColumns; x++) {
        for (var y = 0; y < numberOfRows; y++) {
            // # means there is still empty cell
            if (grid[x][y] == "#")
                return false;
        }
    }
    return true;
}

function nextLevel() {
    if (currentLevel + 1 < levels.length) {
        currentLevel++;
        initNewLevel();
    }
}

function previousLevel() {
    if (currentLevel > 0) {
        currentLevel--;
        initNewLevel();
    }
}

function storeGameData(gameLevel) {
    var expdate = new Date();
    expdate.setTime(expdate.getTime() + (1000 * 60 * 60 * 24 * 31));
    setCookie("sokoban_level", gameLevel, expdate);
}

function readGameLevel() {
    return getCookie("sokoban_level");
}

function getCookie(name) {
    var dcookie = document.cookie;
    var cname = name + "=";
    var clen = dcookie.length;
    var cbegin = 0;
    while (cbegin < clen) {
        var vbegin = cbegin + cname.length;
        if (dcookie.substring(cbegin, vbegin) == cname) {
            var vend = dcookie.indexOf(";", vbegin);
            if (vend == -1) vend = clen;
            return unescape(dcookie.substring(vbegin, vend));
        }
        cbegin = dcookie.indexOf(" ", cbegin) + 1;
        if (cbegin == 0) break;
    }
    return null;
}

function setCookie(name, value, expires) {
    if (!expires) expires = new Date();
    document.cookie = name + "=" + escape(value) + "; expires=" + expires.toGMTString() + "; path=/";
}


var levels = new Array(
        new Array(
                "...................",
                "...................",
                "...................",
                "......XXX..........",
                "......X#X..........",
                "......X.XXXX.......",
                "....XXXo.o#X.......",
                "....X#.o*XXX.......",
                "....XXXXoX.........",
                ".......X.X.........",
                ".......X#X.........",
                ".......XXX.........",
                "...................",
                "...................",
                "...................",
                "..................."
                ),

        new Array(
                "...................",
                "...................",
                "...................",
                "....XXXXX..........",
                "....X...X..........",
                "....Xo..X..........",
                "..XXX..oXX.........",
                "..X..o.o.X.........",
                "XXX.X.XX.X...XXXXXX",
                "X...X.XX.XXXXX..##X",
                "X.o..o..........##X",
                "XXXXX.XXX.X*XX..##X",
                "....X.....XXXXXXXXX",
                "....XXXXXXX........",
                "...................",
                "..................."
                ),

        new Array(
                "...................",
                "...................",
                "...XXXXXXXXXXXX....",
                "...X##..X.....XXX..",
                "...X##..X.o..o..X..",
                "...X##..XoXXXX..X..",
                "...X##....*.XX..X..",
                "...X##..X.X..o.XX..",
                "...XXXXXX.XXo.o.X..",
                ".....X.o..o.o.o.X..",
                ".....X....X.....X..",
                ".....XXXXXXXXXXXX..",
                "...................",
                "...................",
                "...................",
                "..................."
                ),

        new Array(
                "...................",
                "...................",
                "...................",
                ".........XXXXXXXX..",
                ".........X.....*X..",
                ".........X.oXo.XX..",
                ".........X.o..oX...",
                ".........XXo.o.X...",
                ".XXXXXXXXX.o.X.XXX.",
                ".X####..XX.o..o..X.",
                ".XX###....o..o...X.",
                ".X####..XXXXXXXXXX.",
                ".XXXXXXXX..........",
                "...................",
                "...................",
                "..................."
                ),

        new Array(
                "...................",
                "...........XXXXXXXX",
                "...........X..####X",
                "XXXXXXXXXXXX..####X",
                "X....X..o.o...####X",
                "X.oooXo..o.X..####X",
                "X..o.....o.X..####X",
                "X.oo.Xo.o.oXXXXXXXX",
                "X..o.X.....X.......",
                "XX.XXXXXXXXX.......",
                "X....X....XX.......",
                "X.....o...XX.......",
                "X..ooXoo..*X.......",
                "X....X....XX.......",
                "XXXXXXXXXXX........",
                "..................."
                ),

        new Array(
                "...................",
                ".........XXXXX.....",
                ".........X...XXXXX.",
                ".........X.X.XX..X.",
                ".........X.....o.X.",
                ".XXXXXXXXX.XXX...X.",
                ".X####..XX.o..oXXX.",
                ".X####....o.oo.XX..",
                ".X####..XXo..o.*X..",
                ".XXXXXXXXX..o..XX..",
                ".........X.o.o..X..",
                ".........XXX.XX.X..",
                "...........X....X..",
                "...........X....X..",
                "...........XXXXXX..",
                "..................."
                )

//        new Array(
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "...................",
//                "..................."
//                )
        );