Object.create = function (o)
{
    function F() {}
    F.prototype = o;
    return new F();
};

Node.prototype.removeAllChildren = function ()
{
    while(this.hasChildNodes()) {
        this.removeChild(this.firstChild);
    }
}


var MemoryGame = (function () {        // namespace
    var CARDSIZE = 104;
    var FRONTIMSIZE = 100;
    var BACKIMSIZE = 50;

    var Card = {
        prototype: {
            flip: function ()
            {
                this.revealed = !this.revealed;
                this.paint();
            },

            reveal: function ()
            {
                this.revealed = true;
                this.paint();
            },

            hide: function ()
            {
                this.revealed = false;
                this.paint();
            },

            paint: function ()
            {
                this.elt.removeAllChildren();
                this.elt.appendChild(this.revealed ? this.front : this.back);
                return this;
            }
        },

        create: function (i) {
            var card;

            card = Object.create(this.prototype);
            card.imgid = i
            card.revealed = false;

            card.elt = document.createElement("div");
            card.elt.style.display = "inline-block";
            card.elt.className = "card"

            card.front = document.createElement("img");
            card.front.src = "img/" + i + ".png";
            card.front.height = card.front.width = FRONTIMSIZE;
            card.front.style.padding = (CARDSIZE-FRONTIMSIZE)/2;
            card.front.className = "cardfront"

            card.back = document.createElement("img");
            card.back.src = "back.png";
            card.back.height = card.back.width = BACKIMSIZE;
            card.back.style.padding = (CARDSIZE-BACKIMSIZE)/2;
            card.back.className = "cardback"

            card.paint();

            return card;
        }
    };


    var protogame = {
        reveal_all: function ()
        {
            for(var i=0; i<this.cards.length; i++) {
                this.cards[i].reveal();
            }
        },

        hide_all: function ()
        {
            for(var i=0; i<this.cards.length; i++) {
                this.cards[i].hide();
            }
        },

        hide_open: function ()
        {
            for(var i=0; i<this.open.length; i++) {
                this.open[i].hide();
            }
            this.open = [];
        },

        click: function (cardnum)
        {
            var card = this.cards[cardnum];

            // clicks on revealed cards have no effect
            if(!card.revealed) {
                // if already two open, hide them first
                if(this.open.length >= 2) {
                    this.hide_open();
                }

                // open this card
                card.reveal();
                this.open[this.open.length] = card;

                // if two matching cards are open, release them
                if(this.open.length == 2
                        && this.open[0].imgid == this.open[1].imgid) {
                    this.open = [];
                }
            }
        }
    };


    // generate a random permutation of n elements
    function randperm(n)
    {
        var i,j;
        var p = [];
        var tmp;

        for(i=n-1; i>0; i--) {
            j = Math.floor(Math.random() * (i+1));

            tmp = p[i] || i;
            p[i] = p[j] || j;
            p[j] = tmp;
        }

        return p;
    }

    // build an n-by-m game grid in html element elt
    function build(n,m, elt)
    {
        var num_images = (n*m)/2;
        var rowdiv;
        var i,j;

        if((n*m)%2) {
            throw "MemoryGame.build: number of cards not even";
        }

        game = Object.create(protogame);
        game.cards = [];
        game.open = []; // set of "open" cards (revealed but maybe not matching)

        permutation = randperm(n*m);

        elt.removeAllChildren();
        for(i=0; i<n; i++) {
            // build one row
            rowdiv = elt.appendChild(document.createElement("div"));
            rowdiv.className = "gamerow";
            for(j=0; j<m; j++) (function () {
                var cardnum;
                var imgid;
                var card;

                cardnum = i*m+j;
                imgid = permutation[cardnum] % num_images;
                card = game.cards[cardnum] = Card.create(imgid);

                rowdiv.appendChild(card.elt)
                card.elt.onclick = function () { game.click(cardnum); }
            })();
        }

        return game;
    }

    // public interface
    return {
        build: build
    };

})();

// autobuild game if an element with id "gamefield" exists
(function () {
    gamefield = document.getElementById("gamefield");
    if(gamefield) {
        MemoryGame.build(4,5, gamefield);
    }
})();


// vim: et ts=4 sw=4

