﻿// Slide.Show, version 1.0
// Copyright © Vertigo Software, Inc.
// This source is subject to the Microsoft Public License (Ms-PL).
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/publiclicense.mspx.
// All other rights reserved.

/// <reference path="SlideShow.js" />

/*******************************************
 * class: SlideShow.ProgressIndicator
 *******************************************/
SlideShow.ProgressIndicator = function(control, parent, xaml)
{
	/// <summary>Provides a base class for progress indicators.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="xaml">The XAML for the control.</param>
	
	SlideShow.ProgressIndicator.base.constructor.call(this, control, parent, xaml);
	
	SlideShow.merge(this.options,
	{
		top: "50%",
		left: "50%",
		width: 40,
		height: 40,
		opacity: 0,
		progressBackground: "#99000000",
		progressForeground: "#99FFFFFF",
		progressBorderColor: "White",
		progressBorderThickness: 2,
		fadeAnimationDuration: 0.3
	});
	
	this.fadeStoryboard = this.root.findName("FadeStoryboard");
	this.fadeAnimation = this.root.findName("FadeAnimation");
	
	this.control.addEventListener("modulesLoad", SlideShow.createDelegate(this, this.onControlModulesLoad));
};

SlideShow.extend(SlideShow.UserControl, SlideShow.ProgressIndicator,
{
	updateProgress: function(progress)
	{
		/// <summary>Updates the progress displayed by the control.</summary>
		/// <param name="progress">A value between 0 and 1 that specifies the current progress.</param>
		
		if (progress == 1)
			this.fadeOut();
		else if (this.root.opacity == 0)
			this.fadeIn();
	},
	
	fadeIn: function()
	{
		/// <summary>Fades the control into view.</summary>
		
		var duration = (1 - this.root.opacity) * this.options.fadeAnimationDuration;
		
		if (duration > 0)
		{
			this.fadeAnimation.to = 1;
			this.fadeAnimation.duration = "0:0:" + duration.toFixed(8);
			this.fadeStoryboard.begin();
		}
	},
	
	fadeOut: function()
	{
		/// <summary>Fades the control out of view.</summary>
		
		var duration = this.root.opacity * this.options.fadeAnimationDuration;
		
		if (duration > 0)
		{
			this.fadeAnimation.to = 0;
			this.fadeAnimation.duration = "0:0:" + duration.toFixed(8);
			this.fadeStoryboard.begin();
		}
	},
	
	onControlModulesLoad: function()
	{
		/// <summary>Handles the event fired when all modules configured for the Slide.Show control are loaded.</summary>
		
		this.slideViewer = this.control.modules["SlideViewer"];
		
		if (!this.slideViewer)
			throw new Error("Expected module missing: SlideViewer");
		
		this.slideViewer.addEventListener("slideLoading", SlideShow.createDelegate(this, this.onSlideLoading));	
		this.slideViewer.addEventListener("downloadProgressChanged", SlideShow.createDelegate(this, this.onSlideDownloadProgressChanged));
	},
	
	onSlideLoading: function(sender, e)
	{
		/// <summary>Resets the progress when the SlideViewer module fires the "slideLoading" event.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		if (e)
			this.updateProgress(0);
	},
	
	onSlideDownloadProgressChanged: function(sender, e)
	{
		/// <summary>Updates the progress when the SlideViewer module fires the "imageDownloadProgressChanged" event.</summary>
		/// <param name="sender">The event source.</param>
		/// <param name="e">The event arguments.</param>
		
		this.updateProgress(e);
	}
});

/*******************************************
 * class: SlideShow.ProgressBar
 *******************************************/
SlideShow.ProgressBar = function(control, parent, options)
{
	/// <summary>Displays a progress bar while images are downloading.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="options">The options for the control.</param>

	var xaml =
		'<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="ProgressBar" Visibility="Collapsed">' +
		'	<Canvas.Resources>' +
		'		<Storyboard x:Name="FadeStoryboard" Storyboard.TargetName="ProgressBar" Storyboard.TargetProperty="Opacity">' +
		'			<DoubleAnimation x:Name="FadeAnimation" />' +
		'		</Storyboard>' +
		'	</Canvas.Resources>' +
		'	<Rectangle x:Name="ProgressBackground" />' +
		'	<Rectangle x:Name="ProgressForeground" />' +
		'</Canvas>';
	
	SlideShow.ProgressBar.base.constructor.call(this, control, parent, xaml);
	
	SlideShow.merge(this.options,
	{
		width: 180,
		height: 4,
		progressForeground: "#CCFFFFFF",
		progressBorderThickness: 0	
	});
	
	this.setOptions(options);
	
	this.maxProgressForegroundWidth = 0;
	this.progressBackground = this.root.findName("ProgressBackground");
	this.progressForeground = this.root.findName("ProgressForeground");
};

SlideShow.extend(SlideShow.ProgressIndicator, SlideShow.ProgressBar,
{
	render: function()
	{
		/// <summary>Renders the control using the current options.</summary>
		
		SlideShow.ProgressBar.base.render.call(this);
		
		// background
		this.progressBackground.fill = this.options.progressBackground;
		this.progressBackground.stroke = this.options.progressBorderColor;
		this.progressBackground.strokeThickness = this.options.progressBorderThickness;
		
		// foreground
		this.progressForeground.fill = this.options.progressForeground;
		this.progressForeground["Canvas.Top"] = this.options.progressBorderThickness;
		this.progressForeground["Canvas.Left"] = this.options.progressBorderThickness;
	},
	
	updateProgress: function(progress)
	{
		/// <summary>Updates the progress displayed by the control.</summary>
		/// <param name="progress">A value between 0 and 1 that specifies the current progress.</param>
		
		SlideShow.ProgressBar.base.updateProgress.call(this, progress);
		this.progressForeground.width = progress * this.maxProgressForegroundWidth;
	},
	
	onSizeChanged: function()
	{
		/// <summary>Handles the event fired when the control is resized.</summary>
		
		SlideShow.ProgressBar.base.onSizeChanged.call(this);
		
		// background
		this.progressBackground.width = this.root.width;
		this.progressBackground.height = this.root.height;
		
		// foreground
		this.progressForeground.width = 0;
		this.progressForeground.height = this.root.height - this.options.progressBorderThickness * 2;
		this.maxProgressForegroundWidth = this.root.width - this.options.progressBorderThickness * 2;
	}	
});

/*******************************************
 * class: SlideShow.ProgressPie
 *******************************************/
SlideShow.ProgressPie = function(control, parent, options)
{
	/// <summary>Displays a progress pie while images are downloading.</summary>
	/// <param name="control">The Slide.Show control.</param>
	/// <param name="parent">The parent control.</param>
	/// <param name="options">The options for the control.</param>
	
	var xaml =
		'<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="ProgressPie" Visibility="Collapsed">' +
		'	<Canvas.Resources>' +
		'		<Storyboard x:Name="FadeStoryboard" Storyboard.TargetName="ProgressPie" Storyboard.TargetProperty="Opacity">' +
		'			<DoubleAnimation x:Name="FadeAnimation" />' +
		'		</Storyboard>' +
		'	</Canvas.Resources>' +
		'	<Ellipse x:Name="ProgressBackground" />' +
		'	<Path x:Name="ProgressForeground" />' +
		'	<Ellipse x:Name="ProgressBorder" />' +
		'</Canvas>';
	
	SlideShow.ProgressPie.base.constructor.call(this, control, parent, xaml);
	
	this.setOptions(options);
	
	this.progressBackground = this.root.findName("ProgressBackground");
	this.progressForeground = this.root.findName("ProgressForeground");
	this.progressBorder = this.root.findName("ProgressBorder");
};

SlideShow.extend(SlideShow.ProgressIndicator, SlideShow.ProgressPie,
{
	render: function()
	{
		/// <summary>Renders the control using the current options.</summary>
		
		SlideShow.ProgressPie.base.render.call(this);
		
		this.progressBackground.fill = this.options.progressBackground;
		this.progressForeground.fill = this.options.progressForeground;
		this.progressBorder.stroke = this.options.progressBorderColor;
		this.progressBorder.strokeThickness = this.options.progressBorderThickness;		
	},
	
	updateProgress: function(progress)
	{
		/// <summary>Updates the progress displayed by the control.</summary>
		/// <param name="progress">A value between 0 and 1 that specifies the current progress.</param>
		
		SlideShow.ProgressPie.base.updateProgress.call(this, progress);

		var radius = this.progressBackground.width / 2;
		var size = SlideShow.formatString("{0},{1}", radius, radius);
		var angle = 2 * Math.PI * progress;
		var direction = (progress > 0.5) ? 1 : 0;
		var startPoint = SlideShow.formatString("0,{0}", -radius);
		var endPoint = (progress < 1) ? SlideShow.formatString("{0},{1}", Math.sin(angle) * radius, Math.cos(angle) * -radius) : SlideShow.formatString("-0.05,{0}", -radius);
		
		this.progressForeground.data = SlideShow.formatString("M {0} A {1} {2} {3} 1 {4} L 0,0", startPoint, size, angle, direction, endPoint);
	},
	
	onSizeChanged: function()
	{
		/// <summary>Handles the event fired when the control is resized.</summary>
		
		SlideShow.ProgressPie.base.onSizeChanged.call(this);
		
		var diameter = Math.min(this.root.width, this.root.height);
		var radius = diameter / 2;
		var top = this.root.height / 2 - radius;
		var left = this.root.width / 2 - radius;
		
		// background
		this.progressBackground.width = diameter;
		this.progressBackground.height = diameter;
		this.progressBackground["Canvas.Top"] = top;
		this.progressBackground["Canvas.Left"] = left;
		
		// foreground
		this.progressForeground["Canvas.Top"] = top + radius;
		this.progressForeground["Canvas.Left"] = left + radius;
		
		// border
		this.progressBorder.width = diameter;
		this.progressBorder.height = diameter;
		this.progressBorder["Canvas.Top"] = top;
		this.progressBorder["Canvas.Left"] = left;
	}	
});