/*
-------------------
#=js2 - Gallery Slideshow
-------------------
   Name:	js2
Version:	1.0.2
 Author:	Joey Fowler <joey@d3corp.com>
Details:	General JS/CSS gallery slideshow that is fully customizable.
-------------------
*/

var js2 = {};

// reduce the amount of "."'s used and just call get_element()
function get_element(elem) {
	return document.getElementById(elem);
}

// get all "child" tags of the specified type from the parent element
function get_tags(tag, parent) {
	parent = (parent || document);
	return parent.getElementsByTagName(tag);
}

// setup the default values of the slideshow object
js2.slideshow = function(name) {
	this.animating					= false;
	this.hide_descr_when_empty		= true;
	this.hilight_border_color		= '#FF0000';
	this.name						= name;
	this.nav_hover					= 70;
	this.nav_opacity				= 25;
	this.num_rows					= 4;
	this.scroll_speed				= 12;
	this.thumbnail					= Array();
	this.thumbnail_spacing			= 5;
	this.thumb_opacity				= 70;
}

// setup the main slideshow prototype
js2.slideshow.prototype = {
	// initialize the slideshow object
	init: function() {
		var list	= get_tags('li', get_element(this.name)),	// UL->LI that contains all of the thumbnail images and their titles/descriptions
			i = j	= 0,										// incrementer
			width	= 0;										// holds the current width of the thumbnail container

		this.length			= list.length;											// holder for the length of the list
		this.full_div		= get_element(this.name + '_full_image');				// reference to the "large" image div
		this.full_width		= parseInt(js2.style.val(this.full_div, 'width'));		// gets the width of the "large" image
		this.thumbs_div		= get_element(this.name + '_slider');					// reference to the thumbnail "sliding" div		
		this.thumbs_height	= parseInt(js2.style.val(this.thumbs_div, 'height'));	// gets the width of the "large" image
		this.descr_div		= get_element(this.name + '_description');				// reference to the "description" div

		var iterations = Math.ceil(this.length / this.num_rows);
		for (j; j<iterations; j++) {
			var col = document.createElement('div');
			col.setAttribute('class', 'js2_image_col');
			col.className = 'js2_image_col';
			var end = (j + 1) * this.num_rows;
			// loop thru all of the thumbnail images and add them to the slider (while also getting their title/descriptions)
			var max_width = 0;
			for (i; i<end; i++) {
				if (i >= this.length) break;
				this.thumbnail[i]	= {};
				var	li				= list[i],
				thumbnail			= this.thumbnail[i];
				
				// get the (first) image in the LI tag
				var thumb = get_tags('img', li)[0];
				if ((thumb == null) || (thumb.getAttribute('src') == '')) {
					// there ain't no picture!!! ahhhhhhh...wait, it's ok =P ...just remove this "block" from
					// the thumbnails array and move on..heh
					list.splice(i, 1);
					i--;
					continue; 
				}
				thumbnail.large = thumb.getAttribute('large'); // get the "large" version of the image (set as an attribute on the img tag)
				if (thumbnail.large == '') {
					// there ain't a "large" picture specified, so we have to force to use the thumbnail =/
					thumbnail.large = thumb.getAttribute('src');
				}
				
				thumbnail.descr		= get_tags('p', li)[0].innerHTML;			// image description
				thumbnail.title 	= get_tags('h1', li)[0].innerHTML;			// image title
				thumbnail.url		= (url = get_tags('a', li)[0]) ? url : '';	// any available URL
	
				// add the thumbnail to the "slider"
				col.appendChild(thumb);
				if (i < (end - 1)) thumb.style.marginBottom = this.thumbnail_spacing + 'px';
				col.appendChild(document.createElement('br'));
				
				// add the "alt" attribute to the image
				thumb.setAttribute('alt', thumbnail.title);
				thumb.setAttribute('title', thumbnail.title);
				
				// setup the faded effect on the thumbnail
				thumb.style.opacity	= this.thumb_opacity / 100;
				thumb.style.filter	= 'alpha(opacity=' + this.thumb_opacity + ')';
				
				// setup the mouse-over effects and the "make me large" clickable do-hicky
				thumb.onmouseover	= new Function('js2.alpha.set(this, 100, 5)');
				thumb.onmouseout	= new Function('js2.alpha.set(this, ' + this.thumb_opacity + ', 5)');
				thumb.onclick		= new Function(this.name + '.load_image(' + i + ')');
			}
			this.thumbs_div.appendChild(col);
			width += parseInt(col.offsetWidth + this.thumbnail_spacing);
			this.thumbs_div.style.width = width + 'px';
		}
		
		// setup the previous/next buttons
		var prev_btn = get_element(this.name + '_prev_btn'),
			next_btn = get_element(this.name + '_next_btn');
		if (prev_btn && next_btn) {
			var prev_link = document.createElement('a');
			prev_link.setAttribute("title", 'Previous');
			prev_link.setAttribute("href", "javascript:void(0);");
			prev_link.innerHTML = prev_btn.innerHTML;
			prev_btn.innerHTML = "";
			prev_btn.appendChild(prev_link);
			var next_link = document.createElement('a');
			next_link.setAttribute("title", 'Next');
			next_link.setAttribute("href", "javascript:void(0);");
			next_link.innerHTML = next_btn.innerHTML;
			next_btn.innerHTML = "";
			next_btn.appendChild(next_link);
			
			prev_btn.onclick	= new Function('js2.scroll.init("' + this.name + '_slider", -1, ' + this.scroll_speed + ')');
			next_btn.onclick	= new Function('js2.scroll.init("' + this.name + '_slider", 1, ' + this.scroll_speed + ')');
		} else {
			// either one (or both) of the prev/next buttons are missing, make sure both are hidden
			if (prev_btn) prev_btn.style.display = 'none';
			if (next_btn) next_btn.style.display = 'none';
		}
		
		this.load_image(0);
	},
	
	// setup and load the specified image
	load_image: function(pos) {
		// setup the "temp" image to load the large version of
		this.thumb			= new Image();
		this.thumb.onload	= new Function(this.name + '.image_loaded(' + pos + ')');
		this.thumb.src		= this.thumbnail[pos].large;
		
		// reset all of the borders for all of the images and "highlight" the selected one
		var img = get_tags('img', this.thumbs_div), length = img.length, i = 0, width_pos = 0;
		for (i; i<length; i++) {
			img[i].className = (i != pos) ? 'js2_image' : 'js2_image thumb_active';
			if (i <= pos) width_pos += parseInt(img[i].offsetWidth) + parseInt(this.thumbnail_spacing);
		}
	},

	// handles when the "large" image finishes loading
	image_loaded: function(pos) {
		this.full_div.appendChild(this.thumb);
		this.thumb.style.left = parseInt((this.full_div.offsetWidth - this.thumb.offsetWidth) / 2) + 'px';
		
		// set the large image's "alt" attribute to be the image's title
		this.thumb.setAttribute('alt', this.thumbnail[pos].title);
		this.thumb.setAttribute('title', this.thumbnail[pos].title);
		
		// check for a URL
		if (this.thumbnail[pos].url != '') {
			// a URL exists for this image, make the URL div "linkable"
			this.full_div.onclick		= new Function('window.location="' + this.thumbnail[pos].url + '"');
			this.full_div.style.cursor	= 'pointer';
		} else {
			// no link, do nothing (for now)
			this.full_div.onclick = null;
			this.full_div.style.cursor = 'default';
		}
		
		// check for a description
		if ((this.thumbnail[pos].descr != '') && this.descr_div) {
			this.descr_div.innerHTML = this.thumbnail[pos].descr;
			if (this.hide_descr_when_empty) this.descr_div.style.display = '';
		} else if (this.descr_div) {
			this.descr_div.innerHTML = '';
			if (this.hide_descr_when_empty) this.descr_div.style.display = 'none';
		}
		
		// remove any "additional" images in the "large image" container
		var img = get_tags('img', this.full_div);
		if (img.length > 1) this.full_div.removeChild(img[0]);
	}
};

// handles scrolling the thumbnails horizontally
// plans to implement vertical scrolling are on my list =]
js2.scroll = function() {
	this.intval = null;
	return {
		// initialize the scrolling function
		init: function(thumbs, dir, speed) {
			if (js2.animating == true) return;
			js2.animating = true;
			// if the thumbs element passed is just the ID, make sure to get the actual thumbnails before proceeding
			thumbs = (typeof(thumbs) == 'object') ? thumbs : get_element(thumbs);

			// get the leftmost position of the thumbnails and hard-set it as an attribute
			var left_pos = parseInt(js2.style.clean_pixels((thumbs.style.left || js2.style.val(thumbs, 'left'))));
			thumbs.style.left = left_pos + 'px';
			
			// determine the ending destination / left position and setup the sliding interval
			var end_left, thumbs_width = parseInt(thumbs.offsetWidth), slider_width = parseInt(thumbs.parentNode.offsetWidth);
			// we're gonna scroll a full "page" of thumbnails at a time, so make the "end position" the next "page", or whatever's closest
			end_left = (dir == 1) ? ((((thumbs_width + left_pos) - slider_width) < slider_width) ? (left_pos - ((thumbs_width + left_pos) - slider_width)) : (left_pos - slider_width)) : ((left_pos >= -slider_width) ? 0 : (left_pos + slider_width));
			
			this.intval = setInterval(function() { js2.scroll.slide(thumbs, end_left, dir, speed); }, 20);
		},

		// perform the "sliding" transition
		slide: function(thumbs, end_left, dir, speed) {
			// if the thumbs element passed is just the ID, make sure to get the actual thumbnails before proceeding
			thumbs = (typeof(thumbs) == 'object') ? thumbs : get_element(thumbs);

			// get the current "leftmost" position of the thumbnails
			//var left_pos = parseInt(js2.style.clean_pixels((thumbs.style.left || js2.style.val(thumbs, 'left'))));
			var left_pos = jQuery("#js2_images_slider").position().left;

			if (((dir == 1) && (left_pos <= end_left)) || ((dir == -1) && (left_pos >= end_left))) {
				// we have reached our "destination", kill the slide
				js2.scroll.clear_interval(thumbs);
			} else {
				// we have more sliding to do
				var i = Math.abs(end_left + left_pos);
				i = (i < speed) ? i : speed;
				var n = (left_pos - i * dir);
				thumbs.style.left = n + 'px';
			}
			
		},

		reset: function(thumbs, end_left, dir, speed){
			if(js2.animating) return;
			
			js2.animating = true;
			
			this.intval = setInterval(function() { js2.scroll.slide(thumbs, end_left, dir, speed); }, 20);
		},
		
		animating: function(){
			return js2.animating;
		},

		// clear the "sliding" interval to stop the sliding animation
		clear_interval: function(thumbs,dir) {
			// if the thumbs element passed is just the ID, make sure to get the actual thumbnails before proceeding
			thumbs = (typeof(thumbs) == 'object') ? thumbs : get_element(thumbs);
			clearInterval(this.intval); // clear the "sliding" interval
			js2.animating = false;
		}
	}
} ();

// handles the alpha fading in/out of any requested element =]
js2.alpha = function() {
	return {
		// set the specified elements alpha/opacity
		set: function(elem, alpha, steps) {
			// if the element passed is just the ID, make sure to get the actual element before proceeding
			elem = (typeof(elem) == 'object') ? elem : get_element(elem);
			
			// get the current opacity of the element and determine the direction to proceed in
			var opacity = (elem.style.opacity || js2.style.val(elem, 'opacity')),
				dir		= ((alpha > (opacity * 100)) ? 1 : -1);

			// set the elements opacity
			elem.style.opacity = opacity;
			
			// clear any current interval set and then reset it with all of the new settings
			clearInterval(elem.alpha_interval);
			elem.alpha_interval = setInterval(function() { js2.alpha.transition(elem, alpha, dir, steps); }, 20);
		},
		
		// performs the alpha transition to fade in/out
		transition: function(elem, alpha, dir, steps) {
			// calc the new opacity
			var opacity = Math.round(elem.style.opacity * 100);
			
			if (opacity == alpha) {
				// we have reached the ending alpha, clear the interval!
				clearInterval(elem.alpha_interval);
			} else {
				// we still have stuffs to do, calc the new opacity and set both the style and
				// filter so all browsers will register it
				var i = (opacity + Math.ceil(Math.abs(alpha - opacity) / steps) * dir);
				elem.style.opacity	= (i / 100);
				elem.style.filter	= 'alpha(opacity=' + i + ')';
			}
		}
	}
} ();

// we need to pull different style attributes from elements, but browsers (specifically IE) do it different from others
// document.defaultView.getComputedStyle - gets the "computed" style for all browsers, except IE
// elem.currentStyle[*] - gets the current style for IE
js2.style = function() {
	return {
		// return the requested style on the requested element
		val: function(elem, style) {
			// if the element passed is just the ID, make sure to get the actual element before proceeding
			elem = (typeof(elem) == 'object') ? elem : get_element(elem);
			return (document.defaultView && document.defaultView.getComputedStyle) ? document.defaultView.getComputedStyle(elem, null).getPropertyValue(style) : elem.currentStyle[style.replace(/\-(\w)/g, function (str, p1) { return p1.toUpperCase(); })];
		},
		
		// check for, and remove if found, any "px" on a css style
		clean_pixels: function(css) {
			return (((typeof(css) == 'string') && (css.substr((css.length - 2), 2) == 'px')) ? css.substr(0, (css.length - 2)) : css);
		}
	}
} ();
