/*
jquery.nc.scrollFocus
usage :  ($'carousel').scrollFocus()
Point plug-in to a series of li tags w. image content.
Turn the series of LI tags into a scrollable animation
where a single li element and its content expands to be in a "focused" state,
the main image that is being displayed.
*
*var vars = $.extend($('<div>')[0], {
  foo: 1,
  bar: 2,

  customAnimate: true,
  updated: true
});
*/

(function( $ ){

   var methods = {
      init : function( options ) {

         return this.each(function(){

            var $this = $(this);

            // configuration values
            $this.data('elemTop', 20);
            // get the first image in the list, determine its width and set the elemWidth for all the elements
            //$this.data('elemWidth', $this.find('img:eq(0)').width() );
            $this.data('elemWidth', 220 );
            $this.data('focusedElemIndex', 2);
            $this.data('focusedElemWidth', $this.find('img:eq(0)').width() );
            $this.data('focusedElemTop', 0);
            $this.data('focusedElemShiftLeft', 20);
            $this.data('scrollDuration', 1000);
            // END : configuration values

            $this.data('elements', $this.find("li"));
            $this.data('LEFT', 0);
            $this.data('RIGHT', 1);
            $this.data('actions',{
               focus:true,
               unFocus:true,
               scroll:true
            });
            // click : move right
            $("#right").click(function(){
               methods.scrollFocus.call($this,  $this.data('RIGHT'));
            });
            // click : move left
            $("#left").click(function(){
               methods.scrollFocus.call($this,  $this.data('LEFT'));
            });
            // keydown action
            $(document.documentElement).keydown(function (e) {
               if(e.which == 39){
                  methods.scrollFocus.call($this,  $this.data('RIGHT'));
               }
               if(e.which == 37){
                  methods.scrollFocus.call($this,  $this.data('LEFT'));
               }
            });

            // set position of elements with abs positioning
            var leftPos = 0;
            // gotHeightOnReady : refers to none Chrome browswers that got the image height before window.onload
            var gotHeightOnReady = true;
            $.each($this.data('elements'), function(i, v){
               $(v).css("position", "absolute");
               $(v).css("left", leftPos); // TODO i * width
               $(v).css("top", $this.data('elemTop') );
               //$(v).data('origImgWidth', $(v).find('img').width()  );
               $(v).data('origImgWidth', $this.data('elemWidth') );
               $(v).width( $this.data('elemWidth') );
                              $(v).find('img').width( $this.data('elemWidth') );

               /* X-browser : Chrome does not get an image height until window.load is called */
               if($(v).find('img').height()  === 0){
                  loadSet($(v));
                  gotHeightOnReady = false;
               }
               else{
                  $(v).data('origImgHeight',  $(v).find('img').height() );
               }
               leftPos += $this.data('elemWidth');
            })
            if(gotHeightOnReady) {
               methods.delayStart();
            }

            // need to use window.load to ensure that chrome (maybe other browsers) has a chance to read the dimensions of the first image
            function loadSet(elem){
               $(window).load(function(){
                  elem.data('origImgHeight',  elem.find('img').height() );
                  methods.delayStart();
               });
            }
         });
      },
      delayStart : function(){
         setTimeout( function(){
            $('#right').trigger('click');
         }, 500 );
      },
      scrollFocus : function( dir ) {
         var $this = $(this);

         // start the action, but if the actions are not done then return
         if(methods.actionComplete.call($this)===false){
            return;
         }
         // reset the actions to show an in progress state
         methods.resetActions.call($this);
         // move all elements
         methods.scroll.call($this, dir);
      },
      scroll : function(dir){
         var $this = $(this);

         //                      swap
         if(dir === $this.data('RIGHT') ){
            var lastElm = $this.find("li:eq(" + ($this.data('elements').length-1) + ")");
            lastElm.css('left',- $this.data('elemWidth') )
            $this.find('ul').prepend( lastElm );
         }
         else if(dir === $this.data('LEFT') ){
            var firstElm = $this.find("li:eq(0)");
            firstElm.css('left', ($this.data('elements').length) * $this.data('elemWidth')  );
            $this.find('ul').append( firstElm );
         }
         var midStepTop = Math.floor( Math.abs($this.data('elemTop') - $this.data('focusedElemTop')) /2 ) ;
         var midZIndexSet = {
            focus:false,
            unFocus:false
         };
         //                      scroll
         // needs to be $this.find("li"), not the cached version
         $.each($this.find("li"), function(i,v){
            var shift = $this.data('elemWidth');
            shift =  shift * i;
            var hasFocusedElem = false;

            // unFocus
            if( $(v).data('isFocused') === true){
               $(v).add($(v).find('img'))
               .animate({
                  "top": $this.data('elemTop') ,
                  "width": $(v).data('origImgWidth'),
                  "height": $(v).data('origImgHeight')
               },{
                  queue:false,
                  duration:  $this.data('scrollDuration'),
                  complete: function(){
                     methods.actionComplete.call($this,"unFocus",true);
                  },
                  step: function(now, fx){
                     if($(fx.elem)[0].tagName == 'LI' && fx.prop === 'top' && now > midStepTop && !midZIndexSet.unFocus ){
                        $(fx.elem).css('z-index', 0);
                        midZIndexSet.unFocus  = true;
                     }
                  }
               } );
               $(v).data('isFocused', false);
               hasFocusedElem = true;
            }
            // focused element
            else if(i === $this.data('focusedElemIndex') ){
               
               $(v).add($(v).find('img'))
               .css('z-index',250)
               .animate({
                  "top":  $this.data('focusedElemTop'),
                  "width": $this.data('focusedElemWidth'),
                  "height":  ($this.data('focusedElemWidth') / $(v).data('origImgWidth')) * $(v).data('origImgHeight')//,
                  //"height": 300

               },{
                  queue:false,
                  duration:  $this.data('scrollDuration'),
                  complete: function(){
                     methods.actionComplete.call($this,"focus",true);
                  },
                  step: function(now, fx){
                     if($(fx.elem)[0].tagName == 'LI' && fx.prop === 'top' && now < midStepTop && !midZIndexSet.focus   ){
                        $(fx.elem).css('z-index', 1000);
                        midZIndexSet.focus = true;
                     }
                  }
               } );
               // onFocus
               $(v).data('isFocused', true);
               // getFocusedElemText : [label, blurb]
               $this.trigger('focus', methods.getFocusedElemText.call($this, $(v)));

               shift = shift - $this.data('focusedElemShiftLeft'); // lefft offset
            }else {
               $(v).add($(v).find('img')).css('z-index', 0)
            }

            $(v).animate({
               "left":   shift
            },
            {
               duration: $this.data('scrollDuration'),
               queue:false
            })
            // end of loop
            if( i>= $this.data('elements').length-1){
               methods.actionComplete.call($this,"scroll",true);
               if(hasFocusedElem === false){
                  methods.actionComplete.call($this, 'unFocus', true );
               }

            }
         });
      },
      getFocusedElemText : function(elem){
         var header = elem.find('.img-caption').html();
         var blurb = elem.find('.img-text').html();
         return [header, blurb];
      },
      resetActions : function(){
         var $this = $(this);
         $.each($this.data('actions'), function(i,v){
            $this.data('actions')[i] = false ;
         })
      },
      actionComplete : function(action, complete){
         var $this = $(this);

         if(complete === true){
            $this.data('actions')[action]=true;
         }
         else if(!action){
            var trueTotal = 0;
            $.each($this.data('actions'), function(i,v){
               if(v === true)trueTotal++;
            })
            if(trueTotal==3)return true;
            else return false;
         }
      }
   };

   $.fn.scrollFocus = function( ) {
      return methods.init.apply( this, arguments );
   };

})( jQuery );


