/*  ******************************
  Star Review
  Author: Jack Lukic
  Notes: First Commit Sep 04, 2012

  Simple rating module
******************************  */

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

  $.fn.starReview = function(parameters) {
    var
      settings = $.extend(true, {}, $.fn.starReview.settings, parameters),
      // hoist arguments
      moduleArguments = arguments || false
    ;
    $(this)
      .each(function() {
        var
          $module        = $(this),
          $star          = $module.find(settings.selector.star),
          
          className      = settings.className,
          namespace      = settings.namespace,
          instance       = $module.data('module'),
          module
        ;

        module = {

          settings: settings,

          initialize: function() {
            if(settings.rateable) {
              // expandable with states
              if($.fn.state !== undefined) {
                $module
                  .state()
                ;
                $star
                  .state()
                ;
              }
              $star
                .bind('mouseenter.' + namespace, module.event.mouseenter)
                .bind('mouseleave.' + namespace, module.event.mouseleave)
                .bind('click.' + namespace, module.event.click)
              ;
            }
            $module
              .addClass(className.initialize)
              .data('module', module)
            ;
          },

          setRating: function(rating) {
            var
              $activeStar = $star.eq(rating - 1)
            ;
            $module
              .removeClass(className.hover)
            ;
            $star
              .removeClass(className.hover)
            ;
            $activeStar
              .nextAll()
                .removeClass(className.active)
            ;
            $activeStar
              .addClass(className.active)
                .prevAll()
                .addClass(className.active)
            ;
            $.proxy(settings.onRate, $module)();
          },

          event: {
            mouseenter: function() {
              var
                $activeStar = $(this)
              ;
              $activeStar
                .nextAll()
                  .removeClass(className.hover)
              ;
              $module
                .addClass(className.hover)
              ;
              $activeStar
                .addClass(className.hover)
                  .prevAll()
                  .addClass(className.hover)
              ;
            },
            mouseleave: function() {
              $star
                .removeClass(className.hover)
              ;
            },
            click: function() {
              var
                $activeStar = $(this)
              ;
              module.setRating( $star.index($activeStar) + 1);
            }
          },

          // handle error logging
          error: function(errorMessage) {
            console.warn(settings.moduleName + ': ' + errorMessage);
          },

          // allows for dot notation method calls
          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;
              });
            }
            return ( $.isFunction( method ) )
              ? method.apply(context, methodArguments)
              : false
            ;
          }

        };

        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.starReview.settings = {
    
    moduleName     : 'Star Module',
    namespace      : 'star',
    
    rateable       : true,
    onRate         : function(){},
    
    className : {
      initialize : 'initialize',
      loading    : 'loading',
      active     : 'active',
      hover      : 'hover',
      down       : 'down'
    },

    selector  : {
      star : 'i'
    }

  };

})( jQuery, window , document );