(function($) {
    
    $.fn.template = function(url, data) {
        
        this.each(function() {
            var obj = $(this);
            var localData = data || obj;
            
            $.template.run(url, localData, function(results) {
                obj.html(results);
            });
        });
        
        return this;
    }
    
    $.template = {
        cache: {},
        status: {},
        waiting: {},
        
        load: function(url, callback) {

            // this template has never been requested
            if (!$.template.status[url])
            {
                $.template.status[url] = "sending";
                $.template.waiting[url] = [callback];
                
                $.get(url, {}, function(data) {
                    
                    $.template.status[url] = "cached";
                    $.template.cache[url] = data;
                    
                    for (var i in $.template.waiting[url])
                    {
                        $.template.waiting[url][i](data);
                    }
                });
            }
            
            // it is currently being requested
            else if ($.template.status[url] == "sending")
            {
                $.template.waiting[url].push(callback);
            }
            
            // it is cached
            else
            {
                callback($.template.cache[url]);
            }
        },
        
        // returns a new string from some data
        parse: function(content, data)
        {
            // var pattern = ;
            content = content.replace(/\{(.+?)\}/gi, function (m, key, value){
                var expression = key;
                var result;
                
                // try to eval it directly
                try {
                    result = eval(expression);
                }
                
                catch (err) {

                    // try it with data in the current scope
                    try {
                        with(data)
                        {
                            result = eval(expression);
                        }
                    }
                    
                    // print the error
                    catch (err) 
                    {
                        result = "(" + err + ")";
                    }
                }
                
                return result;
            });

            return content;
        },
        
        run: function(url, data, callback)
        {
            $.template.load(url, function(content) {
                var result = $.template.parse(content, data);
                callback(result);
            });
        }
        
        
        
      
    }
    
})(jQuery)