/**
 * jQuery.belt
 * Date: 2010/11/12
 *
 * @author Michaël van Oosten
 * @version 1.0
 *
 **/

(function($) {
	$.fn.belt = function(type,settings) {

		var static = {
			'obj' : null,
			'direction' : null,
			'index' : null,
			'scrollcount' : null
		};

		var config = {
			'animation_speed' : 500,
			'addclass' : 'jquery_belt'
		};

		if (settings) $.extend(config, settings);
		
		var method = {			
			
			/*
			 *  INITIALIZE
			 *  use function once e.g. within $(document).ready()
			 */

			initialize : function() {

				// add styles when javascript turned on
				static.obj.addClass( config.addclass );

				// calculate width								
				var beltUl = static.obj.find('ul'),
					beltLi = beltUl.eq(0).find('li'),
					beltLiWidth = 4;
				
				beltLi.each(function() {
					beltLiWidth += $(this).outerWidth();
				});
				
				// only create 'belt' if beltLiWidth exceeds beltWidth
				if( beltLiWidth > static.obj.outerWidth() ) {

					beltUl.each(function(i) {
						beltLi = beltUl.eq(i).find('li');
						
						// clone last <li>
						var beltLiFirst = beltLi.eq(0),
							beltLiLast = beltLi.eq( beltLi.length - 1 );
							
						beltLiLast.clone().prependTo( beltUl.eq(i) );
						beltLiLast.remove();
						
						// recalculate width after adding class to first item
						beltLiWidth -= beltLiFirst.outerWidth();
						beltLiFirst.addClass('first');
						beltLiWidth += beltLiFirst.outerWidth();
						
						// recalculate belt width and apply
						// beltLiWidth += beltLiLast.outerWidth() + beltLiFirst.outerWidth();
						beltUl.width(beltLiWidth).css('margin-left', -1 * Math.round( beltLiFirst.outerWidth() / 2 ) );

					});
					
					// add previous + next buttons; add click listener
					method['addPreviousNext'].call(this);
					
				}

				method['initFancybox'].call(this);
				
			},
			
			/*
			 *  ADD PREVIOUS/NEXT
			 *  add previous + next buttons; add click listener
			 */
			 
			addPreviousNext : function() {
				static.obj.append('<a class="previous" href="#">vorige</a><a class="next" href="#">volgende</a>');
				static.obj.find('a.previous,a.next').click(function() {
					static.obj = $(this).parents('.' + config.addclass);
					static.direction = ( $(this).hasClass('previous') ) ? 'previous' : 'next';
					method['beltScroll'].call(this);
					return false;
				});
				
				// vertical align middle
				var btn = static.obj.find('a.previous,a.next');
				btn.css('top', Math.round( ( parseInt(static.obj.outerHeight()) - parseInt(btn.outerHeight()) ) / 2) );
				
			},

					
			/*
			 *  INITIALIZE FANCYBOX
			 *  ...
			 */

			initFancybox : function() {
				static.obj.find('li a').fancybox({
					'transitionIn'		: 'none',
					'transitionOut'		: 'none',
					'titlePosition' 	: 'over',
					'titleFormat'		: function(title, currentArray, currentIndex, currentOpts) {
						return '<span id="fancybox-title-over">Image ' + (currentIndex + 1) + ' / ' + currentArray.length + (title.length ? ' &nbsp; ' + title : '') + '</span>';
					}
				});
			},
			 
			/*
			 *  CALCULATE SCROLL END
			 *  define -depending on direction- index of $('.belt li') which is first/last visible in the viewport
			 */

			calculateScrollEnd : function() {

				var beltLi = static.obj.find('ul:eq(0) li'),										// [ $('.belt li') ]
					liCount = beltLi.length,																			// [ $('.belt li').length ]
					beltOffsetLeft = static.obj.offset().left;										// [ $('.belt').offset().left ]
				
				static.index = ( static.direction == 'previous' ) ? 0 : liCount-1;		// define starting point [ $('.belt li').index() ] depending on direction
				
				while( static.index >= 0 && static.index < liCount ) {
					var beltLiOffsetLeft = beltLi.eq(static.index).offset().left;

					if( static.direction == 'previous' ) {
						if( beltLiOffsetLeft > beltOffsetLeft  )
							return;
						static.index++;
					} else {
						if( beltLiOffsetLeft < (beltOffsetLeft + static.obj.outerWidth()) )
							return;
						static.index--;
					}
				}
			},


			/*
			 *  CALCULATE SCROLL COUNT
			 *  calculate number of items to be scrolled
			 */

			calculateScrollCount : function () {

				var beltLi = static.obj.find('ul:eq(0) li'),
					scrollWidth = static.obj.outerWidth() - Math.floor( beltLi.eq( static.index ).outerWidth() / 2 ),
					width = 0,
					index = static.index;

				static.scrollcount = 0;
					
				while( width < scrollWidth ) {
					width += beltLi.eq( static.index ).outerWidth();
					static.scrollcount++;
					if( static.direction == 'previous' ) {
						index--;
						index = ( index < 0 ) ? beltLi.length-1 : static.index;
					} else {
						index++;
						index = ( static.index == beltLi.length ) ? 0 : static.index;
					}
				}
				static.scrollcount--;
			
			},


			/*
			 *  BELT SCROLL
			 *  clone $('.belt li') instances before or after and animate belt; afterwards remove original cloned instances
			 */

			beltScroll : function() {

				var beltUl = static.obj.find('ul');

				// only scroll if no animation is pending
				if( !beltUl.is(':animated') ) {

					method['calculateScrollEnd'].call(this);
					method['calculateScrollCount'].call(this);
	
					var width = 0,
						originalWidth = beltUl.width(),
						marginLeft = parseInt(beltUl.css('margin-left')),
						marginTo = 0;
	
					beltUl.each(function(j) {

						var thisBeltLi = null,
							beltLi = beltUl.eq(j).find('li'),
							index = ( static.direction == 'previous' ) ? beltLi.length-1 : 0;
						
						// prepend li based on index to belt; modify margin-left
						if( static.direction == 'previous' ) {
							marginTo = marginLeft;
							for(i=0; i<static.scrollcount; i++) {
								thisBeltLi = beltLi.eq( index );
								thisBeltLi.clone().prependTo( beltUl.eq(j) );

								index--;
								index = ( index < 0 ) ? beltLi.length-1 : index;

								width += ( j == 0 ) ? thisBeltLi.outerWidth() : 0;
								beltUl.eq(j)
									.width( beltUl.eq(j).width() + thisBeltLi.outerWidth() )
									.css('margin-left', parseInt(beltUl.eq(j).css('margin-left')) - thisBeltLi.outerWidth());
							}

						// append li based on index to belt; margin-left stays the same
						} else {
							// 
							for(i=0; i<static.scrollcount; i++) {
								thisBeltLi = beltLi.eq( index % static.scrollcount );
								thisBeltLi.clone().appendTo( beltUl.eq(j) );

								index++;
								index = ( static.index == beltLi.length ) ? 0 : index;

								width += ( j == 0 ) ? thisBeltLi.outerWidth() : 0;
								beltUl.eq(j).width( beltUl.eq(j).width() + thisBeltLi.outerWidth() );
							}
							marginTo = marginLeft - width;
						}
					});

					// animate belt; remove items (and change margin-left) in callback function
					beltUl.each(function(i) {
						beltUl.eq(i).animate(
							{ marginLeft : marginTo },
							config.animation_speed,
							function() {
								beltLi = static.obj.find('ul:eq(' + i + ') li');
								beltUl.eq(i).width( originalWidth );
								if( static.direction == 'previous' ) {
									for(j=0; j<static.scrollcount; j++) {
										beltLi.eq(beltLi.length-1-j).remove();
									}
								} else {
									beltUl.eq(i).css('margin-left', marginLeft);
									for(j=0; j<static.scrollcount; j++) {
										beltLi.eq(j).remove();
									}
								}
							}
						);
					});
					
					method['initFancybox'].call(this);
					
				}				
			}
			
		};
		
		this.each(function() {
			static.obj = $(this);
			if(typeof type == "string") {
				// call given method
				method[type].call(this);
				return this;
			}
		});
 
 		return this;

	};

})(jQuery);
