﻿
(function ($) {

    var defaults = {
        rows: 10,
        cols: 15,
        mines: 30,
        url: '/LetsConnect?ms=1'
    };

    $.fn.Minesweeper = function (o) {
        return this.each(function () {
            $(this).data('minesweeper', new $ms(this, o));
        });
    }

    $.Minesweeper = function (e, o) {

        this.options = $.extend({}, defaults, o || {});
        this.minesweeper = e;
        this.table = null;
        this.wrap = null;
        this.instructions = null;

        this.name = "Minesweeper";
        this.tableArray = new Array();
        this.minesCnt = 0;

        this.init();
    }

    var $ms = $.Minesweeper;
    $ms.fn = $ms.prototype = {
        minesweeper: '0.0.1'
    };

    $ms.fn.extend = $ms.extend = $.extend;

    $ms.fn.extend({

        init: function () {

            $("#rc_minesweeper").remove();

            this.wrap = $("<div id='rc_minesweeper'></div>").appendTo(this.minesweeper);
            this.table = $("<table border='0' cellspacing='1' cellpadding='0'></table>").appendTo(this.wrap);


            this.instructions = $("<div class='instructions'><span style='float: right'>Right-click to flag a cell.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href='"+this.options.url+"' style='color:white'>Contact us</a>&nbsp;&nbsp;<a onclick='$(\"#rc_minesweeper\").fadeTo(\"fast\",0);$(\"#rc_minesweeper\").remove();'>[X]</a></span><span class='mineCnt' style='float: left'>Mines: <span>" + this.options.mines + "</span></span></div>").appendTo(this.wrap);

            // setup the table
            for (var r = 0; r < this.options.rows; r++) {
                var tr = $("<tr></tr>").appendTo(this.table);
                this.tableArray[r] = new Array();
                for (var c = 0; c < this.options.cols; c++) {
                    var td = $("<td class='close' id='" + r + ":" + c + "'></td>").appendTo(tr);
                    td.bind("contextmenu", { self: this }, this.flagCell);
                    td.bind("click", { self: this }, this.revealCell);
                    this.tableArray[r][c] = "";
                }
            }

            // add the mines
            for (var i = 0; i < this.options.mines; i++) {
                var rnd = Math.floor(Math.random() * this.options.rows * this.options.cols);
                var row = Math.floor(rnd / this.options.cols);
                var col = Math.floor(rnd % this.options.cols);

                if (this.tableArray[row][col] == "*")
                    i--;
                else
                    this.tableArray[row][col] = "*";
            }


            // add the mine counts
            for (var r = 0; r < this.options.rows; r++) {
                for (var c = 0; c < this.options.cols; c++) {

                    if (this.tableArray[r][c] == "*")
                        continue;

                    var count = 0;
                    var tl = (r == 0 || c == 0) ? null : this.tableArray[r - 1][c - 1];
                    var tm = (r == 0) ? null : this.tableArray[r - 1][c];
                    var tr = (r == 0 || c == (this.options.cols - 1)) ? null : this.tableArray[r - 1][c + 1];
                    var lt = (c == 0) ? null : this.tableArray[r][c - 1];
                    var rt = (c == (this.options.cols - 1)) ? null : this.tableArray[r][c + 1];
                    var bl = (r == (this.options.rows - 1) || c == 0) ? null : this.tableArray[r + 1][c - 1];
                    var bm = (r == (this.options.rows - 1)) ? null : this.tableArray[r + 1][c];
                    var br = (r == (this.options.rows - 1) || c == (this.options.cols - 1)) ? null : this.tableArray[r + 1][c + 1];

                    if (tl != null && tl == "*") count++;
                    if (tm != null && tm == "*") count++;
                    if (tr != null && tr == "*") count++;
                    if (lt != null && lt == "*") count++;
                    if (rt != null && rt == "*") count++;
                    if (bl != null && bl == "*") count++;
                    if (bm != null && bm == "*") count++;
                    if (br != null && br == "*") count++;

                    if (count == 0) count = "";
                    this.tableArray[r][c] = count.toString();

                }
            }

            //this.showBoard(this); 
        }, // end init

        showBoard: function (data) {
            var self = data;

            if (data.data)
                self = data.data.self;

            for (var r = 0; r < self.options.rows; r++) {
                for (var c = 0; c < self.options.cols; c++) {
                    var tr = $(this.table).find("tr").get(r);
                    var td = $(tr).find("td").get(c);

                    var val = self.tableArray[r][c];

                    $(td).children().remove();
                    $(td).addClass("open");
                    $(td).removeClass("close");

                    // mine
                    if (val == "*")
                        $("<span class='mine'>*</span>").appendTo(td);
                    else
                        $("<span class='count'>" + val + "</span>").appendTo(td);
                }
            }
        }, // end showBoard

        checkWinner: function (data) {
            var self = data;
            if (data.data != null)
                self = data.data.self;

            var closeCnt = 0;
            for (var r = 0; r < self.options.rows; r++) {
                for (var c = 0; c < self.options.cols; c++) {
                    var tr = $(this.table).find("tr").get(r);
                    var td = $(tr).find("td").get(c);

                    if ($(td).hasClass("close")) closeCnt++;
                }
            }

            return (closeCnt == self.options.mines);
        }, // end checkWinner

        revealCell: function (data, cell) {
            /*for(var i in data)
            alert(i + " ==> " + data[i]);*/
            var self = data.data.self;

            var td = data.currentTarget;

            if (cell != null) td = cell;

            // remove a flag if there's one on this cell
            if ($(td).find(".flag").length > 0) $(td).find(".flag").remove();

            // if this is open already, return
            if ($(td).hasClass("open")) return;

            // reveal adjacent cells if they are 0 or the current cell is 0
            var r = parseInt($(td).attr("id").split(":")[0]);
            var c = parseInt($(td).attr("id").split(":")[1]);

            // determine if this is a mine and show game over
            if (self.tableArray[r][c] == "*") {
                self.gameOver(data);
                return;
            }
            else {
                $(td).children().remove();
                $("<span class='count'>" + self.tableArray[r][c] + "</span>").appendTo(td);
                $(td).removeClass("close");
                $(td).addClass("open");
                $(td).css("background-color", "white");
            }

            // reveal adjacent cells if they are 0 or the current cell is 0
            var openAll = parseInt(self.tableArray[r][c]);

            var tl = (r == 0 || c == 0) ? null : self.tableArray[r - 1][c - 1];
            var tm = (r == 0) ? null : self.tableArray[r - 1][c];
            var tr = (r == 0 || c == (self.options.cols - 1)) ? null : self.tableArray[r - 1][c + 1];
            var lt = (c == 0) ? null : self.tableArray[r][c - 1];
            var rt = (c == (self.options.cols - 1)) ? null : self.tableArray[r][c + 1];
            var bl = (r == (self.options.rows - 1) || c == 0) ? null : self.tableArray[r + 1][c - 1];
            var bm = (r == (self.options.rows - 1)) ? null : self.tableArray[r + 1][c];
            var br = (r == (self.options.rows - 1) || c == (self.options.cols - 1)) ? null : self.tableArray[r + 1][c + 1];

            if (tl != null) {
                var tlc = $($(self.table).find("tr").get(r - 1)).find("td").get(c - 1);
                if ($(tlc).find(".flag").length == 0 && tl != "*") {
                    var cnt = parseInt(tl);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = tlc;
                        setTimeout(function () { self.revealCell(data, tlc); }, 300);
                    }
                }
            }

            if (tm != null) {
                var tmc = $($(self.table).find("tr").get(r - 1)).find("td").get(c);
                if ($(tmc).find(".flag").length == 0 && tm != "*") {
                    var cnt = parseInt(tm);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = tlc;
                        setTimeout(function () { self.revealCell(data, tmc); }, 300);
                    }
                }
            }

            if (tr != null) {
                var trc = $($(self.table).find("tr").get(r - 1)).find("td").get(c + 1);
                if ($(trc).find(".flag").length == 0 && tr != "*") {
                    var cnt = parseInt(tr);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = trc;
                        setTimeout(function () { self.revealCell(data, trc); }, 300);
                    }
                }
            }

            if (lt != null) {
                var ltc = $($(self.table).find("tr").get(r)).find("td").get(c - 1);
                if ($(ltc).find(".flag").length == 0 && lt != "*") {
                    var cnt = parseInt(lt);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = ltc;
                        setTimeout(function () { self.revealCell(data, ltc); }, 300);
                    }
                }
            }

            if (rt != null) {
                var rtc = $($(self.table).find("tr").get(r)).find("td").get(c + 1);
                if ($(rtc).find(".flag").length == 0 && rt != "*") {
                    var cnt = parseInt(rt);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = rtc;
                        setTimeout(function () { self.revealCell(data, rtc); }, 300);
                    }
                }
            }

            if (bl != null) {
                var blc = $($(self.table).find("tr").get(r + 1)).find("td").get(c - 1);
                if ($(blc).find(".flag").length == 0 && bl != "*") {
                    var cnt = parseInt(bl);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = blc;
                        setTimeout(function () { self.revealCell(data, blc); }, 300);
                    }
                }
            }

            if (bm != null) {
                var bmc = $($(self.table).find("tr").get(r + 1)).find("td").get(c);
                if ($(bmc).find(".flag").length == 0 && bm != "*") {
                    var cnt = parseInt(bm);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = bmc;
                        setTimeout(function () { self.revealCell(data, bmc); }, 300);
                    }
                }
            }

            if (br != null) {
                var brc = $($(self.table).find("tr").get(r + 1)).find("td").get(c + 1);
                if ($(brc).find(".flag").length == 0 && br != "*") {
                    var cnt = parseInt(br);
                    if (openAll.toString() == "NaN") { // && cnt.toString() == "NaN") {
                        data.currentTarget = brc;
                        setTimeout(function () { self.revealCell(data, brc); }, 300);
                    }
                }
            }

            if (self.checkWinner(data))
                self.showWinner(data);


        }, // end revealCell

        flagCell: function (data) {
            var self = data.data.self;
            var td = data.currentTarget;
            var mineCnt = parseInt($($($(self.instructions).find(".mineCnt")).find("span")).text());

            if ($(td).find(".flag").length == 0) {

                if (mineCnt == 0) {
                    alert("Sorry.  You can't flag any more cells.");
                    return false;
                }

                $("<span class='flag'>F</span>").appendTo(td);
                mineCnt--;
            }
            else {
                $($(td).find(".flag")).remove();
                mineCnt++;
            }

            // update mine count
            $($($(self.instructions).find(".mineCnt")).find("span")).text(mineCnt);

            // return false removes the browser's context menu
            return false;
        }, // end flagCell

        gameOver: function (data) {
            var self = data.data.self;

            this.showBoard(data);

            // mark the incorrect one
            $(data.currentTarget).css("background-color", "red");

            if (confirm("YOU LOST: Want to play again?"))
                this.init();
            else
                this.showThanks(data);

        }, // end gameOver

        showWinner: function (data) {
            var self = data.data.self;
            self.showBoard(data);
            if (confirm("YOU WON: Want to play again?"))
                self.init();
            else
                self.showThanks(data);
        }, // end showWinner

        showThanks: function (data) {

            var self = data.data.self;
            $(self.table).fadeTo("slow", .3);
            var thanks = $("<div class='thanks' style='z-index 200'>Thanks for playing Roundedcube's version of Minesweeper.  Want your own? <a href='" + self.options.url + "'>Contact us</a>.</div>").appendTo(self.wrap);

        } // end showThanks

    });

})(jQuery);
