// Wax  version: 0.0.1
// Your standard Mustache Wax... Holds your mustaches in place. 
// call with options and a set of templates like this:
// wax = new Wax({path: "/path/to/template/files"}, [{key: 'roster', file: 'roster.mustache'},{key: 'question', file: 'question.mustache'}]);
// wax.load(function(){tmpl = wax.template('roster');});
Wax = function(options, tmpls){
  var default_opts = {
    path: "/",
    callback: this.allLoaded,
    errorCallback: function(tmpl){
      if(console&&console.log){
        console.log("ERROR LOADING TEMPLATE", tmpl);
      };
    }
  };
  this.templates = [];
  this.partials = {};
  this.opts = jQuery.extend(true, {}, default_opts, options);
  if(undefined!==tmpls){
    this.add(tmpls);
  };
};

Wax.prototype = {
  version: "0.0.1",
  loadFromPage: function(){
    var self = this;
    jQuery('script[type=text/mustache]').each(function(i, tmpl_string){
       var $this = jQuery(this);
       self.add( { "key" : $this.attr('key'), template: $this.html() } );
    });
    this.load();
  },
  //can call with a callback context to apply to the callback function, default is the wax instance. 
  load: function(callback, context){
    this.callback = (callback!==undefined) ? callback : this.opts.callback;
    this.callbackContext = (context===undefined) ? this : context;
    this.returned_count = 0;
    this.expected_returned_count = this.templates.length;
    var self = this;
    jQuery.each(this.templates, function(k,tmpl){
      if(tmpl.template){
        //I already have a template, call returned!
        self.returned(tmpl);
      }
      else{
        var url = self.opts["path"]+tmpl.file;
        jQuery.ajax({url: url,
            success: function(tmpl_str){ 
              // My template just arrived! push it into the template prop and call returned! 
              tmpl.template = tmpl_str;
              self.returned(tmpl); 
            },
            dataType: "text",
            context: self,
            error: function(){ 
              //sumpin broke, call returned, but with trigger the error callback
              self.returned(tmpl, true); 
            }
        });        
      };
    });
  },
  returned: function(tmpl, error){
    if(error) this.opts.errorCallback.apply(this, $.makeArray(tmpl));
    this.partials[tmpl.key] = tmpl.template;
    this.returned_count++;
    // console.log('returned...', this.returned_count);
    if(this.expected_returned_count === this.returned_count){
      this.callback.apply(this.callbackContext, this.templates);
    };
  },
  allLoaded: function(){
    //this is useless, but will remind the user to implement a callback
    console.log("All Returned! You should really think about defining a callback...");
  },

  add: function(tmpl){
    var self = this;
    //make this an array because can pass in singles or arrays full of templates!
    // makeArray doesn't do anything if it is already an array
    tmpl = jQuery.makeArray(tmpl);
    jQuery(tmpl).each(function(i,v){
      var templateString = (this.template===undefined) ? false : this.template;
      self.templates.push( { key: this.key.toLowerCase(), file: this.file, template: templateString } );
    });
  },
  
  template: function(tmpl_key){
    var tmpl = jQuery(this.templates).map(function(k,v){
      if(v.key==tmpl_key) return v.template;
    });
    return (tmpl.length===1)? tmpl[0] : tmpl;
  },
  
  render: function(tmpl_key, data){
    var tmpl = this.template(tmpl_key.toLowerCase());
    return jQuery.mustache(tmpl, data, this.partials);
  },
  
  is_object: function(a) {
    return a && typeof a == "object";
  },
  is_array: function(a) {
    return Object.prototype.toString.call(a) === '[object Array]';
  }

};


