
( function($) {

	var LBi = window.LBi;
	
	var SlideshowLibrary = function ()
	{
		this.slideshows = {};
	};
	
	// Methods	
	SlideshowLibrary.prototype.addSlideshow = function addSlideshow( id, instance )
	{
		this.slideshows[ id ] = instance;
	};
	
	SlideshowLibrary.prototype.getSlideshow = function getSlideshow( id )
	{
		return this.slideshows[ id ];
	};
	
	SlideshowLibrary.prototype.removeSlideshow = function removeSlideshow( id )
	{
		delete this.slideshows[ id ];
	};
	
	LBi.namespace('SlideshowLibrary', SlideshowLibrary );
	LBi.slideshows = new SlideshowLibrary();
	
	var Slideshow = function Slideshow( node, settings )
	{
		this.node = node;
		this.$node = $( node );
	
		// use or create id for this slideshow
		this.slideshowId = this.$node.attr( 'id' );
		if ( !this.slideshowId ) 
		{
			this.slideshowId = "slideshow_" + Math.round( Math.random() * 1000000000 );
			this.$node.attr( 'id', this.slideshowId );
		}
		this.slideshowSelector = '#' + this.slideshowId;
				
		this.settings = $.extend( { }, Slideshow.DEFAULTS, settings );

		// initialize data
		this.data = {
			slides: [],
			currentSlideIndex: 0
		};
		
		// initialize some peripheral functionalities
		this.init();
		
		// if we have a parent, use its data and then render
		if ( this.settings.parentSlideshow )
		{
			this.useData( this.settings.parentSlideshow );
			this.render();
		}
		
		// else collect our own data
		else
		{
			this.collectData();		
			this.render();
		}
		
		// Add The Slideshow To The Library
		LBi.slideshows.addSlideshow( this.slideshowId, this );
	}
	
	Slideshow.DEFAULTS = { 
		maxSlides: 99999999,
		infoContainer: undefined,
		parentSlideshow: undefined,
		collapsePaginator: false,
		showSlideInfo: false,
		fit: "outer"
	}; 
		
	// Methods	
	Slideshow.prototype.init = function init()
	{
		this.$slideshowDisplay = this.$node.find( ".slideshow_display" ).eq( 0 );
		this.$slideshowPager = this.$node.find( ".panel_page_list" ).eq( 0 );
		this.$navigationPanel = this.$node.find( ".slideshow_navigation_panel" ).eq( 0 );
		this.$infoContainer = this.$node.closest( '.body' ).find( ".infoContainer" );

		this.$slideshowDisplay.css( { display: "block" } );
		this.$navigationPanel.css( { display: "block" } );
		
 		this.imageWidth = Number( this.$node.attr( 'data-image-width' ) );
 		this.imageHeight = Number( this.$node.attr( 'data-image-height' ) );
	};	
	
	Slideshow.prototype.collectData = function collectData() 
	{
		var self = this;
		var $slideshowData = this.$node.find( ".slideshow_data" );
		
		// remove the data from the DOM - it is not actually used to display the slideshow
		$slideshowData.css({ display: "none" }).remove();
		
		if ( $slideshowData.length > 0 )
		{				
			var slides = [];
		
			// Get slide data from list items	
			$slideshowData.find( "li" ).each( function( index, element )
			{		
				var $slide = $( element );
				
				// extract table data and remove the table from the DOM
				var info = [];
				var $table = $slide.find( 'table' );
				$table.find( "tr" ).each( function()
				{
					var $row = $( this );
					
					// Trim Individual Property And Assign
					var key = QuickTrim( $row.find( 'th' ).eq( 0 ).text() ); 
					var value = QuickTrim(  $row.find( 'td' ).eq( 0 ).text() ); 
					
					info.push( { key: key, value: value } );
				} );
				$table.remove();
				
				$slide.data( { index:index, info: self.renderSlideData( info ) } );					
				slides.push( $slide );				
			} );
			
			this.data.slides = slides;
		}
	};
		
	Slideshow.prototype.useData = function useData( id )
	{
		var parentData = LBi.slideshows.getSlideshow( id ).data;
		
		// use the data from another slideshow
		this.data.slides = parentData.slides.slice( 0 );
		this.data.currentSlideIndex = parentData.currentSlideIndex;
	};
		
	Slideshow.prototype.renderSlideData = function renderSlideData( info )
	{
		var lTable = "<table class=\"table-alt table-zebra-alt\">";
		var rTable = "<table class=\"table-alt table-zebra-alt\">";
		
		var c = info.length;
		if ( c == 0 ) 
		{
			return "";
		}
		
		var l = Math.ceil( info.length / 2 );
	
		var row_class = "odd";
		for ( var i = 0; i < l; i++ )
		{				
			lTable += "<tr class=\"" + row_class + "\">";
			lTable += "<td>" + info[ i ].key + "</td>";
			lTable += "<td>" + info[ i ].value + "</td>";
			lTable += "</tr>";
			
			row_class = row_class == "odd" ? "even" : "odd";
		}
		
		var row_class = "odd";
		for ( var i = l; i < c; i++ )
		{			
			rTable += "<tr class=\"" + row_class + "\">";
			rTable += "<td>" + info[ i ].key + "</td>";
			rTable += "<td>" + info[ i ].value + "</td>";
			rTable += "</tr>";
			
			row_class = row_class == "odd" ? "even" : "odd";
		}
		
		lTable += "</table>"; 
		rTable += "</table>"; 
		
		return lTable + rTable; 
	};
		
	Slideshow.prototype.render = function render() 
	{ 
		var self = this;
		
		// add the images to the display element
		for ( var i = 0; i < this.settings.maxSlides && i < this.data.slides.length; i++ )
		{
			var $original =  this.data.slides[ i ];
			var $clone = $original.clone();
			$clone.data( $original.data() );
			
			this.$slideshowDisplay.append( $clone );
		}
			
		this.$slideshowDisplay.imagesLoaded( function ()
		{
			self.pager = new SlideshowPager( self.$slideshowPager, { 
				numPages: self.$slideshowDisplay.children().length
			} );
			
			self.$slideshowDisplay.bind( "slide_change", function( e, slideIndex )
			{
				self.data.currentSlideIndex = slideIndex;
				self.pager.update( slideIndex );
				
				self.showSlideInfo( slideIndex );
			} );
					
			self.display = new SlideshowDisplay( self.$slideshowDisplay, 
			{ 
				initialSlideIndex: self.data.currentSlideIndex,
				imageWidth: self.imageWidth,
				imageHeight: self.imageHeight, 
				infoContainer: self.settings.infoContainer,
				showSlideInfo: self.settings.showSlideInfo,
				fit: self.settings.fit
			} );
			self.$slideshowPager.bind( "slide_select", function( e, slideIndex )
			{
				self.display.go( slideIndex );
			} );
		} );
	};	
	
	Slideshow.prototype.showSlideInfo = function showSlideInfo( slideIndex )
	{
		if ( this.settings.showSlideInfo && this.$infoContainer.length > 0 )
		{
			var info = this.data.slides[ slideIndex ].data( "info" );			
			this.$infoContainer.html( info );
		}	
	};
	
	Slideshow.prototype.pause = function pause ()
	{
		if ( this.display )
		{
			this.display.pause();
		}
	};
	
	Slideshow.prototype.resume = function resume ()
	{
		if ( this.display )
		{
			this.display.resume();
		}
	};
	
	Slideshow.prototype.destroy = function destroy()
	{
		if ( this.display )
		{
			this.display.destroy();
			delete this.display;
		}
		if ( this.$slideshowDisplay )
		{
			this.$slideshowDisplay.unbind( "slide_change" );
			delete this.$slideshowDisplay;
		}
		
		if ( this.pager )
		{
			this.pager.destroy();
			delete this.pager;
		}
		if ( this.$slideshowPager )
		{
			this.$slideshowPager.unbind( "slide_select" );
			delete this.$slideshowPager;
		}
		
		delete this.node;
		delete this.$node;
		delete this.slideshowId;
		delete this.slideshowSelector;	
		delete this.settings;
		delete this.data;		
	};
	
	LBi.namespace('Slideshow', Slideshow );
	$.registerPlugin('LBiSlideshow', Slideshow );
	
	SlideshowDisplay = function ( node, settings )
	{
		this.$node = $( node );
		this.$children = this.$node.children();
		this.settings = $.extend( {}, SlideshowDisplay.DEFAULTS, settings );
		
		this.init();
		this.go( this.settings.initialSlideIndex );
	}
	
	SlideshowDisplay.DEFAULTS = {
		timeout: 3000,
		speed: 300,
		initialSlideIndex: 0,
		initialPaused: false,
		zIndex: 10,
		assumedTableHeight: 190,
		showSlideInfo: false
	};
	
	SlideshowDisplay.prototype.init = function init()
	{
		var self = this;
	
		this.$prevSlide = null;
		this.$currSlide = null;
		this.zIndex = this.settings.zIndex;
		
		var imagesMaxHeight = 0;
		this.paused = this.settings.initialPaused == true;
		this.showInfoTables = false;
		
		this.$children.each( function( index, element )
		{
			var $element = $( element );
			
			self.showInfoTables = ( self.showInfoTables || $element.data( 'info' ) != "" ) && self.settings.showSlideInfo;
			
			imagesMaxHeight = Math.max( imagesMaxHeight, $element.height() );
			
			var $img = $element.find( 'img' );
			$element.data( { width: $img.width(), height: $img.height() } );
			$element.css( {
				position: "absolute",
				display: "none",
				zIndex: self.zIndex
			} );
		} );
		
		var actualAvailableHeight = Number( this.$node.closest( ".slideshow_wrapper" ).attr( "data-max-total-height" ) ) || 100000;
		if ( this.showInfoTables )
		{
			actualAvailableHeight -= this.settings.assumedTableHeight;
		}
		
		this.settings.imageHeight = Math.min( this.settings.imageHeight, actualAvailableHeight );

		this.$node.css( {
			position: "relative",
			height: this.settings.imageHeight,
			width: this.settings.imageWidth
		} );
		
		var totalHeight = this.settings.imageHeight + 40;
		if ( this.showInfoTables )
		{
			totalHeight += this.settings.assumedTableHeight;
		}
		
		this.$node.closest( '.slideshow_wrapper' ).trigger( "sizing_complete", [ totalHeight ] );
	};
	
	SlideshowDisplay.prototype.go = function go( index )
	{	
		var self = this;
		this.slideIndex = index;
		
		if ( index >= this.$children.length )
		{
			throw new Error( "index is out of range" );
		}
		
		if ( this.$prevSlide )
		{
			this.$prevSlide.css( {
				zIndex: this.zIndex,
				display: "none"
			} );
		}
		
		if ( this.$currSlide )
		{
			this.$currSlide.css( {
				zIndex: this.zIndex + 1
			} );
		}
		
		var $nextSlide = this.$children.eq( this.slideIndex );
		$nextSlide.css( {
			opacity: 0,
			zIndex: this.zIndex + 2,
			display: "block"
		} );
		$nextSlide.animate( { opacity: 1 }, this.settings.speed );
		
		if ( !$nextSlide.data( 'resized' ) )
		{
			$nextSlide.data( 'resized', true );
			
			var w = $nextSlide.data( 'width' );
			var h = $nextSlide.data( 'height' );
			
			var wr = this.settings.imageWidth / w;
			var hr = this.settings.imageHeight / h;
			var r = 1;
			
			if ( this.settings.fit == "inner" )
			{
				r = Math.min( wr, hr );
			}
			else if ( this.settings.fit == "outer" )
			{
				r = Math.max( wr, hr );
			}
			
			w = w * r;
			h = h * r;
			
			$nextSlide.css( {
				width: w + "px",
				height: h + "px",
				left: ( 0.5 * ( this.settings.imageWidth - w ) ) + "px",
				top: ( 0.5 * ( this.settings.imageHeight - h ) ) + "px",
			} );
		}
		
		this.$prevSlide = this.$currSlide;
		this.$currSlide = $nextSlide;
		
		this.clearAutoFlipTimeout();
		this.setAutoFlipTimeout();
		
		this.$node.trigger( "slide_change", [ this.slideIndex ] );
	};
	
	SlideshowDisplay.prototype.pause = function pause()
	{
		if ( !this.paused )
		{
			this.paused = true;
			this.clearAutoFlipTimeout();
		}
	};
	
	SlideshowDisplay.prototype.resume = function resume() 
	{
		if ( this.paused )
		{
			this.paused = false;
			this.clearAutoFlipTimeout();
			this.setAutoFlipTimeout();
		}	
	};
	
	SlideshowDisplay.prototype.clearAutoFlipTimeout = function clearAutoFlipTimeout()
	{
		if ( this.autoFlipTimeout )
		{
			clearTimeout( this.autoFlipTimeout );
			this.autoFlipTimeout = undefined;
		}
	};
	
	SlideshowDisplay.prototype.setAutoFlipTimeout = function setAutoFlipTimeout()
	{
		if ( !this.paused )
		{
			var nextIndex = this.slideIndex + 1;
			if ( nextIndex >= this.$children.length )
			{
				nextIndex = 0;
			}
			this.autoFlipTimeout = setTimeout( this.go.bind( this ), this.settings.timeout, nextIndex );
		}
	}
	
	SlideshowDisplay.prototype.destroy = function destroy()
	{
		this.clearAutoFlipTimeout();
		this.$node.empty();
		
		delete this.$prevSlide;
		delete this.$currSlide;
		delete this.zIndex;
		
		delete this.slideshowHeight;
		delete this.slideshowWidth;
		delete this.paused;
		
		delete this.settings;
		delete this.node;
		delete this.$node;
		delete this.$children;
	}
	
	SlideshowPager = function ( node, settings )
	{
		this.$node = $( node );		
		this.settings = $.extend( {}, SlideshowPager.DEFAULTS, settings );
		
		this.init();
	}
	
	SlideshowPager.DEFAULTS = {
		initialIndex: 0,
		numPages: 2,
		inactiveTemplate: '<a href="#" data-page="{pageindex}">{pagenum}</a>',
		activeTemplate: '<div class="active"><img src="/sites/all/themes/monumenten/images/slideshow-clock.gif?nocache={nocache}" /></div>',
		collapsedTemplate: '<span>&hellip;</span>',
		collapseThreshold: 12
	};
	
	SlideshowPager.prototype.init = function init()
	{		
		this.collapsed = this.settings.numPages > this.settings.collapseThreshold;
	};
	
	SlideshowPager.prototype.update = function update( activeIndex )
	{
		var paginationHtml = "";
		
		var startIndex = this.collapsed && ( activeIndex > 4 ) ? activeIndex - 2 : 0;
		var endIndex = this.collapsed && ( activeIndex + 5 < this.settings.numPages ) ? activeIndex + 3 : this.settings.numPages;		
		
		if ( startIndex > 0 )
		{
			var first = this.settings.inactiveTemplate;
			first = first.replace( /{pagenum}/gi, String( 1 ) );
			first = first.replace( /{pageindex}/gi, String( 0 ) );
		
			paginationHtml += first;
			paginationHtml += this.settings.collapsedTemplate;
		}
		
		for ( var i = startIndex; i < endIndex; i++ )
		{		
			var template;
			if ( i == activeIndex )
			{
				template = this.settings.activeTemplate;
			}
			else
			{
				template = this.settings.inactiveTemplate;
			}
			
			template = template.replace( /{pagenum}/gi, String( i + 1 ) );
			template = template.replace( /{pageindex}/gi, String( i ) );
			template = template.replace( /{nocache}/gi, String( Math.random() * 10000000000 ) );
			
			paginationHtml += template;
		}
		
		if ( endIndex < this.settings.numPages )
		{
			var last = this.settings.inactiveTemplate;
			last = last.replace( /{pagenum}/gi, String( this.settings.numPages ) );
			last = last.replace( /{pageindex}/gi, String( this.settings.numPages - 1) );
			
			paginationHtml += this.settings.collapsedTemplate;
			paginationHtml += last;
		}
		
		this.$node.html( paginationHtml );
		this.$node.find( 'a' ).bind( "click", this.handleClick.bind( this ) );
	};
	
	SlideshowPager.prototype.handleClick = function handleClick( e )
	{
		this.$node.trigger( "slide_select", Number( $( e.currentTarget ).attr( "data-page" ) ) );
		e.preventDefault();
		e.stopImmediatePropagation();
	};
	
	SlideshowPager.prototype.destroy = function destroy()
	{
		this.$node.find( 'a' ).unbind( "click" );
		this.$node.empty();
		delete this.$node;
		delete this.settings;
	};
	
	function QuickTrim(s)
	{
		var l = 0; 
		var r = s.length -1;
		
		while (l < s.length && s[l] == " ")
		{	
			l++; 
		}
		
		while (r > l && s[r] == " ")
		{	
			r -= 1;	
		}
		
		return s.substring(l, r + 1);
	}
	
})( jQuery );

