var CL_SHOWCASE = null;
var CL_SHOWCASE_TOTAL = 1;

var PR_SHOWCASE = null;
var PR_SHOWCASE_TOTAL = 2;

document.observe("dom:loaded", function() {
	//homepage showcase
	if ($("home-showcase") !== null) {
		HP_SHOWCASE = new showcase($("home-showcase"), {
			'total': CL_SHOWCASE_TOTAL,
			'hud_offset': 96
		});
	}
	
	//project showcase
	if ($("project-showcase") !== null) {
		PR_SHOWCASE = new showcase($("project-showcase"), {
			'total': PR_SHOWCASE_TOTAL,
			'request_url': '/release/includes/php/project-showcase.php',
			'get_url': '/work/project/.../image/{index}/',
			'budge': [
				'secondary'
			]
		});
	}
}, this);

showcase = Class.create({
	initialize: function(showcase, options) {
		var a, classes, anchor;
		
		this.options = options || {};
		this.showcase = showcase;
		this.showcase_wrapper = showcase.down("div.showcase-wrapper");
		this.current_item = this.showcase_wrapper.down("div.showcase-item");
		this.nav_anims = {};
		this.showcase_index = 1;
		this.request = {
			'active': false,
			'loading': false,
			'zooming': false
		};
		this.item_cache = {};
		
		//get dimensional stats for restoring
		this.options.stats = {
			width: this.showcase.offsetWidth,
			height: this.showcase.offsetHeight
		};
		
		this.options = ob_set_defaults(this.options, {
			'total': 1,
			'request_url': "/release/includes/php/showcase.php",
			'get_url': "/showcase/{index}/",
			'transition_time': 0.6,
			'transition_delay': 0,
			'notify_timeout': 0.1,
			'timer_url': "/release/images/loader-pink-white.gif",
			'zoom_width': 940,
			'zoom_height': 590,
			'hud_offset': 0
		});
		
		//enable animation on nav buttons
		this.nav_prev = this.showcase.down("p.prev a");
		this.nav_next = this.showcase.down("p.next a");
		
		if (this.options.total <= 1) {
			//disable navigation
			this.nav_prev.hide();
			this.nav_next.hide();
		}
		
		//previous button
		this.nav_prev.observe(
			"mouseover", function(event) {
				this.nav_over(event);
				this.nav_prev.over = true;
			}.bind(this)
		).observe(
			"mouseout", function(event) {
				this.nav_out(event);
				this.nav_prev.over = false;
			}.bind(this)
		).observe(
			"click", this.prev.bind(this)
		);
		
		//adjust previous icon
		icon = this.nav_prev.down("span.icon");
		icon_offset = ((this.nav_prev.up().offsetHeight / 2) - (icon.offsetHeight / 2) + this.options.hud_offset);
		
		icon.setStyle({
			'top': icon_offset + "px"
		});
		
		//next button
		this.nav_next.observe(
			"mouseover", function(event) {
				this.nav_over(event);
				this.nav_next.over = true;
			}.bind(this)
		).observe(
			"mouseout", function(event) {
				this.nav_out(event);
				this.nav_next.over = false;
			}.bind(this)
		).observe(
			"click", this.next.bind(this)
		);
		
		//adjust next icon
		icon = this.nav_next.down("span.icon");
		
		icon.setStyle({
			'top': icon_offset + "px"
		});
		
		//update dimension stats
		this.options.stats['icon_top'] = icon_offset;
		
		//zoom method
		anchor = this.current_item.down("a.zoom[href != '']");
		
		if (anchor !== undefined) {
			anchor.observe("click", this.zoom.bind(this));
			
			//insert zoom hud
			this.zoom_hud = new Element("span", {
				'class': 'zoom-hud'
			});
			this.showcase.insert(this.zoom_hud);
			
			this.showcase.observe("mouseover", function(event) {
				if (event.findElement().up("a.zoom")) {
					this.zoom_hud.addClassName("zoom-hud-active");
				} else {
					this.zoom_hud.removeClassName("zoom-hud-active");
				}
			}.bind(this));
			
			this.showcase.observe("mouseout", function(event) {
				this.zoom_hud.removeClassName("zoom-hud-active");
			}.bind(this));
			
			this.showcase.observe("mousemove", this.zoomer_track.bind(this));
		}
		
		this.nav_dots_wrapper = new Element("div", {
			'class': 'nav-dots'
		}).setStyle({
			'visibility': 'hidden',
			'display': 'block'
		});
		
		if (this.options.total > 1) {
			//navigation/status dots
			this.nav_dots = [];
		
			for (a = 0; a < this.options.total; a++) {
				classes = Array();
				
				if (a == (this.options.total -1)) {
					classes.push("last");
				}
				
				if (a == 0) {
					classes.push("active first");
				}
				
				this.nav_dots.push(new Element("a", {
					'href': '#',
					'title': 'Go to showcase ' + (a + 1),
					'class': (classes.length > 0 ? classes.join(" ") : null)
				}).observe(
					"click", this.dot_nav.bind(this)
				).insert(
					new Element("span")
				));
				
				this.nav_dots_wrapper.insert(this.nav_dots[a]);
			}
		}
			
		this.showcase.insert(this.nav_dots_wrapper);
		
		if (this.options.total > 1) {
			this.nav_dots_wrapper.setStyle({
				'visibility': 'visible',
				'left': ((this.showcase.offsetWidth / 2) - (this.nav_dots_wrapper.offsetWidth / 2)) + 'px'
			});
		}
		
		//loading timers/notifications
		this.timers = {};
		this.timers.request =  null;
		this.timers.load = null;
		
		this.load_notifier = new Element("div", {
			'class': 'ajax-loader'
		}).setStyle({
			'display': 'none'
		}).insert(new Element("img", {
			"src": this.options.timer_url
		}));
		
		this.showcase.insert(this.load_notifier);
	},
	
	next: function(event) {
		/*show next showcase*/
		event.stop();
		
		if (this.showcase_index == this.options.total) {
			this.request_showcase(1, "next");
		} else {
			this.request_showcase(this.showcase_index + 1, "next");
		}
	},
	
	prev: function(event) {
		/*show previous showcase*/
		event.stop();
		
		if (this.showcase_index == 1) {
			this.request_showcase(this.options.total, "prev");
		} else {
			this.request_showcase(this.showcase_index - 1, "prev");
		}
	},
	
	dot_nav: function(event) {
		var element, pos;
		
		event.stop();
		
		element = event.findElement("a");
		pos = element.previousSiblings().length + 1;
		
		if (pos > this.showcase_index) {
			this.request_showcase(pos, "next");
		} else if (pos < this.showcase_index) {
			this.request_showcase(pos, "prev");
		}
	},
	
	request_showcase: function(index, direction) {
		/*request a showcase by index*/
		if (this.request.active === false) {
			this.request.direction = direction;
			this.request.active = true;
			this.request.loading = true;
			this.showcase_index = index;
			
			//set load notification timer
			this.timers.load = window.setTimeout(function() {
				this.load_notify(true);
			}.bind(this), (this.options.notify_timeout * 1000));
			
			if (this.item_cache[this.showcase_index] !== undefined) {
				//use cached transport data
				this.preload_showcase(this.item_cache[this.showcase_index], direction);
			} else {
				//send server request
				var request = new Ajax.Request(this.options.request_url + "?index=" + index, {
					method: 'get',
					onSuccess: function(transport) {
						//pre-load showcase data before display
						this.preload_showcase(transport, direction);
					}.bind(this),
					onFailure: this.get_showcase.bind(this)
				});
			}
		} else {
			//load throttling
			return false;
		}
	},
	
	get_showcase: function(index) {
		/*fallback function for getting showcase via GET url*/
		index = index || this.showcase_index;
		//window.location.href = this.options.get_url.replace(/\{index\}/i, this.showcase_index);
	},
	
	preload_showcase: function(transport, direction, loaded) {
		/*preload the showcase item depending on mime type*/
		var item, response = transport.responseJSON, item_element, item_id, settings;
		
		this.request.transport = transport;
			
		if (loaded === true) {
			//redundancy code for sell-callback via less intellegent mime methods
			this.display_showcase();
		} else {
			if (response === null || response.content === null) {
				this.get_showcase();
				return false;
			}
			
			if (this.item_cache[this.showcase_index] === undefined || this.item_cache[this.showcase_index] === null) {
				//insert transport data into cache
				this.item_cache[this.showcase_index] = transport;
			}
			
			//update showcase total
			this.options.total = parseInt(response.total, 10);
			
			//create item content
			item = new Element("div", {
				'class': 'showcase-item'
			});
			
			//displays a showcase retrieved with ajax
			if (direction == "next") {
				//insert content after current showcase, slide left
				this.request.travel_x = -this.showcase.offsetWidth;
				
				this.showcase_wrapper.insert(item);
			} else if (direction == "prev") {
				//insert content before current showcase, slide right
				this.request.travel_x = 0;
				
				this.showcase_wrapper.setStyle({
					'left': '-' + this.showcase.offsetWidth + 'px'
				}).insert({
					top: item
				});
			}
			
			//set up content element
			item_element = this.media_element(response.content);
			
			if (item_element === null) {
				this.get_showcase();
				return false;
			}
			
			//insert completed elements into item wrapper
			item.insert(item_element);
			
			//set up appropriate callback for loading data
			switch (response.content.mime) {
				case "application/x-shockwave-flash":
					//initialize swf (callback from within swf)
					response.content.params.movie = response.content.media;
					
					//add wrapper time delay
					if (response.content.params.flashvars !== undefined) {
						response.content.params.flashvars += "&timedelay=" + (this.options.transition_time * 1000);
					} else {
						response.content.params.flashvars = "timedelay=" + (this.options.transition_time * 1000);
					}
					
					item_id = item_element.identify();
					
					callback = function(swf_load) {
						if (swf_load.status == flensed.checkplayer.SWF_LOADED) {
							this.display_showcase();
						} else if (swf_load.status == flensed.checkplayer.SWF_FAILED &&
							response.content.media_alt !== undefined) {
							//flash failed to load - display alternate media
							this.display_showcase();
						} else if (swf_load.status == flensed.checkplayer.SWF_FAILED) {
							//flash failed to load - no alt media - use manual method
							this.get_showcase();
							return false;
						}
					}.bind(this)
					
					WS_SWF.create(item_element, response.content.params, callback, true);
					break;
					
				case "image/jpeg":
				case "image/jpg":
				case "image/gif":
				case "image/png":
					//load an image - detect whether the showcase is zoomed in
					if (this.showcase.hasClassName("zoom") &&
						(response.content.classname == "zoom" && response.content.url)) {
						//load hires image, and lowres image
						this.item_cache.img_hi = new Image();
						
						this.item_cache.img_hi.onload = function() {
							this.item_cache.img = new Image();
							
							this.item_cache.img.onload = function() {
								this.display_showcase();
							}.bind(this);
							
							this.item_cache.img.src = response.content.media;
						}.bind(this);
						
						this.item_cache.img_hi.src = response.content.url;
					} else {
						//load lowres image
						this.item_cache.img = new Image();
						
						this.item_cache.img.onload = function() {
							this.display_showcase();
						}.bind(this);
						
						this.item_cache.img.src = response.content.media;
					}
					break;
					
				default:
					//attempt to load via GET
					this.get_showcase();
					return false;
			}
		}
	},
	
	display_showcase: function(display) {
		/*displays the showcase returned by request_showcase*/
		this.request.loading = false;
		
		//remove notifier
		this.load_notify(false);
		
		if (this.request.transport !== null) {
			//update dot nav
			for (a = 0; a < this.nav_dots.length; a++) {
				this.nav_dots[a].removeClassName("active").blur();
			}
			
			this.nav_dots[this.showcase_index - 1].addClassName("active");
			
			//animate wrapper left/right
			if (display || this.options.transition_delay === 0) {
				//transition has passed or is disabled
				var effect = new Effect.Move(this.showcase_wrapper, {
					'x': this.request.travel_x,
					'y': 0,
					'mode': 'absolute',
					duration: this.options.transition_time,
					afterFinish: function() {
						//remove old showcase item
						this.request.active = false;
						this.current_item.remove();
						this.current_item = this.showcase_wrapper.down(".showcase-item");
						
						//re-set showcase to start position
						this.showcase_wrapper.setStyle({
							'left': '0px'
						});
					}.bind(this)
				});
			
				//wipe transport data for sanity
				this.request.transport = null;
			} else {
				//re-run function after delay
				window.setTimeout(function() {
					this.display_showcase(true);
				}.bind(this), (this.options.transition_delay * 1000));
			}
		}
	},
	
	load_notify: function(display) {
		/*display a loading notification*/
		window.clearTimeout(this.timers.load);
		this.timers.load = null;
			
		if (display && (this.request.loading || this.request.zooming)) {
			//position and show notifier
			this.load_notifier.setStyle({
				'visibility': 'hidden',
				'display': 'block'
			});
			
			this.load_notifier.setStyle({
				'left': (this.showcase.offsetWidth / 2) - (this.load_notifier.offsetWidth / 2) + "px",
				'top': ((this.showcase.offsetHeight / 2) - (this.load_notifier.offsetHeight / 2) +  + this.options.hud_offset) + "px",
				'display': 'none',
				'visibility': 'visible'
			});
			
			this.load_notifier.show();
		} else {
			//hide load notifier
			window.setTimeout(function() {
				/*notifier is hidden after a timeout to avoid a race condition.
				this can be caused because load_notifer(.., true) is called by
				a seperate thread*/
				this.load_notifier.hide();
			}.bind(this), 500);
		}
	},
	
	media_element: function(content_node) {
		/*returns an element node based on the passed media type*/
		var element, anchor;
		
		switch (content_node.mime) {
			case "application/x-shockwave-flash":
				element = new Element("div", {
					'class': 'swfobject'
				});
				break;
				
			case "image/jpeg":
			case "image/jpg":
			case "image/gif":
			case "image/png":
				if (this.showcase.hasClassName("zoom") &&
					(content_node.classname == "zoom" && content_node.url)) {
					//showcase is currently zoomed in and hires source exists
					element = new Element("img", {
						'old_src': content_node.media,
						'src': content_node.url
					});
				} else {
					//no hires source to use
					if (this.showcase.hasClassName("zoom")) {
						//unzoom showcase
						this.zoom(null, 1);
					}
					
					element = new Element("img", {
						'src': content_node.media
					});
				}
				
				if (content_node.media_alt) {
					if (content_node.media_alt.mime == "text/plain") {
						element.writeAttribute("alt", content_node.media_alt.media);
					}
				}
				
				if (content_node.url !== undefined) {
					anchor = new Element("a", {
						'href': content_node.url,
						'class': (content_node.classname !== undefined ? content_node.classname : null)
					});
					
					if (content_node.classname == "zoom" && content_node.url) {
						anchor.observe("click", this.zoom.bind(this));
					}
					
					element = anchor.insert(element);
				}
				
				break;
		}
		
		if (content_node.media_alt !== undefined) {
			element.insert(this.media_element(content_node.media_alt));
		}
		
		return element;
	},
	
	zoomer_track: function(event) {
		var offset, pointer;
		
		offset = this.showcase.cumulativeOffset();
		pointer = event.pointer();
		
		this.zoom_hud.setStyle({
			'left': (pointer.x - offset[0]) - (this.zoom_hud.offsetWidth + 2) + 'px',
			'top': (pointer.y - offset[1]) - (this.zoom_hud.offsetHeight + 2) + 'px'
		});
	},
	
	zoom: function(event, process) {
		/*toggles the zoom status of the showcase frame*/
		var budge_items = [], image_url, cacher, img, anchor;
				
		if (event !== null && event !== undefined) {
			event.stop();
		}
		
		image_url = this.current_item.down("a.zoom").readAttribute("href");
		img = this.current_item.down("a.zoom").down("img");
		
		if ((this.request.active || this.request.zooming) &&
			(process === undefined || process === null)) {
			return false;
		}
		
		this.request.zooming = true;
		
		if (!this.showcase.hasClassName("zoom")) {
			switch (process) {
				case null:
				case undefined:
					//pre-load new image
					this.load_notify(true);
			
					cacher = new Image();
					cacher.onload = function() {
						//cache callback
						img.writeAttribute("old_src", img.readAttribute("src"));
						img.writeAttribute("src", image_url);
						
						this.zoom(null, 2);
					}.bind(this);
					
					//cache image
					cacher.src = image_url;
					break;
					
				case 2:
					//remove budge elements
					this.load_notify(false);
					
					if (this.options.budge !== undefined && this.options.budge.length > 0) {
						this.options.budge.each(function(item) {
							if ($(item)) {
								budge_items.push(
									new Effect.Fade(item, {
										sync: true
									})
								);
							}
						});
						
						new Effect.Parallel(budge_items, {
							duration: 0.2,
							afterFinish: function() {
								this.zoom(event, 3);
							}.bind(this)
						});
					} else {
						//no budge items - go straight to step 3
						this.zoom(null, 3);
					}
					break;
					
				case 3:
					//animate showcase
					new Effect.Parallel([
						new Effect.Morph(this.showcase, {
							style: {
								'width': this.options.zoom_width + "px",
								'height': this.options.zoom_height + "px"
							},
							sync: true
						}),
						new Effect.Morph(this.current_item, {
							style: {
								'width': this.options.zoom_width + 'px',
								'height': this.options.zoom_height + "px"
							},
							sync: true
						}),
						new Effect.Morph(this.nav_dots_wrapper, {
							style: {
								'left': ((this.options.zoom_width / 2) - (this.nav_dots_wrapper.offsetWidth / 2)) + 'px'
							},
							sync: true
						}),
						new Effect.Morph(this.nav_prev.down("span.icon"), {
							style: {
								'top': ((this.options.zoom_height / 2) - (this.nav_prev.down("span.icon").offsetHeight / 2)) + 'px'
							},
							sync: true
						}),
						new Effect.Morph(this.nav_next.down("span.icon"), {
							style: {
								'top': ((this.options.zoom_height / 2) - (this.nav_next.down("span.icon").offsetHeight / 2)) + 'px'
							},
							sync: true
						})
						], {
							duration: 0.6,
							afterFinish: function() {
								this.showcase.addClassName("zoom");
								this.request.zooming = false;
								this.zoom_hud.addClassName("zoom-hud-zoomed");
							}.bind(this)
						}
					);
					break;
			}
		} else {
			switch (process) {
				case null:
				case undefined:
				case 1:
					new Effect.Parallel([
						new Effect.Morph(this.showcase, {
							style: {
								'width': this.options.stats.width + "px",
								'height': this.options.stats.height + "px"
							},
							sync: true
						}),
						new Effect.Morph(this.current_item, {
							style: {
								'width': this.options.stats.width + "px",
								'height': this.options.stats.height + "px"
							},
							sync: true
						}),
						new Effect.Morph(this.nav_dots_wrapper, {
							style: {
								'left': ((this.options.stats.width / 2) - (this.nav_dots_wrapper.offsetWidth / 2)) + 'px'
							},
							sync: true
						}),
						new Effect.Morph(this.nav_prev.down("span.icon"), {
							style: {
								'top': this.options.stats.icon_top + 'px'
							},
							sync: true
						}),
						new Effect.Morph(this.nav_next.down("span.icon"), {
							style: {
								'top': this.options.stats.icon_top + 'px'
							},
							sync: true
						})
						], {
							duration: 0.3,
							afterFinish: function() {
								this.zoom(null, 2);
							}.bind(this)
						}
					);
					break;
					
				case 2:
					//replace existing budge items
					if (this.options.budge !== undefined && this.options.budge.length > 0) {
						this.options.budge.each(function(item) {
							if ($(item)) {
								budge_items.push(
									new Effect.Appear(item, {
										sync: true
									})
								);
							}
						});
						
						new Effect.Parallel(budge_items, {
							duration: 0.2,
							afterFinish: function() {
								this.showcase.removeClassName("zoom");
								this.request.zooming = false;
								this.zoom_hud.removeClassName("zoom-hud-zoomed");
								
								img.writeAttribute("src", img.readAttribute("old_src"));
							}.bind(this)
						});
					}
					break;
			}
		}
	},
	
	nav_over: function(event, anchor, callback) {
		/*animates a navigation node appearing*/
		var target_height, target_width;
		
		if (anchor === undefined || anchor === null) {
			anchor = event.findElement("a");
			event.stop();
		}
		
		anchor.addClassName("active");
		anchor_id = anchor.identify();
		
		if (this.nav_anims[anchor_id] !== undefined) {
			//cancel previous animations for this object
			this.nav_anims[anchor_id].cancel();
		}
		
		if (callback !== undefined && callback !== null) {
			anim_callback = function() {
				callback();
			}.bind(this);
		} else {
			anim_callback = null;
		}
		
		target_width = 43;
		target_height = 85;
		
		//animate in
		this.nav_anims[anchor_id] = new Effect.Morph(anchor.down("span.icon"), {
			style: {
				'width': target_width + 'px',
				'height': target_height + 'px',
				'top': ((anchor.offsetHeight / 2) - (target_height / 2) + this.options.hud_offset) + "px"
			},
			duration: 0.1,
			afterFinish: anim_callback
		});
	},
	
	nav_out: function(event, anchor, interactive) {
		/*animates a navigation node dissapearing*/
		var target_height, target_width;
		
		interactive = (interactive === undefined) ? true : interactive;	
		anchor = anchor || event.findElement("a");
		event.stop();
		
		var anchor_id = anchor.identify();
		
		if (this.nav_anims[anchor_id] !== undefined) {
			//cancel previous animations for this object
			this.nav_anims[anchor_id].cancel();
		}
		
		target_width = 33;
		target_height = 65;
		
		//animate out
		this.nav_anims[anchor_id] = new Effect.Morph(anchor.down("span.icon"), {
			style: {
				'width': target_width + 'px',
				'height': target_height + 'px',
				'top': ((anchor.offsetHeight / 2) - (target_height / 2) + this.options.hud_offset) + "px"
			},
			duration: 0.5,
			afterFinish: function(effect) {
				effect.element.removeClassName("active");
			}
		});
	}
});
