/* memory.js
 * copyright (c) by X
 */

var EMPTY=   -1;
var OFF=     0;
var HIDDEN=  1;
var SHOWN=   2;


/**
 * The Memory Image describes an memory card image.
 */
function MemoryImage(pathImage)
{
  this.image= new Image();
  this.image.src= pathImage;
  this.inUse= false;
}

/**
 * The Memory Card is gets into a Memory Field.
 * @param name  The card's name equals a document's image -> required.
 * @param img  The initialisation image.
 * @param state  The initialisation state.
 */
function MemoryCard(name, img, state)
{
  this.name= name;
  this.memoryImage= null;
  this.image= img;
  this.state= state;
}



/**
 * The Memory Object. Use this to create the memory variables.
 * @param document  The document this memory will be shown.
 * @param pathImageOff  Image source for empty memory fields.
 * @param pathImageHidden  Image source for the memory card background.
 * @param pathCardImages  An array of all card images you have.
 */
function Memory(document, nRow, nCol, swapTime, pathImageOff, pathImageHidden, pathCardImages)
{
  this.document= document;
  this.imgOff= new Image(); this.imgOff.src= pathImageOff;
  this.imgHid= new Image(); this.imgHid.src= pathImageHidden;
  this.nRow= nRow;
  this.nCol= nCol;
  this.mcOne= -1;
  this.mcTwo= -1;
  this.swapTime= swapTime;
  this.timeOutID= null;
  this.counter= 0;
  //
  // creates the memory images according the given array of source paths
  this.arrMemoryImages= new Array(2*pathCardImages.length);
  for (var i=0; i<this.arrMemoryImages.length; i++) {
    this.arrMemoryImages[i]= new MemoryImage(pathCardImages[i%pathCardImages.length]);
  }
  //
  // creates the memory cards.
  this.arrMemoryCards= new Array(2*pathCardImages.length);
  for (var i=0; i<this.arrMemoryCards.length; i++) {
    this.arrMemoryCards[i]= new MemoryCard("card"+i, this.imgOff, EMPTY);
  }
  //
  // modifies the document
  with (document) {
    writeln('<table align="left" valign="top" border="0" cellpadding="2" cellspacing="0">');
    var i=0;
    for (var r=0; r<nRow; r++) {
      writeln('<tr>');
      for (var c=0; c<nCol; c++) {
        writeln('<td><a href="" onClick="cardClicked(memory, \u0027'+this.arrMemoryCards[i].name+'\u0027);return false">'
        	 +'<img height="70" width="70"  border="0" '
          +'name="'+this.arrMemoryCards[i].name+'"  '
          +'src="'+this.arrMemoryCards[i].image.src+'"></td>');
        i++;
      }
      writeln('</tr>');
    }
    writeln('</table>');
  }
}

  /**
   * Returns the memory card index.
   */
  function getMemoryCardIndex(memory, name) {
    var i=0;
    while (i<memory.arrMemoryCards.length) {
      if (memory.arrMemoryCards[i].name==name) {
        return i;
      }
      i++;
    }
    return -1;
  }


  /**
   * Sets the state of a memory card.
   * @param memory  the memory reference.
   * @param index  the card's index.
   * @param state  the card's new state.
   */
  function setMemoryCardState(memory, index, state) {
    with (memory) {
      if (index>=0 && index<arrMemoryCards.length) {

			     if (state==EMPTY)  {arrMemoryCards[index].memoryImage= null;arrMemoryCards[index].image= imgOff;}
			else if (state==OFF)    arrMemoryCards[index].image= imgOff;
			else if (state==HIDDEN) arrMemoryCards[index].image= imgHid;
			else if (state==SHOWN)  arrMemoryCards[index].image= arrMemoryCards[index].memoryImage.image;
        arrMemoryCards[index].state= state;
        memory.document.images[arrMemoryCards[index].name].src= arrMemoryCards[index].image.src;
      }
    }
  }

  /**
   * Used to initialize a memory card.
   */
  function initMemoryCard(memory, index, memoryImage) {
    with (memory) {
      if (index>=0 && index<arrMemoryCards.length && !memoryImage.inUse) {
        memoryImage.inUse= true;
        arrMemoryCards[index].memoryImage= memoryImage;
        setMemoryCardState(memory, index, OFF);
      }
    }
  }



/**
 * This method resets the current memory state.
 * First all memory images will get a new state: inUse=false
 * After that the memory cards will be shown as
 */
function resetMemory(memory)
{
  with (memory) {
    counter= 0;
    mcOne= -1;
    mcTwo= -1;
    //
    // set off all cards
    //
    for (var i=0; i<arrMemoryImages.length; i++) {
      arrMemoryImages[i].inUse= false;
      setMemoryCardState(memory, i, OFF);
    }
    //
    // set card images randomized
    //
    var index;
    var dummy;
    for (var i=0; i<arrMemoryCards.length; i++) {
      index= Math.round(Math.random()*(arrMemoryImages.length-1));
      dummy= 0;
      // if the image at index is already in use search the next one
      while ((arrMemoryImages[index].inUse) && (dummy<arrMemoryImages.length+1)) {
        index= ++index%arrMemoryImages.length;
      }
      initMemoryCard(memory, i, arrMemoryImages[index]);
      setMemoryCardState(memory, i, HIDDEN);
    }
  }
}

/**
 * Invoked if a memory card was clicked.
 */
function cardClicked(memory, name)
{
  var index= getMemoryCardIndex(memory, name);
  if (index>=0 && 2*memory.counter<memory.arrMemoryCards.length) with (memory) {
    if (arrMemoryCards[index].state==HIDDEN) {
      if (mcOne>=0 && mcTwo>=0) {
        swapMemoryCards(memory, mcOne, mcTwo);
      }
      if (mcOne<0) {
        mcOne= index;
        setMemoryCardState(memory, index, SHOWN);
      } else if (memory.mcTwo<0 && index!=memory.mcOne) {
          mcTwo= index;
          setMemoryCardState(memory, index, SHOWN);
          // auto remove or hide...
          memory.timeOutID= setTimeout("swapMemoryCards(memory, memory.mcOne, memory.mcTwo)", memory.swapTime);
      }
    }
  }
}

/**
 * Invoked if visible memory cards should be hidden.
 */
function swapMemoryCards(memory, one, two)
{
  if (one==memory.mcOne && two==memory.mcTwo && one>=0 && two>=0) {
    if (memory.timeOutID!=null) {
      clearTimeout(memory.timeOutID);
      memory.timeOutID= null;
    }
    var state= HIDDEN;
    if (memory.arrMemoryCards[one].image.src==memory.arrMemoryCards[two].image.src) {
      state= OFF;
      memory.counter++;
    }
    setMemoryCardState(memory, one, state);
    setMemoryCardState(memory, two, state);
    memory.mcOne= -1;
    memory.mcTwo= -1;

    if (2*memory.counter>=memory.arrMemoryCards.length) {
      for (var i=0; i<memory.arrMemoryCards.length; i++) {
        setMemoryCardState(memory, i, SHOWN);
      }
    }
  }
}



