// jquery.rewire.js
// 0.5
// Stephen Band
//
// http://webdev.stephband.info/

(function(jQuery) {

var plugin = 'rewire',
    debug = true;

// VAR
var options = {},
    events = {
        display:        'display',                                          // Fire at wrapper to make it display something
        displaying:     'displaying',                                       // Fires when a display event is heard
        displayed:      'displayed',                                        // Fires when DoDo displays content
        load:           'load',                                             // Fires when a load is needed
        loading:        'loading',                                          // Fires when DoDo starts an AJAJ request
        loaded:         'loaded'                                            // Fires when DoDo has loaded request
    },
    templates = {};

// FUNCTIONS

function Template(fn, options, template) {
    fn.elem = (template && template.elem);
    fn.options = (template) ? jQuery.extend(template.options, options) : jQuery.extend({}, jQuery.fn[plugin].options, options) ;
    return fn;
}

function namespace(obj, name) {
    var out = {};
    for (var x in obj) {
        out[x] = obj[x] + '.' + name;
    }
    return out;
}

// JQUERY
jQuery.fn.extend({
    // Similar to bind, but bindTo takes an object to bind to (or a template mode or selector string) and
    // passes the current (chained) object as 'this' to the handler function
    bindTo: function( obj, type, data, fn ) {
        var self = this,
            elem = (typeof(obj) === 'string') ? (templates[obj] && templates[obj].elem) || jQuery(obj) : obj ,
            action = fn || data,
            fn = function(e){ return action.call(self, e); };
        
        elem.each(function(){
            jQuery.event.add( this, type, fn, fn && data );
        });
        
        return this;
    }
});

// PLUG
jQuery.fn[plugin] = function(mode, options) {

    // Report missing template
    if (debug && !templates[mode]) {
        console.log(plugin.toUpperCase() + ': Template \'' + mode + '\' not defined. Returning \'this\' to jQuery chain.');
        return this;
    }
    
    var template = templates[mode],
        o = jQuery.extend({}, template.options, options),
        e = namespace(events, mode);
    
    // Add this to the collection
    template.elem = (template.elem)?
        template.elem.add(this):
        this;
    
    // Expose elem as jQuery.plugin.mode
    jQuery[plugin][mode] = template.elem;
    
    // Call template on this
    return template.call(this, o, e) || this;
};

// EXPOSE
jQuery.fn[plugin].options = options;

// HELPERS
jQuery[plugin] = function(mode, options, fn) {
    templates[mode] = new Template(fn || options, fn && options, templates[mode]);
}
jQuery[plugin].events = function(obj) {
    return obj ? jQuery.extend(events, obj) : events ;
}
jQuery[plugin].actions = function(obj) {
    return obj ? jQuery.extend(actions, obj) : actions ;
}

})(jQuery);