/*
Parameters:

pShowID : MUST - the ID on the div container wrapping the slide show.
pDirection : OPTIONAL ["immediately" | "fade" | "slash" | "down" | "up" | "left" | "right"]
pRestTime : OPTIONAL [<integer>] - the number of milliseconds a slide rests before a new slide starts to emerge 
pJump : OPTIONAL [<integer>] - pixels pr. each incremental moving of a slide (for pDirection = "immediately", pJump is ignored)
pDelay : OPTIONAL [<integer>] - milliseconds between each incremental moving of a slide (for pDirection = "immediately", pSpeed is ignored)
pPauseOnMouseover : OPTIONAL [true | false] - false is default. If true then the slideShow will pause then the mouse hovers the slideShow and continue then then mouse leaves the slideShow
pAutoSlide : OPTIONAL [true | false] - true is default. If false then the slideShow will not slide by itself, instead you need to call the move each time you want to slide.
pStackJump : OPTIONAL [<integer>] - 1 is default. if -1 then the next slideIndex will be current slideIndex - 1. (used to go back and forth in the slide stack)

Note1:
pDirection = "immediately" understands
		pJump is ignored
		pDelay is ignored

Note2:
pDirection = "fade" understands:
		pJump as opacity percentage to jump between each opacity change
		pDelay as the milliseconds between each opacity change

Note3:
pDirection = "slash" can only be used on single text containers (no nesting, eg. A inside a SPAN)
pDirection = "slash" understands:
		pJump as number of letters per slash
		pDelay as the milliseconds between each slash

Note4:
pNonAuto = true understands
	pPauseOnMouseover is ignored.

Ideas:
1) pDirection = "flip" could be added creating the effect of flipping a book like here: http://www.dynamicdrive.com/dynamicindex14/bookflip.htm
, the dynamicdrive example could be extended so that then the mouse hovers the left side, the book flips in one direction
, and then the mouse hovers in the right side, the book flips in the other direction - like flipping pages back and forth in a book
2) non-auto sliding could be added like: http://smoothslideshow.jondesign.net/showcase.html
3) event firing then 3.1) a slide starts to slide & 3.2) a slide finish slide. The event should contain
pSlideShowID, direction & currentSlideIndex (even if currentSlideIndex can be found in the runtime. The user should only use the runtime to dig deeper into properties of the current slide)
*/

var wm_slideShow_globals = new function(){
	//The config properties are default values (they will be applied if the value is not transfered as an argument to the wm_slideShow argument list)
	//You can use the config properties to set up your own default configuration
	this.direction = "up"; //config
	this.jump = 1; //config
	this.speed = 10; //config
	this.restTime = 2000; //config
	this.pauseOnMouseover = false; //config
	this.autoSlide = true; //config
	this.stackJump = 1; //config

	//Non-argument properties - default values that cannot be altered using the wm_slideShow argument list, however they can be altered here (hence it is impossible to use different values for different slides on the same page)
	this.slashCursors = ["\\","|","/","-"]; //config
	this.slashCursorIndex = -1; //runtime
	this.getSlashCursor = function(){
		this.slashCursorIndex = (this.slashCursorIndex == this.slashCursors.length - 1) ? 0 : this.slashCursorIndex + 1;
		return this.slashCursors[this.slashCursorIndex];
	}

	//Do not edit any runtime values
	var runtimes = {};//(used as a Hashtable) there will be a runtime object associated with each slideShowID on the page - the runtime object keep state between setTimeout
	this.getRuntime = function(pShowID){
		if (runtimes[pShowID] == null){
			var runtime = {"isInitialized":false,"timer":null,"pausing":false,"show":null,"slides":[],"slidesSlashText":[],"slashPosition":0,"currentSlideIndex":0,"zIndex":0,"slideWidth":0,"slideHeight":0,"opacity":100}
			runtimes[pShowID] = runtime;
		}
		return runtimes[pShowID];
	}
	//(I simply cannot find out how to read opacity out in IE, so I maintain the value on the runtime hashtable instead)
	//slashPosition have the same function as eg. element.style.top, however while I can read the top-value of the style object and therefore don't need to be concerned with how to maintain state of the top-value, I cannot read the slashPostion of the objects within the slide element, therefore I need to have the slashPosition on the runtime hashtable
}

function wm_slideShow(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish){
		var slideShowClosure = wm_slideShow_closure(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish);
		if (window.addEventListener){
			window.addEventListener("load", slideShowClosure, false);
		}
		else{
			window.attachEvent("onload", slideShowClosure);
		}
}

function wm_slideShow_closure(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish){
	//FF behaves wrong if the slideShow is startet before body.onload, therefore I add the slideShow
	//as an eventhandler to the window load event.
	return function(){wm_slideShow_execute(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish);}
}

function wm_slideShow_execute(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish){

	this.addEvent = function(pTarget, pEventType, pEventHandler){
		if (pTarget.addEventListener){
				pTarget.addEventListener(pEventType, pEventHandler, false);
		}
		else if (pTarget.attachEvent){
			pTarget.attachEvent("on" + pEventType, pEventHandler);
		}
	}
	
	var direction = (pDirection == null) ? wm_slideShow_globals.direction : pDirection;
	var jump = (pJump == null) ? wm_slideShow_globals.jump : pJump;
	var speed = (pSpeed == null) ? wm_slideShow_globals.speed : pSpeed;
	var restTime = (pRestTime == null) ? wm_slideShow_globals.restTime : pRestTime;
	var pauseOnMouseover = (pPauseOnMouseover == null) ? wm_slideShow_globals.pauseOnMouseover : pPauseOnMouseover;
	var autoSlide = (pAutoSlide == null) ? wm_slideShow_globals.autoSlide : pAutoSlide;
	var stackJump = (pStackJump == null) ? wm_slideShow_globals.stackJump : pStackJump;
	if (stackJump == 0){alert("pStackJump cannot be set to zero, please choose a positive or negative integer");return;}

	var runtime = wm_slideShow_globals.getRuntime(pShowID);
	
	if (!runtime.isInitialized){
		var onlyDoInitialize = !autoSlide;
		runtime.isInitialized = true;
		runtime.show = document.getElementById(pShowID);
		show = runtime.show;
		show.style.position = (show.style && show.style.position) ? show.style.position : "relative";

		if (pauseOnMouseover){
			addEvent(show, "mouseover", function(){runtime.pausing = true;});
			addEvent(show, "mouseout", function(){runtime.pausing = false;});
		}

		for (var c = show.childNodes.length - 1; c >= 0; c--){
			var child = show.childNodes[c];
			if (child.tagName == null || child.tagName == "!"){//! is the comment tagName
				//discard the child
				show.removeChild(child)
				child = null;
			}
			else{
				show.removeChild(child)
				if (direction == "slash"){
					var textNode = child.removeChild(child.firstChild);
					runtime.slidesSlashText.push(textNode.nodeValue);
					runtime.slides.push(child);
				}
				else{
					//wrap the child in a DIV and add that wrapper to the slides array
					var div = document.createElement("div");
					div.style.position = "absolute";
					div.style.display = "block";
					div.style.zIndex = 0;
					div.appendChild(child);
					runtime.slides.push(div);
				}
			}
		}

		runtime.slides.reverse();
		runtime.slidesSlashText.reverse();

		//set in the first slide
		var firstSlide = runtime.slides[0];
		firstSlide.style.zIndex = runtime.zIndex;
		firstSlide.style.position = "absolute";
		firstSlide.style.top = 0;
		firstSlide.style.left = 0;
		show.appendChild(firstSlide);
		runtime.slideWidth = firstSlide.offsetWidth;
		runtime.slideHeight = firstSlide.offsetHeight;
		
		if (onlyDoInitialize){return;}
	}
	
	advanceSlide(runtime.currentSlideIndex);

	function advanceSlide(pSlideIndex){
		if (!runtime.pausing){
			var currentSlide = runtime.slides[runtime.currentSlideIndex];
			var currentSlide_left = parseInt(currentSlide.style.left, 10);
			var currentSlide_top = parseInt(currentSlide.style.top, 10);
			var currentSlide_slashText = (direction == "slash") ? runtime.slidesSlashText[runtime.currentSlideIndex] : "";
			var currentSlide_slashPosition = runtime.slashPosition;

			if (direction == "right" && currentSlide_left < 0){//move this slide further to the right
				if (currentSlide_left > -jump){
					currentSlide.style.left = "0px";
				}
				else{
					currentSlide.style.left = (currentSlide_left + jump) + "px";
				}
				if (currentSlide.style.left == "0px"){
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, pSlideIndex);}
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
			}
			else if (direction == "left" && currentSlide_left > 0){//move this slide further to the left
				if (currentSlide_left < jump){
					currentSlide.style.left = "0px";
				}
				else{
					currentSlide.style.left = (currentSlide_left - jump) + "px";
				}
				if (currentSlide.style.left == "0px"){
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, pSlideIndex);}
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
			}
			else if (direction == "down" && currentSlide_top < 0){
				if (currentSlide_top > -jump){
					currentSlide.style.top = "0px";
				}
				else{
					currentSlide.style.top = (currentSlide_top + jump) + "px";
				}
				if (currentSlide.style.top == "0px"){
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, pSlideIndex);}
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
			}
			else if (direction == "up" && currentSlide_top > 0){
				if (currentSlide_top < jump){
					currentSlide.style.top = "0px";
				}
				else{
					currentSlide.style.top = (currentSlide_top - jump) + "px";
				}
				if (currentSlide.style.top == "0px"){
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, pSlideIndex);}
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
			}
			else if (direction == "fade" && runtime.opacity < 100){
				if (runtime.opacity + jump > 100){
					runtime.opacity = 100;
				}
				else{
					runtime.opacity += jump;
				}
				setOpacity(currentSlide, runtime.opacity);
				
				if (runtime.opacity == 100){
					//do resting
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, pSlideIndex);}
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
			}
			else if (direction == "slash" && currentSlide_slashPosition > -1){
				var slashTextLength = currentSlide_slashText.length;
				if (currentSlide_slashPosition < slashTextLength){ 
					var newSlashPosition = currentSlide_slashPosition + jump;
					if (newSlashPosition > currentSlide_slashText.length){newSlashPosition = currentSlide_slashText.length;}
					var part = currentSlide_slashText.substring(0, newSlashPosition);
					if (newSlashPosition < slashTextLength){
						part += wm_slideShow_globals.getSlashCursor();
					}
					if (currentSlide.firstChild) {currentSlide.removeChild(currentSlide.firstChild);}
					currentSlide.appendChild(document.createTextNode(part));
					runtime.slashPosition = newSlashPosition;
				}
				else{
					//pause
					runtime.slashPosition = -1;//so that then coming again, the code will execute next slide
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, pSlideIndex);}
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
			}
			else{
				//position and start next slide
				if (pCustomActionOnSlideStart){pCustomActionOnSlideStart(pShowID, direction, runtime.slides.length, pSlideIndex);}

				//but first remove not current slide but former slide
				if (runtime.show.childNodes.length > 2){runtime.show.removeChild(runtime.show.firstChild);}
				
				//next slide
				var nextSlideIndex = 0;

				if (stackJump > 0){
					var testNextSlideIndex = runtime.currentSlideIndex + stackJump;

					nextSlideIndex = (testNextSlideIndex >= runtime.slides.length) ? testNextSlideIndex % runtime.slides.length : testNextSlideIndex;

				}
				else{
					var testNextSlideIndex = runtime.currentSlideIndex + stackJump;
					nextSlideIndex = (testNextSlideIndex < 0) ? runtime.slides.length - ((-testNextSlideIndex) % runtime.slides.length) : testNextSlideIndex;
				}
//				var nextSlideIndex = (runtime.currentSlideIndex + 1 == runtime.slides.length) ? 0 : runtime.currentSlideIndex + 1;
				runtime.currentSlideIndex = nextSlideIndex;
				
				var nextSlide = runtime.slides[nextSlideIndex];
				nextSlide.style.zIndex = ++runtime.zIndex;
				nextSlide.style.position = "absolute";
				
				//positioning
				if (direction == "right"){
					nextSlide.style.top = "0px";
					nextSlide.style.left = (- ((nextSlide.offsetWidth == 0) ? runtime.slideWidth : nextSlide.offsetWidth)) + "px";
				}
				else if (direction == "left"){
					nextSlide.style.top = "0px";
					nextSlide.style.left = runtime.slideWidth + "px";
				}
				else if (direction == "down"){
					nextSlide.style.top = (-((nextSlide.offsetHeight == 0) ? runtime.slideHeight : nextSlide.offsetHeight)) + "px";
					nextSlide.style.left = "0px";
				}
				else if (direction == "up"){
					nextSlide.style.top = runtime.slideHeight + "px";
					nextSlide.style.left = "0px";
				}
				else if (direction == "immediately"){
					nextSlide.style.top = "0px";
					nextSlide.style.left = "0px";
					runtime.show.appendChild(nextSlide);
					if (pCustomActionOnSlideFinish){pCustomActionOnSlideFinish(pShowID, direction, runtime.slides.length, nextSlideIndex);}//here I need to transfer nextSlideIndex instead of pSlideIndex because the direction=immediately, the slide finished is in fact nextSlideIndex
					if (autoSlide){
						runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", restTime);
					}
					return;
				}
				else if (direction == "fade"){
					nextSlide.style.top = "0px";
					nextSlide.style.left = "0px";
					runtime.opacity = 0;
					setOpacity(nextSlide, runtime.opacity);
				}
				else if (direction == "slash"){
					runtime.show.innerHTML = "";
					nextSlide.style.top = "0px";
					nextSlide.style.left = "0px";
					runtime.slashPosition = 0;
				}
				
				runtime.show.appendChild(nextSlide);
			}
		}

		runtime.timer = setTimeout("wm_slideShow_execute('" + pShowID + "', '" + direction + "', " + jump + ", " + speed + ", " + restTime + ", " + pauseOnMouseover + ", " + autoSlide + ", " + stackJump + ", " + pCustomActionOnSlideStart + ", " + pCustomActionOnSlideFinish + ")", speed);
	}

	function setOpacity(pElm, pOpacity){
		pElm.style.opacity = (pOpacity / 100);
		pElm.style.MozOpacity = (pOpacity / 100);
		pElm.style.KhtmlOpacity = (pOpacity / 100);
		pElm.style.filter = "alpha(opacity=" + pOpacity + ")";
	}
}


/***************************************** wm_slideShow API *******************************/
function wm_slideShow_slideNext(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish){
	clearTimeout(wm_slideShow_globals.getRuntime(pShowID).timer);
	wm_slideShow_execute(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish);
}

function wm_slideShow_stop(pShowID){
	clearTimeout(wm_slideShow_globals.getRuntime(pShowID).timer);
	wm_slideShow_globals.getRuntime(pShowID).autoSlide = false;
}

function wm_slideShow_start(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish){
	clearTimeout(wm_slideShow_globals.getRuntime(pShowID).timer);
	wm_slideShow_globals.getRuntime(pShowID).autoSlide = true;
	wm_slideShow_slideNext(pShowID, pDirection, pJump, pSpeed, pRestTime, pPauseOnMouseover, pAutoSlide, pStackJump, pCustomActionOnSlideStart, pCustomActionOnSlideFinish);
}

function wm_slideShow_getViewportX(pShowID){
	var slideShow = document.getElementById(pShowID);
	return wm_slideShow_support.coordinates(slideShow).viewport.X
}

function wm_slideShow_getViewportY(pShowID){
	var slideShow = document.getElementById(pShowID);
	return wm_slideShow_support.coordinates(slideShow).viewport.Y
}

function wm_slideShow_getWidth(pShowID){
	var slideShow = document.getElementById(pShowID);
	return slideShow.offsetWidth;
}

function wm_slideShow_getHeight(pShowID){
	var slideShow = document.getElementById(pShowID);
	return slideShow.offsetHeight;
}

var wm_slideShow_support = new function(){
	//wm_slideShow_support only supports the API, the basic slideShow is NOT using the support function
	this.scroll = function(pElm){
		var scrollLeft = 0;
		var scrollTop = 0;
		
		if (pElm){
			scrollLeft = (pElm.scrollLeft) ? pElm.scrollLeft : 0;
			scrollTop = (pElm.scrollTop) ? pElm.scrollTop : 0;
		}
		else if (document.documentElement && (document.documentElement.scrollTop || document.documentElement.scrollLeft)){
			scrollLeft = document.documentElement.scrollLeft;
			scrollTop = document.documentElement.scrollTop;
		}
		else if (document.body){
			scrollLeft = document.body.scrollLeft;
			scrollTop = document.body.scrollTop;
		}
		else if (window.pageXOffset){
			scrollLeft = window.pageXOffset;
			scrollTop = window.pageYOffset;
		}
		else{
			//old browsers and minor browsers
		}
		
		return {"X":scrollLeft,"Y":scrollTop};
	}
	
	this.coordinates = function(pElm){
		var elm = pElm;
		var pageOffsetX = viewportOffsetX = parentX = elm.offsetLeft;
		var pageOffsetY = viewportOffsetY = parentY = elm.offsetTop;
		while (elm = elm.offsetParent){
			pageOffsetX += elm.offsetLeft;
			pageOffsetY += elm.offsetTop;
			viewportOffsetX += elm.offsetLeft - this.scroll(elm.offsetParent).X;//it is ok to send null or undefined to wm_scroll
			viewportOffsetY += elm.offsetTop - this.scroll(elm.offsetParent).Y;
		}

		var coords = {}
		coords.viewport = {"X":viewportOffsetX,"Y":viewportOffsetY};
		coords.document = {"X":pageOffsetX,"Y":pageOffsetY};

		return coords;
	}
}