/**
 * Constructor for boxes of cycling content.
 * 
 * Cycled elements are children of param ID with class of "cycle-item".
 * Forward / Backward links are children of param ID with classes of ".cycle-forward" 
 * ".cycle-back"
 *
 * For display position (1 of 10) use id "cycle-current" & "cycle-total"
 *
 * Example *Note Must Be Called On Load - don't use var if you need global scope:
 *      	  
 * testimonialBox = new CycleBox({
 *    id: "#home-testimonial",
 *    delay: 2000,
 *    random: false,
 *    isAutoCycle: false,
 *    hasButtons: true,
 *    displayPosition: true
 * });
 * 
 *
 * @param   int      id                - id of container
 * @param   int      delay             - delay in milliseconds for refresh
 * @param   boolean  random            - determines if items are shuffled on load
 * @param   boolean  isAutoCycle       - auto cycle elements
 * @param   boolean  hasButtons        - has forward/back buttons
 * @param   boolean  displayPosition   - show "2 of 10"
 * @param   boolean  wipeAnim          - use wipe animation instead of default (wipe requires jquery ui)
 * @param   boolean  transition        - blends between two elements, requires abs positioning
 * @param   boolean  manualTrigger     - object is created but nothing is shown 
 *                                       until triggered
 *
 * Copyright (C) 2009 by Benjamin Sternthal <ben@sternthal.org>
 */
 
function CycleBox(options) {
   var instance = this;
   
   //user defined options
   instance.container = $(options['id']);
   instance.delay = options['delay'];
   instance.isRandom = options['random'];
   instance.isAutoCycle = options['isAutoCycle'];
   instance.hasButtons = options['hasButtons'];
   instance.displayPosition = options['displayPosition'];
   instance.wipeAnim = options['wipeAnim'];
   instance.manualTrigger = options['manualTrigger'];   
   instance.transition = options['transition'];   
   
   
   //pre sets
   instance.counter = 0;
   instance.currentItem = 0;
   instance.timer;
   instance.firstRun = true;    
   instance.items = instance.container.find('.cycle-item');
   instance.buttonForward = instance.container.find('.cycle-forward');
   instance.buttonBack = instance.container.find('.cycle-back');
   
   /* Randomize Array Order */
   this.randomizeOrder = function(items) {
      for(var j, x, i = items.length; i; 
          j = parseInt(Math.random() * i), x = items[--i], items[i] = items[j], items[j] = x);   
          
      return items;
   };
   
   /* Bind Forward / Back Buttons */
   this.bindManualButtons = function () {
      instance.buttonForward.bind('click', function() {
         instance.manualCycle("forward");
         
         return false;
      });
      
      instance.buttonBack.bind('click', function() {
         instance.manualCycle("back");
         
         return false;
      });   
   };
   
   /* Manual Stop Cycling */
   this.stopCycle = function() {
      instance.counter = 0;
      instance.currentItem = 0;  
      instance.firstRun = true;    
       
      $(instance.items).fadeOut("slow");   
      clearInterval(instance.timer);
      
      return true;
   };
   
   /* Manual Start Cycling With Wipe */
   this.startWipeCycle = function() {
      $(instance.items[0]).animate({
         "width" : "show" ,
         "opacity": "toggle"
      }, { duration: 1000 });   
      instance.timer = setInterval(function(){instance.autoCycle()}, instance.delay);
   };  
   
   /* Manual Start Cycle Default */   
   this.startCycle = function() {
      $(instance.items[0]).fadeIn("slow"); ; 
      instance.timer = setInterval(function(){instance.autoCycle()}, instance.delay);
   };    
     
   /* Manual Cycle */   
   this.manualCycle = function(direction) {
      //reset counter
      instance.counter = instance.currentItem;
                    
      if(direction == "forward") {
         if((instance.counter + 1) >= instance.items.length) {
            instance.counter = 0;
            instance.cycleItem();
         } else {   
            instance.counter++;
            instance.cycleItem();
         }
      } else  {
         if((instance.counter - 1) < 0) {
            instance.counter = instance.items.length;
         }
         instance.counter--;               
         instance.cycleItem();
      }
      
      return true;
   }
   
   /* Auto Cycle - Called Via Set Interval*/   
   this.autoCycle = function() { 
      if(instance.firstRun) {
         instance.counter++;
      }
 
      instance.cycleItem();
      
      if(instance.counter < (instance.items.length-1)) {
         instance.counter++;
      } else {
         instance.counter = 0;
      }
      
      instance.firstRun = false;
      return true;      
   };
   
   /* Transition Animation  */
   this.cycleItem = function () {
      if(!instance.wipeAnim) {
      
         if(instance.transition) {
            $(instance.items).fadeOut(1400);    
         } else {         
            $(instance.items).hide();    
         }   
         
         $(instance.items[instance.counter]).fadeIn(1500);         
         
      } else {
         $(instance.items).fadeOut("slow");
         $(instance.items[0]).animate({
            "width" : "show" ,
            "opacity": "toggle"
         }, { duration: 1000 }); 
      }
      
      instance.currentItem = instance.counter;
      
      if(instance.displayPosition) {
         instance.container.find('#cycle-current').html(instance.currentItem+1);  
      }            
     
      return true;
   }

   
   /* Init */
   this.init = function(){

      if(instance.displayPosition) {
         instance.container.find('#cycle-current').html("1");  
         instance.container.find('#cycle-total').html(instance.items.length);       
      }
      
      if(instance.isRandom) {
         instance.randomizeOrder(instance.items);
      }
       
      if(instance.hasButtons) {
         instance.bindManualButtons();
      }
       
      if (!instance.manualTrigger) { 
         $(instance.items[0]).show(); 
         if(instance.isAutoCycle) { 
            instance.timer = setInterval(function(){instance.autoCycle()}, instance.delay);  
         }
      }
   }
   
   this.init();   
}
