(function ( $ ){
  
  var templates = [];
  
  var methods = {
    loadTemplates: function( pathToTemplate, callback ) {  
      $.ajax({
        url:pathToTemplate,
        success:function(data, textStatus, jqXHR) {
          var marker = 0;
          while(marker < data.length) {
            //find first HTML comment
            var keystart = data.search(/<!-- [_a-z0-9]+ -->/) + 5;
            var keyend = data.search(/ -->/);
            var key = data.substr(keystart, (keyend-keystart));
            var datastart = keyend + 4;
            var dataend = data.search(/<!--end-->/);
            templates[key] = data.substr(datastart, (dataend-datastart));
            data = data.substr(dataend + 10);
          }
          callback();
        },
        error:function(xhr, status, err) {
          $.error(status + ":" + err);
        },
        dataType:"text"
      });  
    },
    
    getTemplate: function( templateName ) {
      return templates[templateName];
    },
    
    append: function( templateName ) {
      return this.append(templates[templateName]);
    },
    
    prepareAndAppend: function( templateName, values ) {
      var elem = $(templates[templateName]);
      for(i in values) {
        $("."+i, elem).html(values[i]);
      }
      return this.append(elem);
    },
    
    prepare: function( templateName, values ) {
      var elem = $(templates[templateName]);
      for(i in values) {
        $("."+i, elem).html(values[i]);
      }
      return elem;
    },
    
    replace: function( templateName ) {
      return this.html(templates[templateName]);
    }
    
  };
  
  $.tpl = methods;
  
  $.fn.tpl = function(method) {
    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tpl' );
    }  
  }
  
})( jQuery );

