/*********************************************************************
 * BMS 2008-01-03
 *
 * Slideshow is a class designed to display an arbirary set of 
 * images using an arbitrary set of effects. MooTools is the 
 * Javascript library used here so many of the funny looking 
 * constructs are supplied by MooTools.  For example, $$() is a 
 * MooTools function that retrieves a collection of elements and 
 * returns them as an array of it Element types.
 *
 * Javascript works best when anonymous functions are used all 
 * over the place and it's great. You can see this in the 
 * definition of the load event.
 *
 * The class doesn't have any public method.  Instead the show is
 * defined by the array of object definitions passed into the
 * class constructor.
 *
 * The slide show is controlled by specifying a set of parameters
 * and each paramter is an object property.  Most are optional with
 * defaults.  The mandatory and the optional parameters are idenified
 * below and the default value is shown for each optional parameter
 *
 * ------------------------------------------------------------------
 * Mandatory:
 *
 * Name                   Comment                       Default value
 * ------------------------------------------------------------------
 * id					  A unique identifier for the             N/A
 *                        slide that can be referred 
 *                        externally.
 *
 * ------------------------------------------------------------------
 * Optional:
 *
 * Name                   Comment                       Default value
 * ------------------------------------------------------------------
 * wait					  The time to wait once the			4 seconds
 *                        slide has been displayed
 * ------------------------------------------------------------------
 * title				  The comment be displayed and     No comment
 *                        image title to set
 * ------------------------------------------------------------------
 * clearAllAfter		  True if other images are to           False
 *                        be cleared AFTER the current
 *                        image is displayed
 * ------------------------------------------------------------------
 * clearAllBefore		  True if other images are to           False
 *                        be cleared BEFORE the current
 *                        image is displayed
 *
 *                        If both 'clearAll' parameters
 *                        are true then clearAllAfter 
 *                        will win.
 * ------------------------------------------------------------------
 * clearAllTogether		  If true, all the existing images       True
 *                        will be removed simultaneously
 * ------------------------------------------------------------------
 * clearSlideBefore		  The id of the previous image to       No id
 *                        remove BEFORE the current slide 
 *                        is displayed.
 * ------------------------------------------------------------------
 * clearSlideAfter		  The id of the previous image to       No id
 *                        remove AFTER the current slide 
 *                        is displayed.
 *
 *                        The 'clearSlide' parameters 
 *                        will be ignored if either of the 
 *                        clearAll parameters are True
 * ------------------------------------------------------------------
 * clearSlideDelay		  The time to wait after removing   0 seconds
 *                        a previous slide
 * ------------------------------------------------------------------
 * startCSS               An object definition listing the   See note
 *                        styles to be set when the image     
 *                        is initialized                        
 * ------------------------------------------------------------------
 * appearCSS			  An object definition listing the   See note
 *                        styles to be set when the image
 *                        is displayed.
 * ------------------------------------------------------------------
 * transitionCSS		  An object definition listing the   See note
 *                        styles to be set when the image
 *                        is transitioned.
 * ------------------------------------------------------------------
 * disappearCSS           An object definition listing the   See note
 *                        styles to be set when the image
 *                        is cleared.
 * ------------------------------------------------------------------
 * appearDuration         The time the slide should take     1 second
 *                        to appear.
 * ------------------------------------------------------------------
 * appearDuration         The time the slide should take     1 second
 *                        to appear.
 * ------------------------------------------------------------------
 * appearDelay			  The time the slide should stay    0 seconds
 * ------------------------------------------------------------------
 * transitionDuration     The time the slide should take     1 second
 *                        to transition.
 * ------------------------------------------------------------------
 * transitionDelay		  The time the transition should    0 seconds
 *                        stay.
 * ------------------------------------------------------------------
 * disappearDuration      The time the slide should take   0.5 second
 *                        to appear
 * ------------------------------------------------------------------
 * useDiv				  Sets an element as a DIV not an       false
 *                        IMG.  This allows a PNG image to 
 *                        be support transparent - even on IE6!
 * ------------------------------------------------------------------
 * Notes:
 *
 * The CSS definitions will centre the slide in the display element
 * if not otherwise specified.  They will also have:
 *
 * startCSS				  transparent
 * appearCSS			  opaque
 * disappearCSS			  transparent
 *
 * The CSS parameters should use MooTools specifiers.  For example
 * the 'vertical-align' CSS specification appears as a 'verticalAlign'
 * object property name.  This is needed because the hyphen sign is
 * not a legal character in JavaScript.  The use of camel casing when
 * joining the two parts of the CSS name is consistent.
 *
 *********************************************************************/

var path = 'pages/images/screenshots/';

var mySlides = [
/*
				{ id: 'background',
				  src: path + 'background.png',
				  wait: 1000,
				  clearAllBefore: true, 
				  clearAllTogether: false, 
				  title: 'Meet ComplyXL' 
				},

				{ id: 'words',
				  src: path + 'words.jpg',
				  wait: 1000,
				  startCSS: { left: '-401px', top: '80px' },
				  appearCSS: { left: '-401px', top: '80px', height: '39px' },
				  appearDelay: 2000,
				  transitionCSS: { left: '5px', top: '80px', width: '285px', height: '13px' },
				  transitionDelay: 2000,
				  title: 'Meet ComplyXL' 
				},

				{ id: 'wholepicture',
				  src: path + 'WholePicture.jpg',
				  wait: 1000,
				  startCSS: { top: '120px' },
				  appearCSS: { top: '120px' },
				  title: 'Meet ComplyXL' 
				},

				{ id: 'seethedifference',
				  src: path + 'SeeTheDifference.png',
				  wait: 6000,
				  startCSS: { top: '160px' },
				  appearCSS: { top: '160px' },
				  title: 'Meet ComplyXL' 
				},
*/
				{ id: 'logo',
				  src: path + 'logo.jpg',
				  wait: 6000,
				  startCSS: { left: '-300px' },
				  clearAllBefore: true, 
				  clearAllTogether: false, 
				  title: 'Meet ComplyXL' 
				},
/*
				{ id: 'star',
				  src: path + 'NewStar.png',
				  appearCSS: { opacity: 0.5 },
				  useDiv: true,
				  wait: 6000
				},
*/
// Addin
				{ id: 'addinZoomout',
				  src: path + 'AddinZoomout.jpg',
				  clearAllAfter: true,
				  wait: 6000,
				  title: 'The ComplyXL client can be standalone or an add-in to Excel' 
				},
				{ id: 'ManageVersions', 
				  src: path + 'ManageVersionsAddin.jpg',
				  title: 'See a simple version history for the current spreadsheet' 
				},
				{ id: 'addinZoomin',
				  src: path + 'AddinZoomin.png',
				  startCSS: { opacity: 1, left: '17px', top: '0px', width: '198px', height: '173px' }, 
				  appearDuration: 500,
				  clearSlideBefore: 'ManageVersions',
				  clearSlideDelay: 500,
				  title: 'ComplyXL is an add-in' 
				},

// Notification
				{ id: 'notifications',
				  src: path + 'notifications.jpg',
				  clearSlideBefore: 'addinZoomin',
				  clearSlideDelay: 500,
				  title: 'Subscribe to be notified when spreadsheets change' 
				},

// Comparison

				{ id: 'comparisonbefore',
				  src: path + 'comparisonbefore.jpg',
				  clearSlideBefore: 'notifications',
				  clearSlideDelay: 1500,
				  clearAllAfter: true,
				  title: 'Graphical or report change review' 
				},

				{ id: 'filterbuttonsbefore',
				  src: path + 'FilterButtonsBefore.png',
				  startCSS: { left: '96px', top: '158px', width: '109px', height: '96px', opaque: 1 },
				  title: 'The differences shown can be filtered' 
				},

				{ id: 'comparisonafter',
				  src: path + 'comparisonafter.jpg',
				  appearCSS: { opacity: 0 },
				  appearDuration: 0,
				  wait: 0,
				  title: '' 
				},

				{ id: 'filterbuttonsafter',
				  src: path + 'FilterButtonsAfter.png',
				  clearSlideAfter: 'filterbuttonsbefore',
				  title: 'Change the filter to show just changes to numeric values' 
				},

				{ id: 'showcomparisonafter',
				  slide: 'comparisonafter',
				  transitionCSS: { opacity: 1 },
				  clearSlideAfter: 'comparisonbefore',
				  wait: 0,
				  title: ''
				},

				{ id: 'shrinkfilterbuttonsafter',
				  slide: 'filterbuttonsafter',
				  transitionCSS: { left: '96px', top: '158px', width: '109px', height: '96px' },
				  wait: 0,
				  title: 'Now the focus is on changed numeric cell values only'
				},

				{ id: 'fadefilterbuttonsafter',
				  slide: 'filterbuttonsafter',
				  transitionCSS: { opacity: 0 },
				  title: ''
				},
//Macro differences
				{ id: 'macrodifferences',
				  src: path + 'MacroDifferencesSmall.jpg',
				  clearAllAfter: true,
				  title: 'See changes to all aspects of spreadsheets such as macros' 
				},

				{ id: 'macrodifferenceszoom',
				  src: path + 'MacroDifferencesZoom.jpg',
				  startCSS: { left: '112px', top: '112px', width: '126px', height: '96px' },
				  appearCSS: {},
				  title: 'See changes to all aspects of spreadsheets such as macros' 
				},

// Repository
				{ id: 'Respository', 
				  src: path + 'Repository.png',	
				  clearAllAfter: true,
				  wait: 500,
				  title: 'You chose the technology for your spreadsheet repository' 
				}
					,
				{ id: 'RespositoryWords', 
				  src: path + 'RepositoryWords.png',	
				  title: 'You chose the technology for your spreadsheet repository' 
				},
				{ id: 'SQLServer', 
				  src: path + 'SQLServer.jpg',	
				  wait: 2000,
				  startCSS: { left: '-140px', top: '71px' }, 
				  appearCSS: { left: '0px', top: '71px' }, 
				  clearSlideBefore: 'RespositoryWords',
				  clearSlideDelay: 500,
				  title: 'You chose the technology for your spreadsheet repository'
				},
				{ id: 'Oracle', 
				  src: path + 'Oracle.png',	
				  wait: 1500,
				  startCSS:  { left: '145px', top: '120px' }, 
				  appearCSS: { left: '145px', top: '120px' }, 
				  title: 'You chose the technology for your spreadsheet repository' 
				},
				{ id: 'MySQL', 
				  src: path + 'MySQL.png',	
				  wait: 6000,
				  startCSS:  { left: '300px', top: '15px' }, 
				  appearCSS: { left: '180px', top: '15px' }, 
				  title: 'You chose the technology for your spreadsheet repository' 
				},
// Editions
				{ id: 'enterprise',
				  src: path + 'EnterpriseEdition.jpg',
				  wait: 200,
				  clearAllBefore: 'logo',
				  startCSS: { top: '10px', left: '10px' },
				  appearCSS: { top: '10px', left: '10px' },
				  title: 'Select an edition to meet your needs <a href="index.php?option=com_lyquidityhome&Itemid=264">Comparison chart</a>' 
				},
				{ id: 'professional',
				  src: path + 'ProfessionalEdition.jpg',
				  wait: 200,
				  startCSS: { top: '10px', left: '10px' } 
				},
				{ id: 'desktop',
				  src: path + 'DesktopEdition.jpg',
				  wait: 4000,
				  appearCSS: { top: '171px', left: '135px' } 
				}
			];

var SlideShow = new Class({
	
	initialize: function(displayArea, displayWidth, displayHeight, slides)
	{
		this.started = false;
		this.completed = false;

		this.imagesLoaded = [];
		this.imagesToLoad = slides;

		this.elHeight = displayHeight;
		this.elWidth  = displayWidth;
		this.el = displayArea;

		if (this.el != null && $type(this.el == 'string'))
		{
			this.el = $(this.el);
		}

		// Define all the defaults in one place
		this.defaultAnimationParameters = 
		{	id: '', wait: 4000, title: '', 
			clearAllAfter: false, clearAllBefore: false, clearAllTogether: true,
			clearSlideBefore: '', clearSlideAfter: '', clearSlideDelay: 0, 
			startCSS: {}, appearCSS: {}, /* transitionCSS: {}, */ disappearCSS: {}, 
			appearDuration: 1000, transitionDuration: 1000, disappearDuration: 500, appearDelay: 0, transitionDelay: 0
		};

		var show = this;

		this.imagesToLoad.each(function(item, i)
		{
			item.seq = i;

			if (item.src == null)
			{
				// It's a transition so put it into the output array
				var params = $merge(show,show.defaultAnimationParameters, item);
				$extend(item, params);
				show.imagesLoaded.push(item);

				return;
			}

			var img = new Asset.image(item.src, 
			{ 'onload': function()
				{
					// check to see if the seq exists already
					for(var i=0; i<show.imagesLoaded.length; i++)
					{
						if (this.seq == show.imagesLoaded[i].seq) return;
					}

					if (this.params.useDiv == null || !this.params.useDiv)
					{
						$extend(this, this.params);
						show.imagesLoaded.push(this);
					}
					else
					{
						var div = new Element('span');
						$extend(div, this.params);
						if (!window.usePNGFilter)
							div.setStyles({
								backgroundImage: 'url(' + this.src + ')',
								backgroundRepeat: 'no-repeat'
							});

						div.width = this.width;
						div.height = this.height;
						show.imagesLoaded.push(div);

						// show.imagesLoaded.push(this);
					}

					if (show.imagesLoaded.length == show.imagesToLoad.length & !show.completed)
					{
						show.startPresentation();
					}
				}
			});

			// Add the composite set of params to the image
			// It should then have a value for each one.
			img.params = $merge(show.defaultAnimationParameters, item);
			// $extend(img, params);
			// img.params = params;

			// Fix up the incompatibilities
			if (img.params.clearAllAfter & img.params.clearAllBefore) img.params.clearAllBefore = false;
			if (img.params.clearSlideBefore != '' & img.params.clearSlideAfter != '') img.params.clearSlideAfter = '';

		});
	}, 

	startPresentation: function()
	{
		show.completed = true;

		show.fx = function()
		{
			show.started = true;
			show.OverviewPresentation();
		}.delay(100);
	},

	/********************************************************************
	 *	Private Function: sortImages
	 *
	 *  Called by the sort function to sort an array of slide 
	 *  image elements
	 *
	 *	Arguments: 
	 *
	 *		a: one of the items to be sorted
	 *		b: one of the items to be sorted
	 *
	 *  Returns:
	 *
	 *  A value of:
	 *		zero if the seq paramter of a and b is the same
	 *		< 0 of a should appear before b
	 *		> 0 of a should appear after b
	 *
	 **********************************************************************/

	sortImages: function(a, b)
	{
		return a.seq - b.seq;
	},
	
	/********************************************************************
	 *	Private Function: OverviewPresentation
	 *
	 *  Presents the slideshow accommodating all the suppored slide 
	 *  parameters
	 *
	 *	Arguments: None
	 *
	 *  Returns: void
	 *
	 **********************************************************************/

	OverviewPresentation: function()
	{
		// Remove the loading image
		var ld = $('loading');
		if (ld != null) ld.remove();

		var show = this;

		this.imagesLoaded.sort(this.sortImages);
		show.ch = new Chain();

		this.imagesLoaded.each(function(img, i)
		{
			// Allow a shortcut if the page has changed
			if (!show.started) return;

			if (img.clearAllBefore)
				show.ClearAll(show.ch, img);

			var isTransitionOnly = img.src == null;
			var defaultDisplayPosition	= isTransitionOnly ? {} : { 'left': (show.elWidth / 2) - (img.width / 2), 'top': (show.elHeight / 2) - (img.height / 2), 'width': img.width, 'height': img.height };

			show.ch.chain(function()
			{
				var chInner = new Chain();

				if (!img.clearAllBefore && img.clearSlideBefore != '')
					show.clearSlide(chInner, $(img.clearSlideBefore), img.clearSlideDelay);

				if (isTransitionOnly)
				{
					// This is a transition so set the img variable to have the settings of the transition 
					var img2 = $(img.slide);
					if (img2 == null)
					{
						// This is an error so move on to the next link in the main chain
						if (show.ch.chains.length > 0)
							show.ch.callChain();
						return;
					}

					new EffectSequence( { element: img2, transitionCallChain: true, chainDelay: img.transitionDelay, effectsSequence:
					[ { duration:  img.transitionDuration, transition: Fx.Transitions.Sine.easeInOut, delay: 0,	css: img.transitionCSS } 
					]}).startChained(chInner);
				}
				else
				{
					chInner.chain(function()
					{
						var defaultStartStyle = { 'position': 'absolute', 'opacity': 0 };

						// Inject the img into the display area.
						img.setStyles( $merge(defaultStartStyle, defaultDisplayPosition, img.startCSS));

						// Add this image to the overviewimage div
						img.inject(show.el);

						if (chInner.chains.length > 0)
							chInner.callChain();

					});
				}

				chInner.chain(function()
				{
					// Check to see if the text has changed
					if (img.title != null && img.title != '' && $('comment').innerHTML != img.title)
					{
						$('comment').setHTML(img.title);
					}

					if (show.ch.chains.length > 0)
						show.ch.callChain();

				});

				chInner.callChain();

			});

			if (!isTransitionOnly)
			{
//				show.ch.chain(function()
//				{
//					alert(show.dump('appearing: ', $merge( { opacity: 1 }, defaultDisplayPosition, img.appearCSS )));
//
//					if (show.ch.chains.length > 0)
//						show.ch.callChain();
//				});

				new EffectSequence( { element: img, transitionCallChain: true, chainDelay: img.appearDelay, effectsSequence:
				[ { duration:  img.appearDuration, transition: Fx.Transitions.Sine.easeInOut, delay: 0,	css: $merge( { opacity: 1 }, defaultDisplayPosition, img.appearCSS ) } 
				]}).startChained(show.ch);

				if(img.transitionCSS != null)
				{
					new EffectSequence( { element: img, transitionCallChain: true, chainDelay: img.transitionDelay, effectsSequence:
					[ { duration:  img.transitionDuration, transition: Fx.Transitions.Sine.easeInOut, delay: 0,	css: img.transitionCSS } 
					]}).startChained(show.ch);
				}
			}

			if (img.clearAllAfter)
				show.ClearAll(show.ch, img); else
			if (img.clearSlideAfter != '')
			{
				show.ch.chain(function()
				{
					var chInner = new Chain();

					show.clearSlide(chInner, $(img.clearSlideAfter), img.clearSlideDelay);

					// Add an end inner chain link to call the next link in the main chain
					chInner.chain(function()
					{
						if (show.ch.chains.length > 0)
							show.ch.callChain();
					});

					chInner.callChain();
				});
			}

			show.ch.chain(function()
			{
				if (show.ch != null && show.ch.chains != null && show.ch.chains.length > 0)
					show.ch.callChain.delay(img.wait, show.ch);
			});

		});

		show.ch.chain(function()
		{
			if (show.started)
				show.OverviewPresentation();
		});

		show.ch.callChain();
	},

	/********************************************************************
	 *	Private Function: clearSlide
	 *
	 *  Clears a slide from the display executing the disappearCSS
	 *  transition
	 *
	 *	Arguments:
	 *
	 *		chInner:	The chain to be used to clear the slide
	 *		imgLast:	The slide to be cleared
	 *		delay:		The period to wait before the transition returns
	 *
	 *  Returns: void
	 *
	 **********************************************************************/

	clearSlide: function(chInner, imgLast, delay)
	{
		if (imgLast != null)
		{
			new EffectSequence( { element: imgLast, transitionCallChain: true, chainDelay: delay, effectsSequence:
			[ { duration:  imgLast.disappearDuration, transition: Fx.Transitions.linear, delay: 0,	css: $merge( { opacity: 0 }, imgLast.disappearCSS ) } 
			]}).startChained(chInner);

			var show = this;

			chInner.chain(function()
			{
				// window.status = 'Removing: ' + imgLast.src;
				imgLast.remove(show.el);

				if (chInner.chains.length > 0 && show.started)
					chInner.callChain();
			});
		}
	},

	/********************************************************************
	 *	Private Function: ClearAll
	 *
	 *	Clears all the slides except the current slide.  Executes the
	 *  disappear transition for each slide being removed.
	 *
	 *	Arguments:
	 *
	 *		ch:		The chain to be used to clear the slides
	 *		img:	The current slide
	 *
	 *  Returns: void
	 *
	 **********************************************************************/

	ClearAll: function(ch, img)
	{
		var show = this;

		ch.chain(function()
		{
			var chInner = new Chain();
			show.el.getChildren().each(function(imgInner, i)
			{
				// Clear all imgs except the current one
				if (imgInner.id == img.id ) return;

				new EffectSequence( { element: imgInner, transitionCallChain: !img.clearAllTogether, chainDelay: 0, effectsSequence:
				[ { duration:  imgInner.disappearDuration, transition: Fx.Transitions.linear,		 delay: 0,	css: $merge( { opacity: 0 }, imgInner.disappearCSS ) } 
				]}).startChained(chInner);

				chInner.chain(function()
				{
					// window.status = 'Removing: ' + imgInner.src;

					imgInner.remove(show.el);

					if (chInner.chains.length > 0 && show.started)
						chInner.callChain(); 
				});

			});

			chInner.callChain();

			if (ch.chains.length > 0 && show.started)
				ch.callChain();
		});
	},

	/********************************************************************
	 *	Private Function: dump
	 *
	 *	  Dumps the content of an associative array
	 *
	 *	Arguments:
	 *
	 *	  prefix	- A name so the user can identify the source content
	 *	  toDump	- The object to be dumped
	 *
	 *  Returns:
	 *
	 *	  a css definition of the changing attributes
	 *
	 **********************************************************************/

	dump: function(prefix, todump)
	{
		var result = "";

		result += prefix + ': ';
		for(var key in todump)
		{
			result += key + ': ' + todump[key] + '; ';
		}

		return result;
	}

});
