//easy, quick ways of referencing specific items in the DOM models
var d = document;
var w = window;
var n = navigator;

//the follwing are variables to determine the users browser for special ways of handling the differences
//internet explorer browser
var ie = (n.appName.indexOf('Microsoft') != -1);
//internet explorer version 6
var ie6 = (ie && n.appVersion.indexOf('MSIE 6.0') != -1);
//internet explorer version 7
var ie7 = (ie && n.appVersion.indexOf('MSIE 7.0') != -1);
//internet explorer prior to version 6
var iep = (ie && !ie6 && !ie7);

//opera
var op = (n.appName.indexOf('Opera') != -1);

//netscape based browser
var ns = (n.appName.indexOf('Netscape') != -1);
//safari
var sf = (ns && n.appVersion.indexOf('Safari') != -1);
//windows firefox (or gecko-based windows browser)
var ff_win = (ns && !sf && !op && n.appVersion.indexOf('Windows') != -1);
//macintoch firefox (or gecko-based macintosh browser)
var ff_mac = (ns && !sf && !op && n.appVersion.indexOf('Macintosh') != -1);

function gEBI(id){
	return d.getElementById(id);
}

function cE(element){
	return d.createElement(element);
}

//class to preload images
// expects an array of the image sources, a callback function pointer, and a parameter of callback parameters if any
//sends itself to the callback function
function PreloadImages(images, callbackFunction, callbackParams){
	this.imageSrcArray = images;					//array of the image sources for the images to preload
	this.callbackFunction = callbackFunction;		//function to call when all images have been processed
	this.callbackParams = callbackParams;			//additional parameters for callback function
	this.imageObjects = new Array;					//array of all of the image Objects created
	this.imagesLoaded = 0;							//amount of images loaded successfully
	this.imagesErrored = 0;							//amount of images that errored on load
	this.imagesAborted = 0;							//amount of images that were aborted on load
	this.imagesProcessed = 0;						//amount of images processed
	
	//preload the images
	for(var i = 0; i < images.length; i++)
		this.preload(images[i]);
}

//creates an image object
PreloadImages.prototype.preload = 
		function(image){
			//create the image object
			imageObject = new Image;
			
			//set up the event handlers
			if(ie){
				imageObject.onload = this.onLoad;
				imageObject.onError = this.onError;
				imageObject.onAbort = this.onAbort;
			}	
			else{
				imageObject.addEventListener('load',this.onLoad,false);
				imageObject.addEventListener('error',this.onError,false);
				imageObject.addEventListener('abort',this.onAbort,false);
			}
			
			//set image object properties
			imageObject.parentPreloadClass = this;
			imageObject.loaded = false;
			imageObject.processed = false;
			
			//push onto array first because IE loads the images immediately and may cause the last image to be loaded before pushed onto array, causing an error later
			this.imageObjects.push(imageObject);
			this.imageObjects[this.imageObjects.length-1].src = image;
		};

//called after the image was processed
PreloadImages.prototype.imageProcessed = 
		function(){
			if(this.imagesLoaded + this.imagesErrored + this.imagesAborted == this.imageSrcArray.length)
				this.callbackFunction(this);
		};

//called when image was loaded
PreloadImages.prototype.onLoad = 
		function(){
			this.loaded = true;
			this.processed = true;
			this.parentPreloadClass.imagesLoaded++;
			this.parentPreloadClass.imageProcessed();
		};

//called when an error occured while attempting to load image
PreloadImages.prototype.onError = 
		function(){
			this.processed = true;
			this.parentPreloadClass.imagesErrored++;
			this.parentPreloadClass.imageProcessed();
		};

//called when the page was aborted while attempting to load image
PreloadImages.prototype.onAbort = 
		function(){
			this.processed = true;
			this.parentPreloadClass.imagesAborted++;
			this.parentPreloadClass.imageProcessed();
		};

var WRAP_IMAGES = 1;
var HORIZONTAL_IMAGES = 2;
var VERTICAL_IMAGES = 4;
function SlideShow(parentId, flags){
	this.variable_name = parentId;
	this.container_div = gEBI(parentId);
	this.slideshow_div = document.createElement('div');
	this.timeout = null;
	this.left_margin = 0;
	this.top_margin = 0;
	this.isWrapAroundSlideshow = flags & WRAP_IMAGES;
	this.addToHeight = 0;
	this.addToWidth = 0;
	this.images = new Array;
	this.imageClass = '';
	this.maxWidth = null;
	this.maxHeight = null;
	this.isHorizontal = !(flags & VERTICAL_IMAGES);
	
	this.container_div.style.overflow = 'hidden';
	this.slideshow_div.className = 'scroll_container_div';
	this.slideshow_div.id = parentId + '_image_container';
	this.slideshow_div.style.marginLeft = '0px';
}

SlideShow.prototype.addImage = 
		function (src, alt, href, target){
			this.images.push({src:src, alt:alt, href:href, target:target});
		};

SlideShow.prototype.setImageClass = 
		function (imageClass){
			this.imageClass = imageClass;
		};

SlideShow.prototype.setImageMargins = 
		function (top,bottom,left,right){
			this.addToHeight = top + bottom;
			this.addToWidth = left + right;
		};

SlideShow.prototype.setMaxImageWidth = 
		function (maxWidth){
			this.maxWidth = maxWidth;
		};

SlideShow.prototype.setMaxImageHeight = 
		function (maxHeight){
			this.maxHeight = maxHeight;
		};

SlideShow.prototype.draw = 
		function (){
			var imageSrcs = new Array;
			for(i=0; i<this.images.length; i++)
				imageSrcs.push(this.images[i].src);
			
			var imagePreloader = new PreloadImages(imageSrcs, this.addImagesAfterPreload, this);
		};

SlideShow.prototype.addImagesAfterPreload = 
		function (preloadClassObject){
			var thisImage;
			var thisObject = preloadClassObject.callbackParams;
			var imageObjects = preloadClassObject.imageObjects;
			var imageClass = thisObject.imageClass;
			var images = thisObject.images;
			var container_div = thisObject.container_div;
			var slideshow_div = thisObject.slideshow_div;
			var addToHeight = thisObject.addToHeight;
			var addToWidth = thisObject.addToWidth;
			var maxHeight = thisObject.maxHeight;
			var maxWidth = thisObject.maxWidth;
			var isWrapAroundSlideshow = thisObject.isWrapAroundSlideshow;
			var isHorizontal = thisObject.isHorizontal;

			for(i=0; i<images.length; i++){
				thisImage = imageObjects[i];
				if(images[i].alt){
					thisImage.alt = images[i].alt;
					thisImage.title = images[i].alt;
				}
				thisImage.className = imageClass;
				thisImage.style.display = 'inline';
				thisImage.style.verticalAlign = 'middle';
				
				if(images[i].href){
					var aTag = cE('a');
					aTag.href = images[i].href;
					if(images[i].alt)
						aTag.title = images[i].alt;
					if(images[i].target)
						aTag.target = images[i].target;
					aTag.appendChild(thisImage);
					slideshow_div.appendChild(aTag);
				}
				else{
					slideshow_div.appendChild(thisImage);
				}
			}
			container_div.appendChild(slideshow_div);

			thisObject.fixHeightWidth(slideshow_div.id, addToHeight, addToWidth, maxHeight, maxWidth, isWrapAroundSlideshow, isHorizontal);
			
			if(isHorizontal)
				thisObject.maxLeft = container_div.offsetWidth - slideshow_div.offsetWidth;
			else
				thisObject.maxTop = container_div.offsetHeight - slideshow_div.offsetHeight;
		};

//function that fixes the height and width of the slideshow after getting all of the images loaded
SlideShow.prototype.fixHeightWidth =
		function (id, addToHeight, addToWidth, imageMaxHeight, imageMaxWidth, isWrapAroundSlideshow, isHorizontal){
			var slideshow_div = gEBI(id);
			var container_div = slideshow_div.parentNode;
			var maxHeight = 0;
			var maxWidth = 0;
			var totalWidth = 0;
			var totalHeight = 0;
			
			for(i=0; i < slideshow_div.childNodes.length; i++){
				var imageNode = slideshow_div.childNodes[i].nodeName == 'A' ? slideshow_div.childNodes[i].firstChild : slideshow_div.childNodes[i];
				//rescale image if maxWidth was sent and it is larger
				if(imageMaxWidth != null && imageNode.width > imageMaxWidth){
					imageNode.height = parseInt(imageNode.height * imageMaxWidth/imageNode.width);
					imageNode.width = imageMaxWidth;
				}
				//rescale image if maxHeight was sent and it is larger
				if(imageMaxHeight != null && imageNode.height > imageMaxHeight){
					imageNode.width = parseInt(imageNode.width * imageMaxHeight/imageNode.height);
					imageNode.height = imageMaxHeight;
				}
				
				if(imageMaxWidth != null && imageNode.width < imageMaxWidth){
					var addToHorizontalMargin = imageMaxWidth-imageNode.width;
					var addToLeftMargin = parseInt((imageMaxWidth-imageNode.width)/2);
					imageNode.style.marginLeft = addToLeftMargin + 'px';
					imageNode.style.marginRight = (addToHorizontalMargin - addToLeftMargin) + 'px';
				}
				else{
					var addToHorizontalMargin = 0;
				}
				if(imageMaxHeight != null && imageNode.height < imageMaxHeight){
					var addToVerticalMargin = imageMaxHeight-imageNode.height;
					var addToTopMargin = parseInt((imageMaxHeight-imageNode.height)/2);
					imageNode.style.marginTop = addToTopMargin + 'px';
					imageNode.style.marginBottom = (addToVerticalMargin - addToTopMargin) + 'px';
				}
				else{
					var addToVerticalMargin = 0;
				}
				
				//calculate the proper widths and heights with this image
				if(isHorizontal){
					if(imageNode.offsetHeight + addToHeight + addToVerticalMargin > maxHeight)
						maxHeight = imageNode.offsetHeight + addToHeight + addToVerticalMargin;
					totalWidth += imageNode.offsetWidth + addToHorizontalMargin + addToWidth;
				}
				else{
					if(imageNode.offsetWidth + addToWidth + addToHorizontalMargin > maxWidth)
						maxWidth = imageNode.offsetWidth + addToWidth + addToHorizontalMargin;
					totalHeight += imageNode.offsetHeight + addToVerticalMargin + addToHeight;
				}
			}
			
			slideshow_div.style.height = (isHorizontal ? maxHeight : totalHeight) + 'px';
			slideshow_div.style.width = (isHorizontal ? totalWidth : maxWidth) + 'px';
			
			if(isWrapAroundSlideshow){
				if(isHorizontal && slideshow_div.offsetWidth > container_div.offsetWidth){
					slideshow_div.style.width = (2*totalWidth) + 'px';
					var amountPictures = slideshow_div.childNodes.length;
					for(i=0; i < amountPictures; i++){
						var node = slideshow_div.childNodes[i].cloneNode(true);
						slideshow_div.appendChild(node);
					}
				}
				else{
					if(!isHorizontal && slideshow_div.offsetHeight > container_div.offsetHeight){
						slideshow_div.style.height = (2*totalHeight) + 'px';
						var amountPictures = slideshow_div.childNodes.length;
						for(i=0; i < amountPictures; i++){
							var node = slideshow_div.childNodes[i].cloneNode(true);
							slideshow_div.appendChild(node);
						}
					}
				}
			}
		}
		
SlideShow.prototype.moveLeft =
		function(amount, step, speed){
			moveAmount = amount > step ? step : amount;
			amountLeft = amount-moveAmount;
			this.left_margin -= moveAmount;
			if(this.isWrapAroundSlideshow && this.left_margin <= this.maxLeft)
				this.left_margin += this.slideshow_div.offsetWidth/2;
			this.slideshow_div.style.marginLeft = this.left_margin+'px';
			window.clearTimeout(this.timeout);
			if(amountLeft > 0)
				this.timeout = window.setTimeout(this.variable_name + '.moveLeft(' + amountLeft + ',' + step + ',' + speed + ');', speed);
			else
				this.timeout = null;
		};

SlideShow.prototype.moveRight =
		function(amount, step, speed){
			moveAmount = amount > step ? step : amount;
			amountLeft = amount-moveAmount;
			this.left_margin += moveAmount;
			if(this.isWrapAroundSlideshow && this.left_margin >= 0)
				this.left_margin -= this.slideshow_div.offsetWidth/2;
			this.slideshow_div.style.marginLeft = this.left_margin+'px';
			window.clearTimeout(this.timeout);
			if(amountLeft > 0)
				this.timeout = window.setTimeout(this.variable_name + '.moveRight(' + amountLeft + ',' + step + ',' + speed + ');', speed);
			else
				this.timeout = null;
		};
		
SlideShow.prototype.moveUp =
		function(amount, step, speed){
			moveAmount = amount > step ? step : amount;
			amountLeft = amount-moveAmount;
			this.top_margin -= moveAmount;
			if(this.isWrapAroundSlideshow && this.top_margin <= this.maxTop)
				this.top_margin += this.slideshow_div.offsetHeight/2;
			this.slideshow_div.style.marginTop = this.top_margin+'px';
			window.clearTimeout(this.timeout);
			if(amountLeft > 0)
				this.timeout = window.setTimeout(this.variable_name + '.moveUp(' + amountLeft + ',' + step + ',' + speed + ');', speed);
			else
				this.timeout = null;
		};

SlideShow.prototype.moveDown =
		function(amount, step, speed){
			moveAmount = amount > step ? step : amount;
			amountLeft = amount-moveAmount;
			this.top_margin += moveAmount;
			if(this.isWrapAroundSlideshow && this.top_margin >= 0)
				this.top_margin -= this.slideshow_div.offsetHeight/2;
			this.slideshow_div.style.marginTop = this.top_margin+'px';
			window.clearTimeout(this.timeout);
			if(amountLeft > 0)
				this.timeout = window.setTimeout(this.variable_name + '.moveDown(' + amountLeft + ',' + step + ',' + speed + ');', speed);
			else
				this.timeout = null;
		};




/******************************************************************************************************************

							THESE ARE THE API CALLABLE FUNCTIONS

******************************************************************************************************************/

SlideShow.prototype.fastForward =
		function(move,step,speed){
			if(!this.timeout){
				if(this.isHorizontal){
					if(this.maxLeft < 0){
						if(!this.isWrapAroundSlideshow)
							var actualMove = this.left_margin-this.maxLeft < move ?  this.left_margin-this.maxLeft : move;
						else
							var actualMove = move;
						if(actualMove)
							this.moveLeft(actualMove, step, speed);
					}
				}
				else{
					if(this.maxTop < 0){
						if(!this.isWrapAroundSlideshow)
							var actualMove = this.top_margin-this.maxTop < move ?  this.top_margin-this.maxTop : move;
						else
							var actualMove = move;
						if(actualMove)
							this.moveUp(actualMove, step, speed);
					}
				}
			}
		};

SlideShow.prototype.rewind =
		function(move,step,speed){
			if(!this.timeout){
				if(this.isHorizontal){
					if(this.maxLeft < 0){
						if(!this.isWrapAroundSlideshow)
							var actualMove = this.left_margin+move < 0 ? move : -this.left_margin;
						else
							var actualMove = move;
						if(actualMove)
							this.moveRight(actualMove, step, speed);
					}
				}
				else{
					if(this.maxTop < 0){
						if(!this.isWrapAroundSlideshow)
							var actualMove = this.top_margin+move < 0 ? move : -this.top_margin;
						else
							var actualMove = move;
						if(actualMove)
							this.moveDown(actualMove, step, speed);
					}
				}
			}
		};

SlideShow.prototype.play =
		function(step, speed){
			if(!this.timeout){
				this.fastForward(step,step,speed);
				this.timeout = window.setTimeout(this.variable_name + '.play(' + step + ',' + speed + ');', speed);
			}
		}

SlideShow.prototype.reversePlay =
		function(step, speed){
			if(!this.timeout){
				this.rewind(step,step,speed);
				this.timeout = window.setTimeout(this.variable_name + '.reversePlay(' + step + ',' + speed + ');', speed);
			}
		}

SlideShow.prototype.stop =
		function(){
			if(this.timeout)
				window.clearTimeout(this.timeout);
		}

SlideShow.prototype.toEnd = 
		function(){
			if(!this.timeout){
				if(this.isHorizontal){
					if(this.maxLeft < 0){
						this.left_margin = this.maxLeft;
						this.slideshow_div.style.marginLeft = this.left_margin+'px';
					}
				}
				else{
					if(this.maxTop < 0){
						this.top_margin = this.maxTop;
						this.slideshow_div.style.marginTop = this.top_margin+'px';
					}
				}
			}
		}

SlideShow.prototype.toBeginning = 
		function(){
			if(!this.timeout){
				if(this.isHorizontal){
					this.left_margin = 0;
					this.slideshow_div.style.marginLeft = this.left_margin+'px';
				}
				else{
					this.top_margin = 0;
					this.slideshow_div.style.marginTop = this.top_margin+'px';
				}
			}
		}

SlideShow.prototype.addPlayListener = 
		function(id, step, speed){
			var funct = ie ? function(){gEBI(id).thisScrollObject.play(step, speed);} : function(){this.thisScrollObject.play(step, speed);};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addReversePlayListener = 
		function(id, step, speed){
			var funct = ie ? function(){gEBI(id).thisScrollObject.reversePlay(step, speed);} : function(){this.thisScrollObject.reversePlay(step, speed);};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addRewindListener = 
		function(id, amount, step, speed){
			var funct = ie ? function(){gEBI(id).thisScrollObject.rewind(amount, step, speed);} : function(){this.thisScrollObject.rewind(amount, step, speed);};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addFastForwardListener = 
		function(id, amount, step, speed){
			var funct = ie ? function(){gEBI(id).thisScrollObject.fastForward(amount, step, speed);} : function(){this.thisScrollObject.fastForward(amount, step, speed);};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addStopListener = 
		function(id){
			var funct = ie ? function(){gEBI(id).thisScrollObject.stop();} : function(){this.thisScrollObject.stop();};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addBeginningListener = 
		function(id){
			var funct = ie ? function(){gEBI(id).thisScrollObject.toBeginning();} : function(){this.thisScrollObject.toBeginning();};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addEndListener = 
		function(id){
			var funct = ie ? function(){gEBI(id).thisScrollObject.toEnd();} : function(){this.thisScrollObject.toEnd();};
			this.addScrollListener(id, funct);
		}

SlideShow.prototype.addScrollListener =
		function (id, funct, thisSlideShowObject){
			//add scrolling listener
			if(ie)
				gEBI(id).attachEvent('onclick', funct);
			else
				gEBI(id).addEventListener('click',funct,false);
			gEBI(id).thisScrollObject = this;
		}
