// Note:  The set card game is written without using class inheritance
// which is made available by the MooTools framework.  Instead, 
// this game was a chance to explore prototypical inheritance
// in Javascript

// the only thing in the global namespace is SALOGIC    
var SALOGIC = 
{ 
  setCardGame: function(jsonObj) {
      
      var cardtable, foundsets, missingsets, cards, i;
 
      // define cardtable (div where we will put the cards)
      cardtable = $('cardtable');

      // define foundsets (div where sets found will be displayed)
      foundsets = $('foundsets');
      
      // define missingsets (span where # of sets not found is displayed)
      missingsets = $('missingsets');

      // define missingsetsplural (span where plural 's' or '' is displayed)
      //missingsetsplural = $('missingsetsplural');
      ///////////////////////////////////
      // create a prototype for a card //
      ///////////////////////////////////      
      var single_card_proto = {};
      single_card_proto.initializeCard = function(position) {
          var that;

          // create an image Element for the card
          this.img = new Element('img', {'src': this.image, 'class':'card'});
      
          // initially the card is not selected
          this.selected = false;
          
          this.position = position;

          // add Effects for Margin and Padding to the image
          this.cardMarginEffect = this.img.effect('margin', {duration: 500});
          this.cardPaddingEffect = this.img.effect('padding', {duration: 500});
     
          // method to inject the card into the DOM
          this.injectCard = function(inject_into_id) {
              this.img.inject(inject_into_id);
          };

          this.toggleCardSize = function() {
              if (this.selected) {
                  // this card has already been selected (i.e. big)
                  this.selected = false;
                  this.cardMarginEffect.start(1, 10);
                  this.cardPaddingEffect.start(8, 0);
                  this.img.setStyle('border-color', 'white');
              } else {
                  // this card is not selected (i.e. small)
                  this.selected = true;
                  this.cardMarginEffect.start(10, 1);
                  this.cardPaddingEffect.start(0, 8);
                  this.img.setStyle('border-color', 'black');
              }
          }; // single_card_proto.toggleCardSize

          that = this;  // store this in that

          // add event for when card is clicked 
          this.img.addEvent('click', function(e) {
              e = new Event(e).stop();
              // this is now 'this.img', so we use 'that'
              that.toggleCardSize();
              list = cards.selectedCards();
              if (list.length === 3) {
                  // 3 cards selected
                  if (cards.boolSet(list)) {
                      // this is a set
                      if (cards.setPreviouslyFound(list)) {
                          alert("You already found this Set.");
                      } else {
                          // newly found set
                          cards.addSet(list);
                          if (cards.found_sets.length >= cards.numberOfSets) {
                              $('setmsg').innerHTML = "Congratulations you found all of the sets!<br /><a href='./'>Click here to load new cards</a>";
                          }
                      }
                  } else {
                      // this is not a set
                      alert("This is NOT a Set.");
                  }
                  // unselect all cards after brief pause (0.6 secs)
                  setTimeout(function() {
                      for (i=0; i < cards.length; i += 1) {
                          if (cards[i].selected) {
                              cards[i].toggleCardSize();
                              cards[i].selected = false;
                          }
                      }
                  }, 600);
              } else if (list.length > 3) {
                 alert("Too many cards are selected!  You must unselect a card.");
              }
          }); // this.img.addEvent('click', 
      
      };  // single_card_proto.initializeCard
      //////////////////////////////////
      //   end prototype for a card   //
      //////////////////////////////////      

      // setup game using json object //
      cards = jsonObj.cards;  //array of cards currently in play
      cards.numberOfSets = jsonObj.numberOfSets;  // number of sets in cards in play
      cards.found_sets = [];  // initially no sets have been found

      //////////////////////////
      // add methods to cards //     
      //////////////////////////

      // return an array of indices of cards that are currently selected
      cards.selectedCards = function() {
          var positions_of_cards_selected = [];
          i = 0;
          for (i=0; i< this.length; i+=1) {
              if(this[i].selected) {
                  positions_of_cards_selected.push(i);
              }
          }
          return positions_of_cards_selected;
      }; // cards.selectedCards

      // bool - true when three parameters are equal or each unique
      cards.sameOrUniq = function(a, b, c) {
        var result;
        if ((a===b) && (b===c)){
            result = true;  // all the same
        } else if ((a != b) && (b != c) && (a != c)) {
            result = true;  // all unique
        } else {
            result = false;
        }
        return result;
      } // cards.sameOrUniq(a, b, c)

      // do these 3 cards form a set?
      cards.boolSet = function(list) {
          one = this[list[0]];
          two = this[list[1]];
          three = this[list[2]];
          if (this.sameOrUniq(one.number, two.number, three.number) &&
          this.sameOrUniq(one.color, two.color, three.color) &&
          this.sameOrUniq(one.shape, two.shape, three.shape) &&
          this.sameOrUniq(one.shading, two.shading, three.shading)) {
              result = true;
          } else {
              result = false;
          }
          return result;
      }; // cards.boolSet

      // bool function, checks if the current set was already found
      cards.setPreviouslyFound = function(set) {
          var result = false;
          for(i=0; i < this.found_sets.length; i += 1) {
              if (this.found_sets[i][0] === set[0] &&
              this.found_sets[i][1] === set[1] &&
              this.found_sets[i][2] === set[2]) {
                  result = true;
              }
          }
          return result;
      }; // cards.setPreviouslyFound
      
      // add a Set to the list of sets already found
      cards.addSet = function(set) {
          for(i=0; i < set.length; i+=1) {
              var img_small = new Element('img',
                  {'src': this[set[i]].image, 'class': 'minicard'});
              img_small.inject(foundsets);
          }
          new Element('br').inject(foundsets); 
          this.found_sets.push(set);
          this.displayNumberOfSetsToFind();
      }; // cards.addSet

      // display the number of sets that still need to be found
      cards.displayNumberOfSetsToFind = function() {
          var num_missing_sets = this.numberOfSets - this.found_sets.length;
          missingsets.innerHTML = num_missing_sets;
          //missingsetsplural.innerHTML = (num_missing_sets === 1 ? '' : 's');
      }; // cards.displayNumberOfSetsToFind

      ///////////////////////////
      // end methods for cards //     
      ///////////////////////////


      // go through each card individually
      for (i=0; i < cards.length; i+=1) {
          // add all properties of single_card_proto to card at position i in array cards
          $extend(cards[i], single_card_proto);

          // initialize card at position i, 
          cards[i].initializeCard(i);

          // each row of cards has 4 cards in it, insert BR into DOM as necessary
          if (i%4 === 0) {
            new Element('br').inject(cardtable);
          }

          // insert the element for the card into the DOM
          cards[i].injectCard(cardtable);
      } // for i

      cards.displayNumberOfSetsToFind();

  }, // setCardGame()

  init: function() {
     var default_json_obj = 
      {"cards":
         [{ "number":1, "color":"purple", "shape":"squiggle", "shading":"outline", "image":"1psh.gif" }, 
          { "number":3, "color":"red", "shape":"diamond", "shading":"hatched", "image":"3rdl.gif"}, 
          { "number":3, "color":"red", "shape":"squiggle", "shading":"hatched", "image":"3rsl.gif"},
          { "number":3, "color":"red", "shape":"diamond", "shading":"outline", "image":"3rdh.gif"}, 
          { "number":2, "color":"purple", "shape":"squiggle", "shading":"hatched", "image":"2psl.gif"}, 
          { "number":3, "color":"green", "shape":"oval", "shading":"outline", "image":"3goh.gif"}, 
          { "number":3, "color":"red", "shape":"oval", "shading":"solid", "image":"3ros.gif"}, 
          { "number":2, "color":"green", "shape":"squiggle", "shading":"hatched", "image":"2gsl.gif"}, 
          { "number":2, "color":"green", "shape":"squiggle", "shading":"solid", "image":"2gss.gif"}, 
          { "number":1, "color":"red", "shape":"diamond", "shading":"solid", "image":"1rds.gif"}, 
          { "number":1, "color":"red", "shape":"diamond", "shading":"outline", "image":"1rdh.gif"}, 
          { "number":2, "color":"red", "shape":"diamond", "shading":"outline", "image":"2rdh.gif"} 
         ], "numberOfSets":6};

      new Json.Remote('set_12cards.php', {
          onComplete:  function(result) {
              SALOGIC.setCardGame(result);
          },
          onFailure: function() {
              SALOGIC.setCardGame(default_json_obj);
          }
      }).send(); // JSON request
  } // init 
} // end SALOGIC

window.addEvent('domready', SALOGIC.init.bind(SALOGIC));


