// Slideshow
var Slideshow = Class.create({
	initialize: function(id, slides, options) {
		if (!$(id)) return;
		
		this.id = id;
		
		this.options = Object.extend({
			className: 'slideshow',
			transition: 'fade',				// Transition Types = fade | slide-right | slide-left | slide-top | slide-bottom | follow-right | follow-left | random
			layout: '',						// Image Display Type = zoom | scale | fill | [empty = center image and retain size]
			displayDuration: 6, 			// Duration to display image in seconds
			transitionDuration: .4,			// Duration in which to perform transition
			loop: true,						// Loops transition back to start
			
			/* Dimensions in pixels */
			width: 500,
			height: 400,
			
			/* Description height */
			descriptionHeight: 80,
			
			/* Start Slideshow Automatically */
			autoStart: true,
			
			/* Functions */
			onTransition: function() { },	// Called after transition begins
			onNext: function() { },			// Called after next slide chosen
			onPrevious: function() { }		// Called after previous slide chosen
		}, options || {});

		/* Bind Option Functions */
		this.options.onTransition.bind(this);
		this.options.onNext.bind(this);
		this.options.onPrevious.bind(this);
		
		/* Register Variables */
		this.previousSlide = null;
		this.currentSlide = null;
		this.currentFrame = null;
		this.timer = null;
		this.paused = false;
		
		// Set Control Array
		this.controls = new Array();
		
		/* Apply settings to current DIV */
		$(this.id).addClassName(this.options.className+"_enclosure");
		
		/* Set Enclosure Dimensions */
		$(this.id).setStyle({ width: this.options.width+"px", height: this.options.height+"px" });
		 
		/* Create Slide Frames Screen */
		var el = document.createElement("div");
			el.id = this.id+"_frame0";
			el.className = this.options.className+"_frame";
			
			/* Append First Frame */
			$(this.id).appendChild(el);
			$(el.id).setStyle({ width: this.options.width+"px", height: this.options.height+"px" });
			
			/* Attach click handler to first frame */
			Event.observe(el.id, "click", this.click.bindAsEventListener(this));
			
			/* Create Second Frame */
			el = document.createElement("div");
			el.id = this.id+"_frame1";
			el.className = this.options.className+"_frame";

			/* Append Second Frame */
			$(this.id).appendChild(el);
			$(el.id).setStyle({ width: this.options.width+"px", height: this.options.height+"px" });
			
			/* Attach click handler to first frame */
			Event.observe(el.id, "click", this.click.bindAsEventListener(this));
			
			/* Create Description Element */
			el = document.createElement("div");
			el.id = this.id+"_description";
			el.className = this.options.className+"_description";
			
			/* Append Description Element */
			$(this.id).appendChild(el);
			$(el.id).setStyle({ width: this.options.width+"px", height: this.options.descriptionHeight+"px", display: "none" });
			
		/* Create Transition Screen */
		var trans = document.createElement("div");
			trans.id = this.id+"_transition";
			trans.className = this.options.className+"_transition";
			
			/* Append Transition */
			$(this.id).appendChild(trans);
			$(trans.id).setStyle({ width: this.options.width+"px", height: this.options.height+"px", display: "none" });
			
		/* Load Slides */
		this.load(slides);
		
		/* Start Slideshow */
		if (this.options.autoStart) this.start();
	},
	
	load: function(slides) {
		var v;
		
		/* Assign Slides to object */
		this.slides = slides;
		
		/* Verify Slide Array Information --  [{ image: '', description: '', display: /zoom|scale|fill|[empty]/, transition: /fade|slide-right|slide-left|slide-top|slide-bottom|random/, displayDuration: /time_to_display/, onDisplay: function(self) {}, onHide: function(self) {} }] */ 
		
		for (var i = 0; i < this.slides.length; i++) {
			if (typeof(this.slides[i].image) === 'undefined') {
				/* Remove Invalid Element */
				this.slides.splice(i, 1);
				
				/* Reset counter to new current index */
				i--;
			} else {
				/* Load image into cache */
				v = this.slides[i].image;
				
				this.slides[i].image = document.createElement("img"); // new Image();
				this.slides[i].image.src = v;
				this.slides[i].image.id = this.id+'_slide_'+parseInt(i, 10);
				
				/* Verify Information */ 
				if (typeof(this.slides[i].display) === 'undefined') {
					this.slides[i].display = this.options.layout;
				}
				if (typeof(this.slides[i].transition) === 'undefined') {
					this.slides[i].transition = this.options.transition;
				}
				if (typeof(this.slides[i].displayDuration) === 'undefined') {
					this.slides[i].displayDuration = this.options.displayDuration;
				}
				if (typeof(this.slides[i].onDisplay) === 'undefined') {
					this.slides[i].onDisplay = function(self) {}
				}
				if (typeof(this.slides[i].onHide) === 'undefined') {
					this.slides[i].onHide = function(self) {}
				}
				if (typeof(this.slides[i].onClick) === 'undefined') {
					this.slides[i].onClick = function(self) {}
				}
			}
		}
	},
	
	_isLoaded: function(slide) {
		if (typeof(slide) != 'object' && slide > 0 && slide < this.slides.length) {
			slide = this.slides[slide];
		} else if (typeof(slide) == 'undefined') {
			return false;
		}
		
		return slide.image.complete;
	},
	
	_transitionFrame: function(display) {
		if (display) {
			/* Show Transition Loading Frame */
			if ($(this.id+"_transition").getStyle("display") !== 'block') {
				$(this.id+"_transition").setStyle({ top: "0px", left: "0px", width: this.options.width+"px", height: this.options.height+"px", zIndex: 400 });
				Effect.Appear(this.id+"_transition", { duration: .2 });
			}
		} else {
			/* Hide Transition Loading Frame */
			if ($(this.id+"_transition").getStyle("display") !== 'none') {
				Effect.Fade(this.id+"_transition", { duration: .2 });
			}
		}
	},
	
	_description: function(display, description) {
		if (display) {
			/* Add Description Text */
			$(this.id+"_description").innerHTML = description;
			
			/* Show Description Element */
			if ($(this.id+"_description").getStyle("display") !== 'block') {
				$(this.id+"_description").setStyle({ top: (this.options.height+1)+"px", left: "0px", width: this.options.width+"px", height: this.options.descriptionHeight+"px", zIndex: 300, display: 'none' });
				Effect.Appear(this.id+"_description", { duration: .2 });
				new Effect.Move(this.id+"_description", { x: 0, y: this.options.height-this.options.descriptionHeight, mode: 'absolute', duration: .2 });
			}
		} else {
			/* Hide Description Element */
			if ($(this.id+"_description").getStyle("display") !== 'none') {
				Effect.Fade(this.id+"_description", { duration: .2 });
				new Effect.Move(this.id+"_description", { x: 0, y: this.options.height+1, mode: 'absolute', duration: .2 });				
			}
		}
	},

	attachControls: function(controls) {
		controls.setParent(this);
		controls.create();
		
		this.controls.push(controls);
	},
	
	transition: function() {
		/* Assign slide */
		var slide = this.slides[this.currentSlide];
		var activeFrame = this.currentFrame;
		var hiddenFrame = this.currentFrame == 1 ? 0 : 1;
		
		/* Check that image is loaded and ready -- if not, display transition frame */
		if (!this._isLoaded(slide)) {
			/* Display Transition Frame because it's taking too long */
			this._transitionFrame(true);
			
			/* Set Transition to try again after short delay */
			this.transition.bind(this).delay(this.options.transitionDuration); 			
			return;
		} else {
			this._transitionFrame(false);
		}
		
		/* Hide Description Element */
		this._description(false);
		
		/* Calculate aspect ratio */
		var aspect = Math.round((slide.image.width / slide.image.height)*1000)/1000;

		/* Clear Hidden Frame */
		$(this.id+"_frame"+hiddenFrame).update("");
		
		/* Load next image into hidden frame */
		var newImage = slide.image;
		$(this.id+"_frame"+hiddenFrame).appendChild(newImage);
		
		/* Size Hidden Image */
		switch (slide.display) {
			case 'zoom':
				/* Zoom image to fill frame */
				if (slide.image.width >= this.options.width) { //slide.image.height) {
					var newHeight = this.options.height;
					var newWidth = Math.round(this.options.height * aspect);
				} else {
					var newWidth = this.options.width;
					var newHeight = Math.round(this.options.width / aspect);
				}
				break;
			case 'scale':
				/* Scale image to fit within frame */
				if (slide.image.width >= this.options.width) { //slide.image.height) {
					var newWidth = this.options.width;
					var newHeight = Math.round(this.options.width / aspect);
				} else {
					var newHeight = this.options.height;
					var newWidth = Math.round(this.options.height * aspect);
				}

				break;
			case 'fill':
				var newWidth = this.options.width;
				var newHeight = this.options.height;
				break;
			default:
				newWidth = slide.image.width;
				newHeight = slide.image.height;
				break;
		}
		
		/* Set Position of Image */
		var top = Math.round((this.options.height - newHeight) / 2);
		var left = Math.round((this.options.width - newWidth) / 2);
			$(newImage.id).setStyle({ top: top+"px", left: left+"px", width: newWidth+"px", height: newHeight+"px"});
		
		/* Do Transition */
		var trans = slide.transition;
			
		// Check if Transition is Random
		if (slide.transition == 'random') {
			trans = Math.floor(Math.random()*5);
		}
		
		// Default Fade
		var do_fade = true;
			
		switch (trans) {
			case 0:
			case 'fade':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ top: "0px", left: "0px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				break;
			case 1:
			case 'slide-right':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ top: "0px", left: (this.options.width+1)+"px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				
				new Effect.Move(this.id+"_frame"+hiddenFrame, { x: 0, y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				new Effect.Move(this.id+"_frame"+activeFrame, { x: (this.options.width*2), y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				break;
			case 2:
			case 'slide-left':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ top: "0px", right: ((-1*this.options.width)+1)+"px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				
				new Effect.Move(this.id+"_frame"+hiddenFrame, { x: 0, y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				new Effect.Move(this.id+"_frame"+activeFrame, { x: (this.options.width*-1), y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				break;
			case 3:
			case 'slide-top':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ left: "0px", top: (this.options.height*-1)+"px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				
				new Effect.Move(this.id+"_frame"+hiddenFrame, { x: 0, y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				new Effect.Move(this.id+"_frame"+activeFrame, { x: 0, y: (this.options.height*-1), mode: 'absolute', duration: this.options.transitionDuration });				
				break;
			case 4:
			case 'slide-bottom':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ left: "0px", top: (this.options.height*2)+"px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				
				new Effect.Move(this.id+"_frame"+hiddenFrame, { x: 0, y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				new Effect.Move(this.id+"_frame"+activeFrame, { x: 0, y: (this.options.height*2), mode: 'absolute', duration: this.options.transitionDuration });				
				break;
			case 5:
			case 'follow-right':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ top: "0px", left: (this.options.width*-1)+"px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				
				new Effect.Move(this.id+"_frame"+hiddenFrame, { x: 0, y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				new Effect.Move(this.id+"_frame"+activeFrame, { x: (this.options.width*2), y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				break;
			case 6:
			case 'follow-left':
				/* Position hidden frame for transition */
				$(this.id+"_frame"+hiddenFrame).setStyle({ top: "0px", left: ((this.options.width*2)+1)+"px", zIndex: 200 });
				$(this.id+"_frame"+activeFrame).setStyle({ zIndex: 100 });
				
				new Effect.Move(this.id+"_frame"+hiddenFrame, { x: 0, y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				new Effect.Move(this.id+"_frame"+activeFrame, { x: (this.options.width*-1), y: 0, mode: 'absolute', duration: this.options.transitionDuration });				
				break;
		}
		
		/* Appear/Fade respective Frames */
		if (do_fade == true) {
			Effect.Appear(this.id+"_frame"+hiddenFrame, { duration: this.options.transitionDuration });
			Effect.Fade(this.id+"_frame"+activeFrame, { duration: this.options.transitionDuration });
		} else {
			$(this.id+"_frame"+hiddenFrame).setStyle({ display: 'block' });
			$(this.id+"_frame"+activeFrame).setStyle({ display: 'block' });
		}
		
		/* Call Slides onDisplay Function */
		slide.onDisplay(this);
		if (this.previousslide != null) this.slides[this.previousSlide].onHide(this);
		
		// Call Control onTransition Function
		if (this.controls.length > 0) {
			for (var c = 0; c < this.controls.length; c++) {
				this.controls[c].onTransition();
			}
		}
		
		/* Show Description Frame if slide has description */
		if (typeof(slide.description) !== 'undefined' && !slide.description.blank()) this._description.bind(this, true, slide.description).delay(this.options.transitionDuration);
		
		/* Set New Current Frame Variables */
		this.currentFrame = hiddenFrame;
				
		/* Run User Function */
		this.options.onTransition();
		
		/* Create Delay for Next Slide */
		if (!this.paused) {
			if (this.options.loop || (!this.options.loop && this.currentSlide < this.slides.length-1)) {
				this.timer = this.next.bind(this).delay(slide.displayDuration);
			}
		}
	},
	
	start: function(slide) {
		if (this.currentSlide !== null) {
			this.next();
		} else {
			if (typeof(slide) === 'undefined') slide = 0;
			
			/* Setup Defaults */
			this.currentSlide = slide;		
			this.currentFrame = 0;
	
			/* Hide Both Frames */
			$(this.id+"_frame0").setStyle({ display: 'none' });
			$(this.id+"_frame1").setStyle({ display: 'none' });
			
			this.transition();
		}
		
		this.paused = false;
	},
	
	end: function() {
		this.pause();
		
		this.currentSlide = null;

		/* Hide Loading Frame */
		this._transitionFrame(false);

		/* Hide Both Frames */
		Effect.Fade(this.id+"_frame0", { duration: this.options.transitionDuration });
		Effect.Fade(this.id+"_frame1", { duration: this.options.transitionDuration });
	},
	
	pause: function() {
		clearTimeout(this.timer);
		
		this.paused = true;
	},
	
	next: function() {
		clearTimeout(this.timer);

		this.previousSlide = this.currentSlide;
		this.currentSlide = parseInt(this.currentSlide, 10) + 1 > this.slides.length-1 ? (this.options.loop ? 0 : this.slides.length-1) : parseInt(this.currentSlide, 10) + 1;
		 
		/* Run User Function */
		this.options.onNext();
		
		this.transition();
	},
	
	previous: function() {
		clearTimeout(this.timer);

		this.previousSlide = this.currentSlide;
		this.currentSlide = this.currentSlide - 1 >= 0 ? this.currentSlide - 1 : (this.options.loop ? this.slides.length-1 : 0);
		
		/* Run User Function */		
		this.options.onPrevious();
		
		this.transition();
	},
	
	show: function(which) {
		clearTimeout(this.timer);
		
		this.previousSlide = this.currentSlide;
		this.currentSlide = which;

		this.transition();
	},
	
	click: function() {
		/* Determine which slide is showing and do click function associated with that slide */
		var slide = this.slides[this.currentSlide];

		// Make Click Call
		slide.onClick()
	}
	
});

// Control Button Base Class for use with SlideShow Controls Class
var ControlButton = Class.create({
	initialize: function(id, options) {
		this.id = id;
		
		this.parent = null;
		
		this.options = Object.extend({
			image: null,
			hover: null,
			text: 'Button',
			
			/* Functions */
			onCreate: function(self) { },	// Called on Image Create
			onClick: function(self) { },	// Called on Image Click
			onHover: function(self) { },	// Called on Image Hover
			onBlur: function(self) { }		// Called on Image Blur
		}, options || {});

	},
	
	setParent: function(parent) {
		this.parent = parent;
	},
	
	draw: function() {
		var img;
		
		// Create DIV
		this.el = document.createElement("span");
		this.el.id = this.id;
		this.el.style.display = 'inline';
			
		// Create Image
		if (this.image !== null) {
			img = document.createElement("img");
			img.id = this.id+"_image";
			img.src = this.options.image;
			img.alt = this.options.text;
			img.align = "absmiddle";
			
			// Add Image Element to DIV
			this.el.appendChild(img);
		} else {
			this.el.innerHTML = this.options.text;
		}
		
		// Return Element
		return this.el;
	},
	
	hover: function() {
		if (this.options.hover !== null) $(this.id+"_image").src = this.options.hover;
		
		this.options.onHover(this);
	},
	
	blur: function() {
		if (this.options.hover !== null) $(this.id+"_image").src = this.options.image;
		
		this.options.onBlur(this);
	},
	
	click: function() {
		this.options.onClick(this);
	},
	
	create: function() {
		this.options.onCreate(this);
		
		// Set Style
		$(this.id).className = this.parent.options.className+"_button";

		// Attach Events to Element
		Event.observe(this.id, "click", this.click.bindAsEventListener(this));
		Event.observe(this.id, "mouseover", this.hover.bindAsEventListener(this));
		Event.observe(this.id, "mouseout", this.blur.bindAsEventListener(this));
	}
	
});

// Controls for Slideshow Class
var SlideControls = Class.create({
	initialize: function(id, buttons, options) {
		this.id = id;
		this.parent = null;
		this.buttons = buttons;

		this.options = Object.extend({
			className: 'slideshow_controls',
			
			/* Dimensions in pixels */
			width: false,
			height: 63,
			
			// Attach Controls top or bottom?
			attachment: 'bottom',	// top, bottom
			
			onCreate: function(self) { },
			onTransition: function(self) { }
		}, options || {});

		/* Bind Option Functions */
		this.options.onCreate.bind(this);
		this.options.onTransition.bind(this);
		
		if ($(id)) {
			this.draw(false);
		}
	},
	
	setParent: function(parent) {
		this.parent = parent;
	},
	
	draw: function(changeClass) {
		if (typeof(changeClass) == 'undefined' || changeClass == true) $(this.id).className = this.options.className;
		
		// Build Buttons
		if (this.buttons != null && this.buttons != false) {
			for (var i = 0; i < this.buttons.length; i++) {
				// Set Parent of Button to this
				this.buttons[i].setParent(this);
				
				// Attach to DOM
				$(this.id).appendChild(this.buttons[i].draw());
			}
	
			// Call Button Creation Function after attached to DOM
			for (var i = 0; i < this.buttons.length; i++) {
				this.buttons[i].create();
			}
		}
	},
	
	start: function() {
		this.parent.start();
	},
	
	end: function() {
		this.parent.end();
	},
	
	pause: function() {
		this.parent.pause();
	},
	
	next: function() {
		this.parent.next();
	},
	
	previous: function() {
		this.parent.previous();
	},
	
	show: function(slide) {
		this.parent.show(slide);
	},
	
	create: function() {
		if (!$(this.id) && $(this.parent.id)) {
			// Get Parent Dimensions
			var width = $(this.parent.id).getDimensions();
			
			width = this.options.width == false ? width.width : this.options.width;
			
			// Create Control Container
			var el = document.createElement("div");
				el.id = this.id;
				el.style.width = width+"px";
				
			// Attach Controls Below Parent Slide
			if (this.options.attachment.toLowerCase() == 'bottom') {
				$(this.parent.id).insert({ after: el });
			} else {
				$(this.parent.id).insert({ before: el });
			}
				
			
			this.draw();
		}
		
		this.options.onCreate(this);
	},
	
	onTransition: function() {
		this.options.onTransition(this);
	}
	
});

// Frame Counter
var CounterControls = Class.create(SlideControls, {
	initialize: function($super, id, options) {
		options = Object.extend({
			className: 'slideshow_counter_controls'
		}, options || {});
		
		$super(id, null, options);
	},
	
	create: function($super) {
		$super();
		
		var el;
		
		// Do Slide Frames
		for (var i = 0; i < this.parent.slides.length; i++) {
			el = document.createElement("div");
				el.id = this.id+"_frame_"+i.toString();
				el.className = this.options.className+"_unselected";
				el.innerHTML = (i+1).toString();
				el.style.display = 'inline-block';
				
				$(this.id).appendChild(el);
		}
		
		// Setup Frame Events
		for (i = 0; i < this.parent.slides.length; i++) {
			Event.observe(this.id+"_frame_"+i.toString(), "click", this.click.bindAsEventListener(this));
		}

	},
	
	onTransition: function($super) {
		$super();
		
		// Determine Slide Number
		var slide = this.parent.currentSlide;

		// Reset all frames and set current frame to selected
		for (var i = 0; i < this.parent.slides.length; i++) {
			if (i != slide) {
				$(this.id+"_frame_"+i.toString()).className = this.options.className+"_unselected";
			} else {
				$(this.id+"_frame_"+i.toString()).className = this.options.className+"_selected";
			}
		}
		
	},
	
	click: function(e) {
		// Determine Frame Number
		var slide = Event.element(e);
			slide = slide.id.substring(slide.id.indexOf('_frame_')+7);
			
		// Transition to proper frame
		this.show(slide);
	}
});

// Buttons for Slideshow Control
var buttons = {play: new ControlButton('play',	{image: './images/slideshow/controls/play.png', hover: './images/slideshow/controls/play_hover.png', onClick: function(self) { self.parent.start(); if ($('pause')) { $('pause').setStyle({ display: 'inline'}); $('play').hide(); } else if ($('end')) { $('end').setStyle({ display: 'inline'}); $('play').hide(); } }, onCreate: function(self) { if ($('pause') && self.parent.parent.options.autoStart) { $('play').hide(); } else if ($('end') && self.parent.parent.options.autoStart) { $('end').hide(); } } }),
			   pause: new ControlButton('pause',	{image: './images/slideshow/controls/pause.png', hover: './images/slideshow/controls/pause_hover.png', onClick: function(self) { self.parent.pause(); if ($('play')) { $('play').setStyle({ display: 'inline'}); $('pause').hide(); } }, onCreate: function(self) { if ($('play') && !self.parent.parent.options.autoStart) { $('pause').hide(); } } }),
			   next: new ControlButton('next',	{image: './images/slideshow/controls/forward.png', hover: './images/slideshow/controls/forward_hover.png', onClick: function(self) { self.parent.next(); } }),
			   prev: new ControlButton('prev',	{image: './images/slideshow/controls/rewind.png', hover: './images/slideshow/controls/rewind_hover.png', onClick: function(self) { self.parent.previous(); } }),
			   end:	new ControlButton('end',	{image: './images/slideshow/controls/stop.png', hover: './images/slideshow/controls/stop_hover.png', onClick: function(self) { self.parent.end(); if ($('play')) { $('play').setStyle({ display: 'inline'}); if (!$('pause')) {$('end').hide(); } else { $('pause').hide(); } } }, onCreate: function(self) { if ($('play') && !$('pause') && !self.parent.parent.options.autoStart) { $('end').hide(); } } }),
			   spacer: new ControlButton('spacer', {image: './images/slideshow/controls/blank.png' })
};
