// effects.js - version 0.1 - Spry Pre-Release 1.5 Preview
//
// Copyright (c) 2006. Adobe Systems Incorporated.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//   * Neither the name of Adobe Systems Incorporated nor the names of its
//     contributors may be used to endorse or promote products derived from this
//     software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

///////////////////////////////////////////////////////////////////////////////////////
// 
//  This file is used in an advanced demo to examplify the Spry Effects functionalities 
//  and interoperability between them. To read more details about different Spry Effects
// 	and their detailed options please see our detailed samples:
//
// 	http://labs.adobe.com/technologies/spry/samples/#effects
//
// 	We had to write the following custom objects and functions to achieve our demo goal:
//  
//  Spry.Effect.FadeBlind 
//			- A custom cluster effect which group toghether a Fade and a Blind Effect
//
//  Spry.Effect.FadeSlide 
// 			- A custom cluster effect which group toghether a Fade and a Blind Effect
//
// 	Observer 
//      - A custom observer attached to every effect that will run in page. This observer 
// 			was designed to run any effect a second time in the oposite direction and 
// 			revert at the end any CSS changes that where changed by the effect on the target
// 			element
//
// 	runEffect()
// 			- A custom function that will prepare and run a given effect on a target element
//
//  ExampleHelpText()
// 			- A custom function designed to change the content text of an element.
//  
///////////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////
//
// 	Global Variables
//
////////////////////////////////////////////////////

// list of effects already run to be reused
var effects = {};
// latest effect ran
var prevEffect = false;
// CSS initial properties for the elements on which we apply the effects
var initialElements = [];
// list of style properties to be monitored
var saveStyle = ['position', 'width', 'height', 'opacity', 'filter', 'top', 'left', 'backgroundColor', 'visibility', 'display'];

////////////////////////////////////////////////////
//
// 	Cluster Effects
//
////////////////////////////////////////////////////

/* 
 * FadeBlind 
 * 		Custom Cluster effect that fade in/out and blind in/out simultanous an element
 * 		by running in parallel the Fade() and Blind() predefined clusters
 */

Spry.Effect.FadeBlind = function(element, options)
{
	Spry.Effect.Cluster.call(this, options);
	
	this.name = 'FadeBlind';
	var duration = 1000;
	var doToggle = false;
	var from = 100;
	var to = 0;

	if (options)
	{
		if (options.duration) duration = options.duration;
		if (options.toggle) doToggle = options.toggle;
		if (options.from) from = options.from;
		if (options.to) to = options.to;
	}

	var options = {duration: duration, from: from + '%', to: to + '%', toggle: doToggle};
	var blind = new Spry.Effect.Blind(element, options); 
	this.addParallelEffect(blind);

	var options = {duration: duration, from: from, to: to, toggle: doToggle};
	var fade = new Spry.Effect.Fade(element, options); 
	this.addParallelEffect(fade);
};

Spry.Effect.FadeBlind.prototype = new Spry.Effect.Cluster();
Spry.Effect.FadeBlind.prototype.constructor = Spry.Effect.FadeBlind; 

/* 
 * FadeSlide 
 * 		Custom Cluster effect that fade in/out and slide simultanous an element
 * 		by running in parallel the Fade() and Slide() predefined clusters
 */

Spry.Effect.FadeSlide = function(element, options)
{
	Spry.Effect.Cluster.call(this, options);
	
	this.name = 'FadeSlide';
	var duration = 1000;
	var doToggle = false;
	var from = 100;
	var to = 0;

	if (options)
	{
		if (options.duration) duration = options.duration;
		if (options.toggle) doToggle = options.toggle;
		if (options.from) from = options.from;
		if (options.to) to = options.to;
	}

	var options = {duration: duration, from: from + '%', to: to + '%', toggle: doToggle};
	var slide = new Spry.Effect.Slide(element, options);
	this.addParallelEffect(slide);

	var options = {duration: duration, from: from, to: to, toggle: doToggle};
	var fade = new Spry.Effect.Fade(element, options);
	this.addParallelEffect(fade);
};

Spry.Effect.FadeSlide.prototype = new Spry.Effect.Cluster();
Spry.Effect.FadeSlide.prototype.constructor = Spry.Effect.FadeSlide;

///////////////////////////////////////////////////////////////
//
// Generic Observer
//
// 		The observer will save the initial element state, 
// 		restore the effect and the element to their original 
// 		states when the effect finished or canceled.
//
///////////////////////////////////////////////////////////////

var Observer = {};

/*
 * 	Observer.onPreEffect(obj)
 * 		Before running an effect forward the initial CSS values are saved.
 *    We will use later these when the animation will finish or is canceled 
 * 		to restore the animated element to be ready for the next effect.
 *    This function is automatically called by the effect.
 *  Parameters:
 * 		obj - the running effect that calls this function
 */
Observer.onPreEffect = function(obj){
	if (obj.direction && obj.direction == Spry.forwards){
		saveElement(obj.element);
		if (obj.name == 'Slide' || obj.name == 'FadeSlide'){
			saveElement(document.getElementById('content_box'));
		}
	}
};

/*
 * 	Observer.onCancel(obj)
 * 		When an effect is canceled this function will restore the element CSS.
 * 		Also we toggle the effect so the next time will run to go forward again.
 *    This function is automatically called by the effect.
 *  Parameters:
 * 		obj - the running effect that calls this function
 */
Observer.onCancel = function(obj){
	if (obj.direction == Spry.forwards){
		obj.doToggle();
	}
	
	restoreElement(obj.element);

	if (obj.name == 'Slide' || obj.name == 'FadeSlide'){
		var el = document.getElementById('content_box')
		restoreElement(el);
	}
};

/*
 * 	Observer.onPostEffect(obj)
 * 		When a forward effect finish the effect is restarted to toggle the effect. 
 * 		We will use a small timeout to make sure the effect properly finish the 
 * 		animation in forward direction.
 * 		After the second run will restore the element CSS
 *    This function is automatically called by the effect.
 *  Parameters:
 * 		obj - the running effect that calls this function
 */
Observer.onPostEffect = function(obj){
	if (obj.direction == Spry.forwards)
		setTimeout(function(){obj.start()}, 150);
	else
		restoreElement(obj.element);
};

/////////////////////////////////////////////////
//
// Utilities functions
//
/////////////////////////////////////////////////

/* 
 * ExampleHelpText
 * 		change the content text of the text_pane div with the new one received
 * Parameters:
 * 		helpText - the new text to be displayed into the text_pane element
 * 
 */
function ExampleHelpText(helpText)
{
	document.getElementById("text_pane").innerHTML='<p>'+helpText+'</p>';
};

/* 
 * ReloadDocument()
 * 		reload the current page from the server
 * 
 */
function ReloadDocument()
{
	window.location.reload(true);
};

/* 
 * saveElement(el)
 * 		Save into the global array of 'initialElements' some CSS properties 
 * 		of the given element that where altered by the animation running.
 * Parameters:
 *		el - the DOM element for which to save the CSS properties
 */
var saveElement = function(el){
	if (!initialElements[el.id])
	{
		initialElements[el.id] = {};
		for (var i = 0; i < saveStyle.length; i++)
		{
			initialElements[el.id][saveStyle[i]] = Spry.Effect.getStyleProp(el, saveStyle[i]);
		}
	}
};

/* 
 * restoreElement(el)
 * 		Restore from the global array 'initialElements' some CSS properties 
 * 		of the given element to prepare it for the next effect to run.
 * Parameters:
 *		el - the DOM element for which to restore the CSS properties
 */
var restoreElement = function(el){
	for (var i = 0; i < saveStyle.length; i++)
		el.style[saveStyle[i]] = initialElements[el.id][saveStyle[i]];
};

/*
 * runEffect()
 *    This is the dispatcher that will instantiate, if not already done, 
 * 		the given 'effect' with a list of 'options' to run on a given target 'element'.
 *
 *  	The observer defined above will also be attached to the effect to 
 * 		initially save the unaltered 'element' properties, automatically restart 
 *    the animation in backward direction and restore the saved properties at the end.
 *
 * 		The 'effect' is than started and the text from the text_pane is changed
 * 		with the 'helpText'
 *
 * 		The "new Spry.Effect[effect]" is a generic way of initializing a given 'effect'.
 * 		The Spry samples are describing for each effect what is the specific code
 * 		to be included in page and the complete list of supported options. An online version
 * 		of the Spry Effects samples could be accessed here:
 *
 *    http://labs.adobe.com/technologies/spry/samples/#effects
 *
 * Parameters:
 * 		effect - the name of the effect to run
 * 		element - the element id from page to run this effect on
 * 		options - the options necessary for the effect to run
 * 		helptext - the new status page to be displayed
 */
var runEffect = function(effect, element, options, helptext){
	if (prevEffect && effects[prevEffect].isRunning){
		effects[prevEffect].cancel();
		setTimeout(function(){runEffect(effect, element, options, helptext)}, 150);
		return;
	}

	if (!effects[effect]){
		effects[effect] = new Spry.Effect[effect](element, options);
		if (effect != 'Highlight' && effect != 'Shake' && effect != 'Pulsate')
			effects[effect].addObserver(Observer);
	}

	effects[effect].start();

	if (helptext)
		ExampleHelpText(helptext);

	prevEffect = effect;
};

