/**
 *
 * Perform jQuery library
 * Developed by Perform
 *
 * Built on top of the jQuery library
 * http://jquery.com
 *
 * Description: Creates a news reader from an unordered list
 * Varsion: 1.0 - gearbox version
 * Version: 1.1 - added support for more newsreaders on same page
 *              - code cleanup
 *              - error messages
 *              - encapsulation of newsreader methods inside newsreader
 *              - boundary handling when user tries to get to position which is out of bounds, the position will be auto recalculated to correct one
**/
//global variable which stores last used element, so we can simulate the original behavior
(function($){
newsreaderElement = null;    
  
/**
 * example: $('object').newsreader(options);
 *          $('object').newsreader('start');
 *          $('object').newsreader('pause');
 *          $('object').newsreader('getPosition');
 *          $('object').newsreader('changeItem',from,to);
 *          $('object').newsreader('changeItem',to);
 */
  $.fn.newsreader = function(method) {    
  
    //default configuration of properties
    var settings = {
      speed: 5,                  // Default transition speed (5 seconds)
      hold: 3,                   // Default holding time (3 seconds)
      start: 0,                  // Starting index on the UL
      nav: null,                 // Newsreaders Navigation Id
      navClickFunc: null,        // Navigation click function call
      navOnHoverInFunc: null,    // Navigation hover over item function call
      navOnHoverOutFunc: null,   // Navigation hover out item function call
      //new properties
      onItemChangeFunc: null,      // After item is changed, this function will be called
      selectedClass: 'selected'  // Class assigned to selected item
    }

    function getNewsreaderData(element, noErrors) {
      var data = $(element).data('newsreader');
      if (typeof data === 'object'){
        return data;
      }else{
        if (typeof noErrors === 'undefined' || !noErrors){
          $.error( 'Newsreader has to be initialised before any method can be called' );
        }
        return false;
      }
    }
    
    function storeNewsreaderData(element,data) {
      $(element).data('newsreader',data);
      return true;
    }
        
        
    var publicMethods = {
      /* constructor of class*/
      init: function(options){
        return this.each(function(){
          var $this = $(this),
              data = getNewsreaderData(this,1),
              count = ('li',$this).children;
          newsreaderElement = $this;
          /*when reader was intiated for this element, destruct it*/
          if (data!==false){
            data.element.newsreader('destruct');
          }
          
          data = {
            element: $this,
            // Combine the default and user configurations together   
            settings: $.extend(settings, options || {}),
            // stores interval variable when newsreader is launched
            interval: false,
            // stores timeout variable when newsreader has to hold momentarily (when the user manually change the item)
            hold_timeout: false
          }
            
          if (count==0){
            $.error('Newsreader must not be empty');
          }
              
          if (data.settings.start>count-1){
            //$.error('Start truncated from "'+data.settings.start+'" to '+(count-1))
            data.settings.start = count -1;
          } else if (data.settings.start<0){
            data.settings.start = 0;
          }
          
          data.position = data.settings.start;
          
          // Hide all the li items apart the starting position
          $this.children().each(function(index){
            if(index!=data.settings.start) {
              $(this).hide();
            }
          });

          // Check if there is any navigation
          if(data.settings.nav!=null) {
            $(data.settings.nav).children().each(function(index){
              // Add the selected class to the first item
              if(index==data.settings.start) {
                $(this).addClass(data.settings.selectedClass);
              }
        
              // If the newsreader passes a click function
              if(data.settings.navClickFunc!=null) {    
                $(this).bind('click.newsreader',function(){
                  if (typeof(window[data.settings.navClickFunc]) === 'function') {
                    window[data.settings.navClickFunc](index);
                    return false;
                  }            
                });
              }
        
              // If the newsreader passes a onHoverIn function
              if(data.settings.navOnHoverInFunc!=null) {    
                $(this).bind('mouseenter.newsreader',function(){
                  if (typeof(window[data.settings.navOnHoverInFunc]) === 'function') {
                    window[data.settings.navOnHoverInFunc](index);
                  }            
                });
              }

              // If the newsreader passes a onHoverOut function
              if(data.settings.navOnHoverOutFunc!=null) {    
                $(this).bind("mouseleave",function(){
                  if (typeof(window[data.settings.navOnHoverOutFunc]) === "function") {
                    window[data.settings.navOnHoverOutFunc](index);
                  }
                });
              }
            });
          }
         
          /* store necessary data so it is availiable for other methods */
          storeNewsreaderData(this,data);
          
          // Show the newsreader - Should be hidden in the CSS to render a cleaner load    
          $this.show();
          $this.newsreader('start');
        });
      },
      /* start newsreader */
      start: function(){
        var data = getNewsreaderData(this);
        if (data){
          if (data.interval===false){
            data.interval = setInterval(function(){
              data.element.newsreader('changeItem',data.position+1);
            },data.settings.speed*1000);
            storeNewsreaderData(this,data);
          } else {
            $.error('Newsreader already started');
          }
        }
      },
      /* pause newsreader */
      pause: function(on_hold){
        var data = getNewsreaderData(this);
        
        if (data){          
          if( data.interval === false && ( typeof on_hold !== 'undefined' && on_hold !== true ) ) {
              $.error('Newsreader has to be started before it can be paused');
              
              return false;
          }
          
          if( data.interval !== false ) {
              clearInterval(data.interval)
              data.interval = false;
            
              storeNewsreaderData(this,data);                       
          } 
          
          if( on_hold === true ) {         
              clearTimeout(data.hold_timeout);
              data.hold_timeout = setTimeout(function() { 
                  $.newsreader.start();
              }, data.settings.hold * 1000);
            
              storeNewsreaderData(this,data);                     
          }
        }
        
        return false;
      },
      
      /* returns a current position in newsreader*/
      getPosition: function(){
        var data = getNewsreaderData(this);
        if (data){
          return data.position;
        }
        return false;
      },
      /* change from one slot to another */
      changeItem: function(from,to){
        var data = getNewsreaderData(this);
        if (data){
          /*check input*/
          if (typeof to === 'undefined'){
            to = from;
            from = data.element.newsreader('getPosition');
          }
          
          var children = data.element.children();
          var count = children.length;
          
          /*Check if the to is not out of bounds and if so, correct them*/
          while (to<0){
            //$.error('Newsreader is scrolling thourght left boundary, autocorrecting from "'+to+'" to "'+(to+count)+'"');
            to = to + count;
          }
          while (to>=count){//scrolling through right boundary
            //$.error('Newsreader is scrolling thourght right boundary, autocorrecting from "'+to+'" to "'+(to-count)+'"');            
            to = to - count;
          }
          
          children.hide().removeClass(data.settings.selectedClass); // Hide All li elements and remove to selected class
          if (data.settings.nav){
            $(data.settings.nav).children().removeClass(data.settings.selectedClass);// Remove All Nav Selected Classes      
          }
          children.eq(to).show().addClass(data.settings.selectedClass); // Show the next item in it's order
          if (data.settings.nav){
            $(data.settings.nav).children().eq(to).addClass(data.settings.selectedClass); // Add the selected class to the nav
          }
          
          data.position = to;
          storeNewsreaderData(this,data);
         
          // If the newsreader passes a onItemChangeFunc function
          if(data.settings.onItemChangeFunc!=null) {    

            if (typeof(window[data.settings.onItemChangeFunc]) === "function") {
              window[data.settings.onItemChangeFunc](from,to);
            }
          }
        }
      },
      /* destructor of class */
      destruct: function(){
        return this.each(function(){
          var $this = $(this),
          data = getNewsreaderData(this);
          if (data.interval!==false){
            $this.newsreader('pause');
          }
          // Namespacing FTW
           $(window).unbind('.newsreader');
           data.newsreader.remove();
           $this.removeData('newsreader');
         });
      }
    }/*END publicMethods*/
                         
    // Method calling logic
    if (publicMethods[method]){
      return publicMethods[method].apply(this, Array.prototype.slice.call( arguments, 1));
    } else if (typeof method === 'object' || ! method) {
      return publicMethods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.newsreader' );
    }
  };

  /**
   * Old behavior simulation
   * DEPRECATED
   */
   $.newsreader = function(){}

   $.newsreader.getPosition = function(){
     return newsreaderElement.newsreader('getPosition');
   }

   $.newsreader.start = function(){
     return newsreaderElement.newsreader('start');
   }

   $.newsreader.pause = function(on_hold){
     return newsreaderElement.newsreader('pause', on_hold);
   }

   $.newsreader.changeItem = function(from,to){
     return newsreaderElement.newsreader('changeItem',from,to);
   }
})(jQuery);

