/*  ******************************
  Accordion
  Author: Jack Lukic
  Notes: First Commit July 19, 2012

  Simple accordion design
******************************  */

;(function ($, window, document, undefined) {

  $.fn.accordion = function(parameters) {
    var
      settings = $.extend(true, {}, $.fn.accordion.settings, parameters),
      // hoist arguments
      moduleArguments = arguments || false
    ;
    $(this)
      .each(function() {

        var
          $module   = $(this),
          $title    = $module.find(settings.selector.title),
          $icon     = $module.find(settings.selector.icon),
          $content  = $module.find(settings.selector.content),
          
          instance  = $module.data('module'),
          className = settings.className,
          module
        ;

        module = {

          initialize: function() {
            // initializing
            $title
              .on('click', module.change)
            ;
            $module
              .data('module', module)
            ;
          },
            
          change: function() {
            var
              $activeTitle   = $(this),
              $activeContent = $activeTitle.next($content),
              contentIsOpen  = $activeTitle.hasClass(className.active)
            ;
            if(contentIsOpen) {
              if(settings.collapsible) {
                $.proxy(module.close, $activeTitle)();
              }
            }
            else {
              $.proxy(module.open, $activeTitle)();
            }
          },

          open: function() {
            var
              $activeTitle    = $(this),
              $activeContent  = $activeTitle.next($content),
              $currentTitle   = $title.filter('.' + className.active),
              $currentContent = $currentTitle.next($title)
            ;
            if(settings.exclusive && $currentTitle.size() > 0) {

              $currentTitle
                .removeClass('active')
              ;
              $currentContent
                .stop()
                .slideUp(settings.speed , settings.easing, function() {
                  $(this)
                    .removeClass('active')
                    .removeAttr('style')
                  ;
                })
              ;
            }
            $activeTitle
              .addClass(className.active)
            ;
            $activeContent
              .hide()
              .addClass(className.active)
              .stop()
              .slideDown(settings.speed, settings.easing, function() {
                $(this)
                  .removeAttr('style')
                ;
              })
            ;
          },

          close: function() {
            var
              $activeTitle   = $(this),
              $activeContent = $activeTitle.next($content)
            ;
            $activeTitle
              .removeClass(className.active)
            ;
            $activeContent
              .removeClass(className.active)
              .show()
              .stop()
              .slideUp(settings.speed, settings.easing, function(){
                $(this)
                  .removeAttr('style')
                ;
              })
            ;
          },

          debug: function(message) {
            if(settings.debug) {
              console.info(settings.moduleName + ': ' + message);
            }
          },
          error: function(errorMessage) {
            console.warn(settings.moduleName + ': ' + errorMessage);
          },
          invoke: function(methodName, context, methodArguments) {
            var
              method
            ;
            methodArguments = methodArguments || Array.prototype.slice.call( arguments, 2 );
            if(typeof methodName == 'string' && instance !== undefined) {
              methodName = methodName.split('.');
              $.each(methodName, function(index, name) {
                if( $.isPlainObject( instance[name] ) ) {
                  instance = instance[name];
                  return true;
                }
                else if( $.isFunction( instance[name] ) ) {
                  method = instance[name];
                  return true;
                }
                module.error(settings.errors.method);
                return false;
              });
            }
            if ( $.isFunction( method ) ) {
              return method.apply(context, methodArguments);
            }
            // return retrieved variable or chain
            return method;
          }

        };

        // calling a method
        if(instance !== undefined && moduleArguments) {
          // simpler than invoke realizing to invoke itself (and losing scope due prototype.call()
          if(moduleArguments[0] == 'invoke') {
            moduleArguments = Array.prototype.slice.call( moduleArguments, 1 );
          }
          return module.invoke(moduleArguments[0], this, Array.prototype.slice.call( moduleArguments, 1 ) );
        }
        // initializing
        module.initialize();

      })
    ;
    return this;
  };

  $.fn.accordion.settings = {
    moduleName  : 'Accordion',
    debug       : false,
    
    exclusive   : true,
    collapsible : true,

    errors: {
      method    : 'The method you called is not defined'
    },

    className   : {
      active    : 'active',
      hover     : 'hover'
    },

    selector    : {
      title     : '.title',
      icon      : '.icon',
      content   : '.content'
    },

    speed       : 500,
    easing      : 'easeInOutQuint'

  };

})( jQuery, window , document );