/*
	Class: PopImg
	Author: Kory Sharp
	Last Update: 01/27/2010
	Dependencies: prototype.js, scriptaculous.js?load=effects, builder
	
	Usage: 
		Single Image:
			<a href="fullsize_images_path" title="image caption" rel="popimg">text or thumbnail</a>
		Multiple Images:
			<a href="fullsize_images_path" title="image caption" rel="popimg[gallery name]">text or thumbnail</a>
*/

var PopImg = Class.create({
	images: [], // images in current pop set
	loaded: [], // images that have been preloaded
	heights: [], // store image heights
	widths: [], // store image widths
	speed: .3,  // duration for transitions below
	pos_timer: [],
	locked: false,
	pos: undefined, // index position (from var images) of the current image
	
	initialize: function() {
		// makes sure the keyboard event as well as "this" (PopImg class) are available
		this.key_events = this.key_events.bindAsEventListener(this);
	
		// build out the skeleton of the popimg viewer (overlay and interior)
		var body = $$('body')[0];
		new Insertion.Bottom(body, $(Builder.node('div', { id: 'overlay' })).hide());
		new Insertion.Bottom(body, 
			$(Builder.node('div', { id: 'popimg' }, [
				Builder.node('div', { id: 'popimg_nav' }, [
					Builder.node('a', { href: '#', id: 'popimg_close' }),
					Builder.node('a', { href: '#', id: 'popimg_next' }),
					Builder.node('a', { href: '#', id: 'popimg_previous' })
				]),
				Builder.node('div', { id: 'popimg_image_holder' }, [
					$(Builder.node('img', { id: 'popimg_image' })).hide(),
					Builder.node('div', { id: 'popimg_loading' })
				])
			])).hide()
		);
	
		// generate onclick events for the navigational items		
		$('popimg_previous').observe('click', (function(event) { event.stop(); this.switch_image(this.pos - 1); }).bind(this));
		$('popimg_next').observe('click', (function(event) { event.stop(); this.switch_image(this.pos + 1); }).bind(this));
		$('popimg_close').observe('click', (function(event) { event.stop(); this.close(); }).bind(this));
		$('overlay').observe('click', (function(event) { event.stop(); this.close(); }).bind(this));
		
		// timer to check the position of the image (should be centered)
		Event.observe(window, 'resize', (function(event) {
			event.stop();
			
			$('popimg').setStyle({ 
				top: ((document.viewport.getHeight() - this.heights[this.pos] - 50) / 2) + document.viewport.getScrollOffsets()[1] + 'px',
				left: ((document.viewport.getWidth() - this.widths[this.pos] - 50) / 2) + document.viewport.getScrollOffsets()[0] + 'px'
			});
			
		}).bind(this));
		
		// read the click event for any link containing popimg
		document.observe('click', (function(event){
            var img = event.findElement('a[rel^=popimg]');
            if (img) {
                event.stop();
                this.open(img);
            }
        }).bind(this));
	},
	open: function(img) {
		// set the height of the overlay
		$('overlay').setStyle({ height: this.get_window_height() + "px" });
		// set the left position of the popimg viewer
		$('popimg').setStyle({ 
			left: (document.viewport.getWidth() / 2) - ($('popimg').getWidth() / 2) + 'px',
			top: ((document.viewport.getHeight() - $('popimg').getHeight()) / 2) + document.viewport.getScrollOffsets()[1] + 'px'
		});
				
		// fade in the overlay and the popimg container
		new Effect.Appear('overlay', { 
			from: 0, 
			to: .9, 
			duration: this.speed,
			afterFinish: (function() {
				new Effect.Appear('popimg', { 
					from: 0, 
					to: 1, 
					duration: this.speed,
					afterFinish: (function() {
						this.find_images(img);
						this.enable_keyboard();
					}).bind(this)
				});	
			}).bind(this)
		});
	},
	close: function() {
		$('popimg').hide();
		$('popimg_image').hide();
		this.disable_keyboard();
		new Effect.Fade('overlay', { duration: this.speed });	
	},
	find_images: function(img) {
		this.images = [];
		this.loaded = [];
		this.pos = 0;
		if (img.readAttribute('rel') == 'popimg') {
			this.images.push([img.readAttribute('href'), img.readAttribute('title')]);
			this.loaded.push(false);
		} else {
			$$('a[href][rel="' + img.readAttribute('rel') + '"]').uniq().each((function(img) {
				this.images.push([img.readAttribute('href'), img.readAttribute('title')]);
				this.loaded.push(false);
			}).bind(this));
			for (var i = 0; i < this.images.length; i++ ) {
				if (this.images[i][0] == img.readAttribute('href')) {
					this.pos = i;
					break;
				}
			}
		}
		this.switch_image(this.pos);
	},
	switch_image: function(pos) {
		if ((this.images.length > 1 || !$('popimg_image').visible()) && this.locked == false) {
			// make sure pos is in range
			if (pos < 0) pos = this.images.length - 1;
			else if (pos >= this.images.length) pos = 0;
			this.pos = pos; 
			
			this.locked = true;
			
			new Effect.Fade('popimg_image', {
				duration: this.speed,
				afterFinish: (function() {
					if (!this.loaded[this.pos]) $('popimg_loading').show();
					var preload = new Image();
					preload.onload = (function() {
						new_height = arguments[0].height;
						new_width = arguments[0].width;
						this.loaded[this.pos] = true;
						
						// check to see if the height is larger than the viewport - (padding + controls)
						if (new_height > document.viewport.getHeight() - 100) {
							old_height = new_height;
							new_height = document.viewport.getHeight() - 100;
							new_width = new_width * new_height / old_height;
						}
						this.heights[this.pos] = new_height;
						this.widths[this.pos] = new_width;
						
						this.preload();
						$('popimg_loading').hide();
						
						var new_top = ((document.viewport.getHeight() - this.heights[this.pos] - 25) / 2) + document.viewport.getScrollOffsets()[1];
						var new_left = ((document.viewport.getWidth() - this.widths[this.pos] - 50) / 2) + document.viewport.getScrollOffsets()[0];
						
						new Effect.Morph('popimg', {
							style: 'top: ' + new_top + 'px; left: ' + new_left + 'px',
							duration: .5
						});
						new Effect.Morph('popimg_image_holder', {
							style: 'height: ' + new_height + 'px; width: ' + new_width + 'px',
							duration: .5,
							afterFinish: (function() {
								$('overlay').setStyle({ height: this.get_window_height() + "px" });
								$('popimg_image').src = this.images[this.pos][0];
								$('popimg_image').width = this.widths[this.pos];
								$('popimg_image').height = this.heights[this.pos];
								
								new Effect.Appear('popimg_image', { 
									duration: this.speed,
									afterFinish: (function() {
										this.locked = false;
									}).bind(this)
								});
							}).bind(this)
						});
					}).bind(this, preload);
					preload.src = this.images[this.pos][0];
				}).bind(this)
			});
		}
	},
	preload: function() {
		// preload the previous and next images
		var previous = (this.pos > 0 && !this.loaded[this.pos - 1]) ? this.pos - 1 : this.images.length - 1;
		var back_preload = new Image();
		back_preload.onload = (function() { this.loaded[previous] = true; }).bind(this);
		back_preload.src = this.images[previous][0];
		
		var next = (this.pos < (this.images.length - 1) && !this.loaded[this.pos + 1]) ? this.pos + 1 : 0;
		var next_preload = new Image();
		next_preload.onload = (function() { this.loaded[next] = true; }).bind(this);
		next_preload.src = this.images[next][0];
	},
	enable_keyboard: function() { Event.observe(document, "keydown", this.key_events); },
	disable_keyboard: function() { Event.stopObserving(document, "keydown", this.key_events); },
	key_events: function(event) {
		switch (event.keyCode) {
			// 'b' or left arrow
			case 37:
			case 66:
				this.switch_image(this.pos - 1);
				break;
			// 'n' or right arrow
			case 39:
			case 78:
				this.switch_image(this.pos + 1);
				break;
			// esc, 'x', or 'c'
			case 27:
			case 67:
			case 88:
				this.close();
				break;
			default:
				break;
		}
	},
	get_window_height: function() {
		// retrieve the height of the document including scrollable area
		var document_height, window_height;
		
		if (window.innerHeight && window.scrollMaxY) document_height = window.innerHeight + window.scrollMaxY;
		else if (document.body.scrollHeight > document.body.offsetHeight) document_height = document.body.scrollHeight;
		else document_height = document.body.offsetHeight;
		
		if (self.innerHeight) window_height = self.innerHeight;
		else if (document.documentElement && document.documentElement.clientHeight) window_height = document.documentElement.clientHeight;
		else if (document.body) window_height = document.body.clientHeight;
		
		return (document_height < window_height) ? window_height : document_height;
	}
});
Event.observe(document, "dom:loaded", function() { var pop = new PopImg(); });