/*
**  Memory Game - a card game also knowned as Concentration.
**  Copyright (C) 2010 SaferNet Brasil <contato@safernet.org.br>
**  Author: Aurélio A. Heckert <aurium(a)gmail:com>
**
**  This program is free software: you can redistribute it and/or modify
**  it under the terms of the GNU Affero General Public License as
**  published by the Free Software Foundation, either version 3 of the
**  License, or (at your option) any later version.
**
**  This program 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 Affero General Public License for more details.
**
**  You should have received a copy of the GNU Affero General Public License
**  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


var MEMORYGAME_DEBUG = true;

function MemoryGame( conf ) {
  if ( typeof( conf.parent ) == "string" ) {
    conf.parent = document.getElementById( conf.parent );
  }
  this.conf = conf;
  var game = this;
  try {
    imgLoaderConf = {
      parent: conf.parent,
      onLoad: function(){ game.constructGame(); },
      timeout: conf.imgLoadTimeout,
      imgs: []
    };
    for ( var imgUrl,i=0; imgUrl=conf.imgs[i]; i++ ) {
      imgLoaderConf.imgs[i] = imgUrl;
    }
    imgLoaderConf.imgs[i] = conf.hiddenImg;
    new ImgLoader( imgLoaderConf );
  } catch(err) {
    this.debug( "constructor", err );
  }
}

MemoryGame.prototype.debug = function ( methodName, err ) {
  if ( IMGLOADER_DEBUG ) {
    alert( "ImgLoader."+methodName+"()\n" + ( err.description? err.description : err ) );
  }
}

MemoryGame.prototype.constructGame = function () {
  this.cardURLs = [];
  // make an array with duplicate cards:
  for ( var imgUrl,i=0; imgUrl=this.conf.imgs[i]; i++ ) {
    this.cardURLs[i*2] = imgUrl;
    this.cardURLs[(i*2)+1] = imgUrl;
  }
  // Shuffle the cards:
  var totCards = this.cardURLs.length;
  for ( var i=0; i<totCards; i++ ) {
    var newPosition = i;
    while ( newPosition == i ) { // force a diferent position
      newPosition = Math.round( Math.random()*(totCards-1) );
    }
    var tmpCard = this.cardURLs[i];
    this.cardURLs[i] = this.cardURLs[newPosition];
    this.cardURLs[newPosition] = tmpCard;
  }
  
  this.gameBox = $('<div class="memory-game-box"></div>');
  this.gameBox.appendTo( this.conf.parent );

  var game = this;
  this.cardURLs.last = 0;
  setTimeout( function(){ game.addCard() }, 100 );
}

MemoryGame.prototype.destroy = function () {
  this.conf.parent.removeChild( this.gameBox[0] );
}

MemoryGame.prototype.addCard = function () {
  var game = this;
  var imgUrl = this.cardURLs[this.cardURLs.last];
  var card = $('<div class="memory-game-card" img="'+imgUrl+'"'+
               ' onclick="this.game.cardClick(this)">'+
               '<img src="'+this.conf.hiddenImg+'"/></div>');
  card.appendTo( this.gameBox );
  // "card" is a jQuery object
  // "card[0]" is a HTML object
  card[0].game = this;
  this.cardURLs.last++;
  if ( this.cardURLs[this.cardURLs.last] ) {
    setTimeout( function(){ game.addCard() }, 100 );
  }
}

MemoryGame.prototype.totPairFound = 0;
MemoryGame.prototype.pairFound = function (card1, card2) {
  card1.className += " memory-game-pair-found";
  card2.className += " memory-game-pair-found";
  this.totPairFound++;
  this.conf.onPairFound( this, card1, card2 );
  if ( this.totPairFound == this.conf.imgs.length ) {
    this.gameCompleted();
  }
}

MemoryGame.prototype.gameCompleted = function () {
  this.gameEnd = new Date();
  var game = this;
  setTimeout( function(){ game.conf.onGameCompleted(game)  }, 300 );
}

MemoryGame.prototype.cardClick = function (card) {
  if ( !card.opened ) {
    if ( !this.gameStart ) { this.gameStart = new Date() }
    var first = this.firstCardOpened || false;
    card.opened = true;
    var img = card.firstChild;
    img.src = card.getAttribute("img");
    if ( first ) {
      if ( first.getAttribute("img") == card.getAttribute("img") ) {
        this.pairFound( this.firstCardOpened, card );
      } else {
        var game = this;
        setTimeout( function(){ game.hiddenCard(first) }, 400 );
        setTimeout( function(){ game.hiddenCard(card)  }, 600 );
      }
      this.firstCardOpened = false;
    } else {
      this.firstCardOpened = card;
    }
  }
}

MemoryGame.prototype.hiddenCard = function (card) {
  /*
  Old way (without animation):
  card.firstChild.src = this.conf.hiddenImg;
  card.opened = false;
  */
  var continueFlip = true;
  var steps = 5;
  var img = card.firstChild;
  if ( !card.origMargin ){
    if ( typeof(card.currentStyle) != "undefined" ) {
      var cardStyle = card.currentStyle;
      var imgStyle  = img.currentStyle;
    } else {
      var cardStyle = document.defaultView.getComputedStyle(card, null);
      var imgStyle  = document.defaultView.getComputedStyle(img, null);
    }
    card.origMargin = {
      left: parseInt(cardStyle.marginLeft),
      right: parseInt(cardStyle.marginRight)
    };
    card.origPadding = {
      left: parseInt(cardStyle.paddingLeft),
      right: parseInt(cardStyle.paddingRight)
    };
    img.origWidth = img.clientWidth;
    img.origHeight = img.clientHeight;
    img.origHeight += "px";
    card.step = steps;
    card.splitSize = img.origWidth / steps;
    card.inc = -1;
  }
  if ( card.inc == -1 ) { // reducing card
    if ( card.step > 1 ) {
      card.step--;
      img.style.height = img.origHeight;
      var w = parseInt(card.splitSize*card.step);
      img.style.width = w+"px";
      card.style.marginLeft  = (card.origMargin.left+(img.origWidth-w)/2)+"px";
      card.style.marginRight = (card.origMargin.right+(img.origWidth-w)/2)+"px";
    } else {
      card.step = 0;
      img.style.display = "none";
      card.style.paddingLeft  = "0px";
      card.style.paddingRight = "0px";
      card.style.marginLeft  =
        ( card.origMargin.left + (img.origWidth/2) + card.origPadding.left )+"px";
      card.style.marginRight =
        ( card.origMargin.right + (img.origWidth/2) + card.origPadding.right )+"px";
      card.inc = 1;
    }
  } else { // growing card
    if ( card.step == 0 ) {
      card.style.paddingLeft  = card.origPadding.left+"px";
      card.style.paddingRight = card.origPadding.right+"px";
      img.src = this.conf.hiddenImg;
      img.style.display = "inline";
    }
    if ( card.step < steps ) {
      card.step++;
      img.style.height = img.origHeight;
      var w = parseInt(card.splitSize*card.step);
      img.style.width = w+"px";
      card.style.marginLeft  = (card.origMargin.left+(img.origWidth-w)/2)+"px";
      card.style.marginRight = (card.origMargin.right+(img.origWidth-w)/2)+"px";
    } else { // end flip
      continueFlip = false;
      card.opened = false;
      card.style.marginLeft  = card.origMargin.left+"px";
      card.style.marginRight = card.origMargin.right+"px";
      card.step = steps;
      card.inc = -1;
    }
  }
  if ( continueFlip ) {
    var game = this;
    setTimeout( function(){ game.hiddenCard(card) }, 30 );
  }
}

