(function($){
    /**
     * 
     * @class Adapter
     * @param {String} method="init" nome do método que sera chamado
     * @description jQuery Plugin para simplificar chamada de plugins
     */
    var Adapter = function( method ) {
        if ( methods[method] ) {
            return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
        } else{
            return methods.init.apply( this, arguments );
        }    
    }    
    /**
     *
     * @description Repositório de adapters
     */
    var adapters =  {}
    
    /**
     *
     * @description Repositório de métodos
     */
    var methods = {
        /**
         * 
         * @description chamada um método ou um adapter
         * @memberOf Adapter
         * @param {String} adapterName Nome do adapter
         * @param {String} adapterMethodName Nome do método do adapter, o default é init
         * @example 
         * $( "div" ).adapter( "init", "cycle", "pause", "slow", 5000 ); //methodName, adapterName, adapterMethodName, param1, param2, paramN...
         * $( "div" ).adapter( "cycle", "pause", "slow", 5000 ); //adapterName, adapterMethodName, param1, param2, paramN... ( implicit methodName = init )
         * $( "div" ).adapter( "cycle", "pause" ); //adapterName, adapterMethodName
         * $( "div" ).adapter( "cycle", "slow", 5000); //adapterName, param1, param2, paramN... ( implicit adapterMethodName = init )
         * $( "div" ).adapter( "cycle"); //adapterName 
         */
        init: function(adapterName, adapterMethodName){
            if( adapters[adapterName] && typeof adapters[adapterName] === "object" && typeof adapters[adapterName][adapterMethodName] === "function" ){
                return adapters[adapterName][adapterMethodName].apply( methods.defaultJQueryElement(adapterName, this), Array.prototype.slice.call( arguments, 2 ) );                
            }
            else if( adapters[adapterName] && typeof adapters[adapterName] === "object"  && typeof adapters[adapterName].init === "function"){
                return adapters[adapterName].init.apply( methods.defaultJQueryElement(adapterName, this), Array.prototype.slice.call( arguments, 1 ) );                
            }
            else{
                throw adapterName + " adapter does not exist";
            }
        },
        /**
         *
         * @description Adiciona um adapter
         * @memberOf Adapter
         * @param {String} adapterName Nome do adapter
         * @param {Object} adapter Adapter
         * @example $.adapter( "add", "cycle", { init: function{ alert("teste"); }} )
         */
        add: function( adapterName, adapter ){
            if( adapter && typeof adapter == "object" && typeof adapter.init == "function" ){
                adapters[adapterName] = adapter;
                $(window).trigger( $.Event( "add.adapter", {"adapterName": adapterName, "adapter": adapter} ) );
            }
            return this
        },
        /**
         * 
         * @description Remove um adapter
         * @memberOf Adapter
         * @param {String} adapterName Nome do adapter
         * @example $.adapter( "remove", "cycle" ) )
         */
        remove: function( adapterName ){
            if( adapters[adapterName] ){
                var adapter = adapters[adapterName];
                adapters[adapterName] = null;
                $(window).trigger( $.Event( "remove.adapter", {"adapterName": adapterName, "adapter": adapter} ) );
            }
            return this
        },
        /**
         * 
         * @description Gera um objeto literal de configuração considerando a configuração padrão, options e inline nesta ordem de sobreposição.
         * @memberOf Adapter
         * @param {String} adapterName Nome do adapter
         * @param {Object} options Objeto literal de configuração
         * @return {jQuery Object} Objeto literal de configuração
         * @example var settings = $(div).adapter( "options", "cycle", { timout: 5000 } ) )
         */
        options: function( adapterName, options ){
            return this.each(function(){
                var $this = $(this);
                var inlineConfig = ( new Function( "return " + $this.attr('data-adapter-' + adapterName + '-config')+";" ) )();
                var defaults = $this.adapter("defaults", adapterName);
                var config = $this.data( "data-adapter-" + adapterName + "-config")?$this.data( "data-adapter-" + adapterName + "-config"):{};
                $this.data( "data-adapter-" + adapterName + "-config", $.extend( true, config, defaults, options, inlineConfig ) );
            })
        },
        /**
         *
         * @description Set/Get a configuração default de um plugin
         * @memberOf Adapter
         * @param {String} adapterName Nome do adapter
         * @param {Function} settings Função que retorna a configuração
         * @example 
         * var defaults = $.adapter( "defaults", "cycle" );
         * $.adapter( "defaults", "cycle", function(){ return { next: $(this).find(".next") } } ) );
         */
        defaults: function( adapterName, settings ){
            if( typeof settings === 'function' ){
                adapters[adapterName].defaults = settings;
                return this;
            }
            else{
                return adapters[adapterName].defaults.call(this);
            }
        },
        
        /**
         *
         * @description Get/Set default element
         * @memberOf Adapter
         * @param {String} adapterName Nome do adapter
         * @param {jQuery|Function} jQueryElement
         */
        defaultJQueryElement: function( adapterName, jQueryElement ){
            if( jQueryElement == $ && adapters[adapterName] && typeof adapters[adapterName].defaultJQueryElement === 'function' ){
                return adapters[adapterName].defaultJQueryElement();
            }
            else if( jQueryElement != $ && typeof jQueryElement === 'function' ){
                adapters[adapterName].defaultJQueryElement = jQueryElement;
            }
            else{
                return jQueryElement;
            }
        }
    }
    $.fn.adapter = $.adapter = Adapter;    
})(jQuery)
