/*!

Copyright © 2008, Riada International Pty. Ltd.

http://www.riada.com

*/

//
//  TastyEffect-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyEffect = new Class(
	{
	initialize: function(options)
		{
		this.options = $merge(
			{
			pause: 2000,
			speed: 0,			// p/s (pixels per second)
			duration: 2000,		// Only used if speed = 0
			transition: 'linear',
			ease: 'easeOut',
			alignX: 1,
			alignY: 1,
			offsetX: 0,
			offsetY: 0,
			opacity: 1,
			order: 0,
			scale:1,
			start:0,
			delay:0
			}, options || {});
			
		this.changeZOrder = true;
		this.changeWidth = true;
		this.changeHeight = true;
		this.fx = null;
		this.startTimer = null;
		
		if (this.options.transition == 'linear')
			this.transition = Fx.Transitions.linear;
		else
			this.transition = Fx.Transitions[this.options.transition][this.options.ease];
		},
	
	setup: function(controller, block)
		{
		this.controller = controller;
		this.block = block;
		},
	
	observe: function()
		{
		if (this.fx)
			this.fx.addEvent('complete', this.onComplete.bindWithEvent(this));
		},
	
	onComplete: function()
		{
		this.block.onComplete(this);
		},
		
	start: function()
		{
//		if (this.changeZOrder)
//			this.block.moveToFront(this.controller);
		},
		
	stop: function()
		{
		if (this.fx)
			{
			this.fx.cancel();
			this.fx = null;
			}
		
		if (this.startTimer && this.startTimer >= 0)
			window.clearTimeout(this.startTimer);

		this.startTimer = null;
		},
		
	calcDuration: function(dist, speed)
		{
		return Math.round((dist / Math.max(.001, speed)) * 1000);
		},
		
	duration2D: function(duration, speed, x1, y1, x2, y2)
		{
		if (speed > 0)
			duration = this.calcDuration(Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)), speed);
		
		// Give the browser a chance to update if duration is too small
//		return Math.max(duration, 20);
		return duration;
		},

	duration1D: function(duration, speed, x1, x2)
		{
		if (speed > 0)
			duration = this.calcDuration(Math.abs(x2 - x1), speed);
		
		return Math.max(duration, 20);
		}
	});

//
//  TastyBlock-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyBlock = new Class(
	{
	initialize: function(options, effects)
		{
		this.options = $merge(
			{
			alignX: 0,
			alignY: 1,
			offsetX: 0,
			offsetY: 0,
			autoSize: 1,
			width: -2,
			height: -1,
			wrap: 1,
			url: "",
			target: 0,
			}, options || {});
		
		this.effects = effects;
		this.previousClip = null;
this.isScaling = false;		
		},
	
	setup: function(controller, el)
		{
		this.controller = controller;
		this.el = el;

		var wrap = this.options.wrap ? 'normal' : 'nowrap';
		
		el.setStyles({
			'position' : 'absolute',
			'white-space': wrap,
			'overflow' : 'hidden'
			});

		el.addEvent('click', this.click.bindWithEvent(this));

		this.originalSize = {width: el.getScrollSize().x, height: el.getScrollSize().y};
		this.originalFontSize = el.getStyle('fontSize').toFloat();

		// Get a copy of the original paragraph font sizes
		var paras = el.getElements('p');
		this.originalFontSizeArray = [];
		
		for (var i = 0; i < paras.length; i++)
			this.originalFontSizeArray.push(paras[i].getStyle('fontSize').toFloat());
		
		this.effects.each(function(effect, index)
			{
			effect.setup(this.controller, this);
			}, this);
		},
		
	size: function(options)
		{
		var size = {};
		
		if (options.autoSize)
			{
			if (this.el.match('img'))
				{
				if (this.originalSize.width > this.controller.el.clientWidth || 
					this.originalSize.height > this.controller.el.clientHeight)
					{
					// ratios
					var wr = this.originalSize.width / this.controller.el.clientWidth;
					var hr = this.originalSize.height / this.controller.el.clientHeight;
	
					if (wr > hr) // landscape
						{
						size.width = this.controller.el.clientWidth;
						size.height = this.originalSize.height / wr;
						}
					else // portrait
						{
						size.height = this.controller.el.clientHeight;
						size.width = this.originalSize.width / hr;
						}
					}
				else
					{
					size.width = this.originalSize.width;
					size.height = this.originalSize.height;
					}
				}
			else
				{
				if (options.wrap)
					{
					size.width = this.controller.el.clientWidth;

					if (this.originalSize.height < this.controller.el.clientHeight)
						size.height = this.controller.el.clientHeight;
					else
						size.height = this.originalSize.height;
					}
				else
					{
					size.height = this.controller.el.clientHeight;
					
					if (this.originalSize.width < this.controller.el.clientWidth)
						size.width = this.controller.el.clientWidth;
					else
						size.width = this.originalSize.width;
					}
				}
				
			return size;
			}
			
		if (options.width == -1)		// Natural width
			size.width = this.originalSize.width;
		else if (options.width == -2)	// Container with
			size.width = this.controller.el.clientWidth;
		else if (options.width == -3)	// More than project
			{
			if (this.originalSize.width < this.controller.el.clientWidth)
				size.width = this.controller.el.clientWidth;
			else
				size.width = this.originalSize.width;
			}
		else
			size.width = options.width;	// Explicit width
			
		if (options.height == -1)
			size.height = this.originalSize.height;
		else if (options.height == -2)
			size.height = this.controller.el.clientHeight;
		else if (options.height == -3)	// More than project
			{
			if (this.originalSize.height < this.controller.el.clientHeight)
				size.height = this.controller.el.clientHeight;
			else
				size.height = this.originalSize.height;
			}
		else
			size.height = options.height;

		return size;
		},
		
	position: function(options, useCurrentSize)
		{
		var size;

		if (useCurrentSize)
			{
			if (this.isScaling)
				size = {width: this.scaleWidth, height: this.scaleHeight};
			else
				size = {width: this.el.getScrollSize().x, height: this.el.getScrollSize().y};
			}
		else
			size = this.size(this.options);

		return {
			width: size.width,
			height: size.height,
			x: this.controller.align(options.alignX, options.offsetX, this.controller.el.clientWidth, size.width),
			y: this.controller.align(options.alignY, options.offsetY, this.controller.el.clientHeight, size.height)
			};
		},
		
	start: function()
		{
		// Initial position
		var position = this.position(this.options, false);

		// *** TODO Should this be conditional? ie a parameter?
		this.sendToFront();

		this.previousClip = [0, position.width, position.height, 0];
		
		this.el.setStyles(
			{
			'opacity': 1,
			'left': position.x,
			'top': position.y,
			'width': position.width,
			'height': position.height,
			'fontSize': this.originalFontSize,
			'visibility': 'visible',
//			'clip': this.previousClip
			'clip': 'auto'
			});

	// Resize all child paragraphs
		var paras = this.el.getElements('p');
		
		for (var i = 0; i < paras.length; i++)
			paras[i].setStyle('fontSize', this.originalFontSizeArray[i]);

		// Start the first effect
//		this.effects[0].startTimer = this.startEffect.delay(Math.max(this.effects[0].options.delay, 20), this, this.effects[0]);
		this.effects[0].startTimer = this.fixTimer(this.startEffect.delay(this.effects[0].options.delay, this, this.effects[0]));
		},

	fixTimer: function(timer)
		{
		if (timer)
			return timer;
		
		// Timer was returned undefined, so we pass something back other than undefined
		return -1;
		},
		
	stop: function()
		{
		for (index = 0; index < this.effects.length; index++)
			this.effects[index].stop();
		},
		
	startEffect: function(effect)
		{
		var index = this.effects.indexOf(effect);

		effect.start();
		effect.observe();

		// Start the next effect concurrently?
		if (index + 1 < this.effects.length)
			{
			var nextEffect = this.effects[index + 1];
			
			if (nextEffect.options.start == 1)
//				nextEffect.startTimer = this.startEffect.delay(Math.max(nextEffect.options.delay, 20), this, nextEffect);
				nextEffect.startTimer = this.fixTimer(this.startEffect.delay(nextEffect.options.delay, this, nextEffect));
			}
		},
	
	// Should be moved into effect
	onComplete: function(effect)
		{
		var index = this.effects.indexOf(effect);

		effect.startTimer = null;
	
		// Start the next effect?
		if (index + 1 < this.effects.length)
			{
			var nextEffect = this.effects[index + 1];

			if (nextEffect.options.start == 0 && nextEffect.startTimer == null)
				{
//				nextEffect.startTimer = this.startEffect.delay(Math.max(nextEffect.options.delay, 20), this, nextEffect);
				nextEffect.startTimer = this.fixTimer(this.startEffect.delay(nextEffect.options.delay, this, nextEffect));

				return;
				}
			};
			
		// Have all effects finished?
		for (index = 0; index < this.effects.length; index++)
			// Still going
			if (this.effects[index].startTimer)
				return;

		// Next block
		this.controller.next();
		},
		
	click: function()
		{
		if (this.options.url != null && this.options.url != "")
			switch (this.options.target)
				{
				// Current window
				case 0 :
					window.location.href = this.options.url;
					break;
					
				// New window
				case 1 :
					window.open(this.options.url, 'tastyfx', '')
					break;
				}
		},
	
	reorder: function()
		{
		this.controller.zOrder.each(function(block, index)
			{
			block.el.setStyle('z-index', index);
			});
		},
		
	sendToFront: function()
		{
		this.controller.zOrder.erase(this);
		this.controller.zOrder.push(this);

		this.reorder();
		},
		
	sendToBack: function()
		{
		this.controller.zOrder.erase(this);
		this.controller.zOrder.unshift(this);

		this.reorder();
		},
	
	moveZOrder: function(delta)
		{
		var index = this.controller.zOrder.indexOf(this);
		var index2, temp_item;
	
		// Make sure the index is within the array bounds
		if (index < 0 || index >= this.controller.zOrder.length)
			return;

		// Make sure the target index is within the array bounds
		index2 = index + delta;
		
		if (index2 < 0 || index2 >= this.controller.zOrder.length || index2 == index)
			return;

		// Move the elements in the array
		temp_item = this.controller.zOrder[index2];
		this.controller.zOrder[index2] = this.controller.zOrder[index];
		this.controller.zOrder[index] = temp_item;			

		this.reorder();
		}
	});

//
//  TastyMoveTo-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyMoveTo = new Class(
	{
	Extends: TastyEffect, 
	
	start: function()
		{
		this.parent();

		var position = this.block.position(this.options, true);

		var duration = this.duration2D(this.options.duration, this.options.speed, position.x, position.y, 
			this.block.el.getStyle('left').toInt(), this.block.el.getStyle('top').toInt());

		this.fx = new Fx.Morph(this.block.el, 
			{
			duration: duration,
			transition: this.transition
			}).start({'left':position.x, 'top':position.y});
		}
	});

//
//  TastyReveal-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyReveal = new Class(
	{
	Extends: TastyEffect,
	
/*	initialize: function(options)
		{
		this.parent(options);
		
		this.changeZOrder = false;
		},
*/		
	start: function()
		{
		this.parent();
		
		var options = {};
		var els = [];
		
		var maxDuration = 0;
		var index = 0;
		var i;
		
		// Move all others that are currently displayed
		for (var i = 0; i < this.controller.zOrder.length; i++)
			{
			var otherBlock = this.controller.zOrder[i];

			// Don't modify this block
			if (otherBlock != this.block)
				{
				var bc = otherBlock.el.getCoordinates();
				var cc = this.controller.el.getCoordinates();
				
				if (bc.left >= cc.left && bc.right <= cc.right &&
					bc.top >= cc.top && bc.bottom <= cc.bottom)
					{
					els.push(otherBlock.el);
				
					var position = otherBlock.position(this.options, true);

					maxDuration = Math.max(this.options.duration, maxDuration);
					
					options[index.toString()] = 
						{
						'left': position.x,
						'top': position.y
						};
					
					index++;
					}
				}
			};
			
		this.fx = new Fx.Elements(els,
			{
			duration: maxDuration,
			transition: this.transition
			}).start(options);
		}
	});

//
//  TastyClip-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyClip = new Class(
	{
	Extends: TastyEffect,
	
	initialize: function(options)
		{
		options = $merge(
			{
			alignX1: -1,
			alignX2: 1,
			alignY1: -1,
			alignY2: 1,
			offsetX1: 0,
			offsetX2: 0,
			offsetY1: 0,
			offsetY2: 0
			}, options || {});

		this.parent(options);
		},
	
	// TODO use controller align function
	clipAlign: function(alignment, size)
		{
		switch (alignment)
			{
			case -1 :
				return 0;
				
			case 0 :
				return size / 2;
			
			default :
			case 1 :
				return size;
			}
		},
		
	start: function()
		{
		this.parent();
		
		// *** TODO Do we need to take into account the scale? ie calling position(..., true) instead?
		var size = this.block.size(this.block.options);
		
		var to = [
			this.clipAlign(this.options.alignY1, size.height) + this.options.offsetY1,
			this.clipAlign(this.options.alignX2, size.width) + this.options.offsetX2,
			this.clipAlign(this.options.alignY2, size.height) + this.options.offsetY2,
			this.clipAlign(this.options.alignX1, size.width) + this.options.offsetX1
			];
			
		this.fx = new Fx.Morph(this.block.el, 
			{
			duration: this.options.duration,
			transition: this.transition
			}).start({'clip': [this.block.previousClip, to]});

		this.block.previousClip = to;
		}
	});

//
//  TastyOpacity-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyOpacity = new Class(
	{
	Extends: TastyEffect, 
	
	start: function()
		{
		this.parent();
	
		this.fx = new Fx.Morph(this.block.el, 
			{
			duration: this.options.duration,
			transition: this.transition
			}).start({'opacity': this.options.opacity});
		}
	});

//
//  TastyScale-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyScale = new Class(
	{
	Extends: TastyEffect, 
	
	start: function()
		{
		this.parent();

		var width = this.block.el.getScrollSize().x * this.options.scale;
		var height = this.block.el.getScrollSize().y * this.options.scale;

		var x = this.controller.align(this.options.alignX, this.options.offsetX, this.controller.el.clientWidth, width);
		var y = this.controller.align(this.options.alignY, this.options.offsetY, this.controller.el.clientHeight, height);

		var currentFontSize = this.block.el.getStyle('fontSize').toInt();

this.block.isScaling = true;
this.block.scaleWidth = width;
this.block.scaleHeight = height;

		this.fx = new Fx.Morph(this.block.el, 
			{
			duration: this.options.duration,
			transition: this.transition
			}).start({
				'fontSize': currentFontSize * this.options.scale,
				'left':x, 
				'top':y,
				'width': width,
				'height': height
				});

		// Resize all child paragraphs
		var paras = this.block.el.getElements('p');
		var paraOptions = {};
		
		for (var i = 0; i < paras.length; i++)
			{
			var currentFontSize = paras[i].getStyle('fontSize').toFloat();
			var option = {
				'fontSize': this.block.originalFontSizeArray[i] * this.options.scale
				};

			paraOptions[i] = option;
			}
	
		var fx2 = new Fx.Elements(paras,
			{
			duration: this.options.duration,
			transition: this.transition
			}).start(paraOptions);
		},
		
	onComplete: function()
		{
		this.block.isScaling = false;

		this.parent();
		}
	});

//
//  TastyPause-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyPause = new Class(
	{
	Extends: TastyEffect, 
	
	initialize: function(options)
		{
		this.parent(options);
		
		this.pauseTimer = null;
		},
		
	start: function()
		{
		this.parent();
		
		this.pauseTimer = this.onComplete.delay(this.options.pause, this);
		},
		
	stop: function()
		{
		this.parent();
		
		if (this.pauseTimer)
			window.clearTimeout(this.pauseTimer);
		}
	});

//
//  TastyZOrder-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyZOrder = new Class(
	{
	Extends: TastyEffect, 
	
	initialize: function(options)
		{
		this.parent(options);
		
		this.pauseTimer = null;
		},
		
	start: function()
		{
		this.parent();

		switch (this.options.order)
			{
			case 0 :	// Move to Front
				this.block.sendToFront();
				break;
				
			case 1 :	// Move to Back
				this.block.sendToBack();
				break;
				
			case 2 :	// Send Forwards
				this.block.moveZOrder(1);
				break;
				
			case 3 :	// Send Backwards
				this.block.moveZOrder(-1);
				break;
			}

		this.pauseTimer = this.onComplete.delay(20, this);
		},
		
	stop: function()
		{
		this.parent();
		
		if (this.pauseTimer)
			window.clearTimeout(this.pauseTimer);
		}
	});

//
//  TastyCaption-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyCaption = new Class(
	{
	initialize: function(controller, type, style)
		{
		this.el = new Element('div', 
			{
			'styles': $merge(style, {
				'position': 'absolute', 
				'visibility':'visible',
				'overflow':'hidden',
				'width':controller.el.clientWidth,
				'opacity': 0.7,
				'top': -1000,
				'left': 0,
				'margin': 0,
				'padding': 0,
				'z-index':200})
			});
		
		this.controller = controller;
		this.type = type;
		
		this.el.inject(controller.el);
		},
		
	show: function(block)
		{
		var showCaption = function(b)
			{
			var text, startY, endY;
			
			var title = b.el.get('title');
			var caption = b.el.get('alt');
			
			if (title && caption)
				text = title + '<br />' + caption;
			else
				text = caption || title || '';

			this.el.set({'opacity': 0, 'html': text});

			switch (this.type)
				{
				default :
				case 1 :		// Top
					startY = -this.el.getScrollSize().y;
					endY = 0;
					break;
					
				case 2 :		// Bottom
					startY = this.controller.el.clientHeight;
					endY = this.controller.el.clientHeight - this.el.getScrollSize().y;
					break;
					
				case 3 :		// Top fade
					startY = endY = 0;
					break;
					
				case 4 :		// Bottom fade
					startY = endY = this.controller.el.clientHeight - this.el.getScrollSize().y;
					break;
				}
				
			this.el.morph({'top': [startY, endY], 'opacity': 0.7, 'link': 'chain'});
			
			}.pass(block, this);
			
		var startY = 0, opacity = 0;
		
		switch (this.type)
			{
			default :
			case 1 :		// Top
				startY = -this.el.getScrollSize().y;
				opacity = 0.7;
				break;
				
			case 2 :		// Bottom
				startY = this.controller.el.clientHeight;
				opacity = 0.7;
				break;
				
			case 3 :		// Top fade
				startY = 0;
				break;
				
			case 4 :		// Bottom fade
				startY = this.controller.el.clientHeight - this.el.getScrollSize().y;
				break;
			}

		this.el.get('morph').cancel().start({'top': startY, 'opacity': opacity, 'link': 'chain'}).chain(showCaption);
		}
		
	});
//
//  TastyFX-mootools.m
//  TastyFX
//
//  Copyright 2008 Riada International Pty. Ltd.. All rights reserved.
//

TastyFX = new Class(
	{
	initialize: function(container, options, blocks, overlays)
		{
		this.options = $merge(
			{
			captionType: 0,
			captionStyle: {
				fontFamily: 'Arial',
				fontSize: '10pt',
				textAlign: 'center',
				color: '#ffffff',
				backgroundColor: '#000000'}
			}, options || {});
		

		this.el = $(container);
		this.el.setStyles({
			position:'relative', 
			overflow:'hidden'
			});

		this.el.addEvent('mouseenter', this.mouseEnter.bindWithEvent(this));
		this.el.addEvent('mouseleave', this.mouseExit.bindWithEvent(this));

		var elements = this.el.getChildren();

		// Make sure theres not more blocks than elements
		if (blocks.length > elements.length)
			block = blocks.slice(0, elements.length);

		// Set up blocks
		for (var i = 0; i < blocks.length; i++)
			blocks[i].setup(this, elements[i]);

		this.blocks = blocks;

		// Setup overlays
		for (var i = 0; i < overlays.length; i++)
			overlays[i].setup(this);
			
		this.overlays = overlays;
			
		// TastyFX has captions
		if (this.options.captionType)
			this.caption = new TastyCaption(this, this.options.captionType, this.options.captionStyle);

		// Make a copy of blocks, so we can keep the z-indices
		this.zOrder = $A(blocks);
		
		this.currentBlockIndex = 0;
		this.play();
		},

	mouseEnter: function()
		{
		for (var i = 0; i < this.overlays.length; i++)
			this.overlays[i].show();
		},
		
	mouseExit: function()
		{
		for (var i = 0; i < this.overlays.length; i++)
			this.overlays[i].hide();
		},

	go: function(index)
		{
		this.pause();

		this.currentBlockIndex = index;

		if (this.caption)
			this.caption.show(this.blocks[index]);
		
		this.blocks[index].start();
		},
		
	first: function()
		{
		this.go(0);
		},
	
	previous: function()
		{
		this.go(Math.max(this.currentBlockIndex - 1, 0));
		},
		
	play: function()
		{
		this.go(this.currentBlockIndex);
		},
		
	pause: function()
		{
		for (var i = 0; i < this.blocks.length; i++)
			this.blocks[i].stop();
		},
		
	next: function()
		{
		this.currentBlockIndex++;
		
		if (this.currentBlockIndex >= this.blocks.length)
			this.currentBlockIndex = 0;
			
		this.go(this.currentBlockIndex);
		},
		
	last: function()
		{
		this.go(this.blocks.length - 1);
		},

	align: function(alignment, offset, controllerSize, size)
		{
		var value = 0;

		switch (alignment)
			{
			case 0 :	// Above or Far Left
				value = -size;
				break;
			
			case 1 :	// Top or Left
				break;
				
			case 2 :	// Middle or Center
				value = (controllerSize - size) / 2;
				break;
				
			case 3 :	// Bottom or Right
				value = controllerSize - size;
				break;
				
			case 4 :	// Below or Far Right
				value = controllerSize;
				break;
				
			case 5 :	// Random Inside
				value = this.align(Math.floor(Math.random() * 3) + 1, offset, controllerSize, size);
				break;
				
			case 6 :	// Random Outside
				value = Math.floor(Math.random() * 2);
				value = this.align(value == 0 ? value : 4, offset, controllerSize, size);
				break;
			}
		
		return value + offset;
		}
	});
