// NICK NIELSEN JAVASCRIPT APPLICATION LIBRARY
// v 1.3
// changes in this version {added function "VALIDATE EMAIL ADDRESS", "SWAP IMAGE"}




// SHUFFLE ARRAY (New array method that randomly shuffles and array.)

Array.prototype.shuffle = function() {
	var temp = new Array();
	var length = this.length;
	for(i=0; i<length; i++) {
		var randIndex = Math.floor(Math.random()*(this.length));
		var randElement = this.splice(randIndex,1);
		temp.push(randElement);
	}
	return temp;
}




// ARRAY SEARCH
// return all matches between an array and regular expression

Array.prototype.search = function(regex) {
	var matches = new Array();
	for(i=0; i<this.length; i++) {
		var string = this[i];
		var match;
		if(match = string.match(regex)) {matches.push(match[1]);}
	}
	if(matches.length!=0) {return matches;}
	else return null;
}





// REPLACE ONE CHARACTER (New string method.)
// needle: ANY STRING: required (String to search for.)
// replacement: ANY STRING: required (Replace needle with this string.)
// number: ANY NUMBER≥0 (Number of replacements to make.  Default is "1";}
// index: ANY NUMBER≥0 (Index to begin searching. Default is "0".)

String.prototype.charReplace = function(needle,replacement,number,index) {
	if(!number) {var number=1;}
	if(!index) {var index=0;}
	var newString = '';
	var count = 0;
	for(i=0; i<this.length; i++) {
		if(this.charAt(i)==needle && count<number && i>=index) {
			newString+=replacement;
			count++;
		}
		else {newString+=this.charAt(i);}
	}
	return newString;
}




// INCLUDE JAVASCRIPT FILE
// path: RELATIVE FILE PATH: required (File path of script to be included, relative to parent document.)
// callback: ANY JAVASCRIPT FUNCTION (Function to be executed after script has been included.)
// NOTES (doesn't work yet.  Can't detect script load in IE.)

function include(path,callback) {
	var head = document.getElementsByTagName('head')[0];
	var script = document.createElement('script');
	script.type = 'text/javascript';
	script.src = path;
	script.onload = function() {callback();}
	script.onreadystatechange = function() {
		if(script.readyState=='complete') {callback();}
	}
	head.appendChild(script);
}




// DETECT BROWSER

//var callback = function() {alert(BrowserDetect.browser);}
//include(scriptPath('application.js')+'browser_detect.js',callback);




// GET ELEMENT BY ID

function $(id) {
	return document.getElementById(id);
}




// FADE IN - OUT ELEMENT
// direction: 1 OR -1  ("1" for fade in; "-1" for fade out. If no value is specified, or if "0" is entered, element will alternate between in and out.)
// speed: 0 < SPEED ≤ 100 ("0" is the slowest speed, with no fade - resorts to default; "100" is the fastest.  Default is "5".  Entering "0" sets to default.)
// hide: TRUE OR FALSE  (When fading out, if set to "TRUE", hides the element after it has completely faded out. Defatult value is "FALSE".)
// show: ANY ELEMENT DISPLAY VALUE  (When fading in, sets the display value of the element if it was previously "none".  Default is "block".)
// callback: ANY JAVASCRIPT CODE  (runs a script after completion.)

function fade(element,direction,speed,hide,show,callback) {
	var element, direction, speed, hide, show, callback, opacity, increment, animateFade;
	if(BrowserDetect.browser=='Explorer') {
		if(!element.style.filter) {opacity=1;}
		else {
			var string = element.style.filter.replace('alpha(opacity=','');
			string = string.replace(')','');
			opacity = string/100;
		}
	}
	else {
		if(!element.style.opacity) {opacity=1;}
		else {opacity = element.style.opacity;}
	}
	if(opacity>1) {opacity=1;}
	if(opacity<0) {opacity=0;}
	if(element.style.display=='none') {opacity=0;}
	element.style.opacity = opacity;
	element.style.filter = 'alpha(opacity='+opacity*100+')';
	if(!direction | direction==0) {
		if(opacity<.5) {direction=1;}
		else {direction=-1;}
	}
	if(!show | show=='none') {show='block';}
	if(element.style.display=='none' && direction==1) {element.style.display=show;}
	if(!speed | speed==0) {speed=5;}
	increment = .01*speed*direction;
	animateFade = function() {
		opacity = eval(opacity+'+'+increment);
		if(opacity<=0) {opacity=0;}
		if(opacity>=1) {opacity=1;}
		element.style.opacity = opacity;
		element.style.filter = 'alpha(opacity='+opacity*100+')';
		if(opacity==0 | opacity==1) {
			if(opacity==0 && hide) {element.style.display='none';}
			if(callback) {callback();}
			return false;
		}
		setTimeout(animateFade);
	}
	animateFade();
}




// SLIDE OPEN - CLOSED
// max: ANY NUMBER 0 OR GREATER  (When direction is "1" for "open", maximum length element will expand to. Default value is "0".)
// dimension: 1-4  ("1" slides up, "2" slides right, "3" slides down, "4" slides left. Default value is "2".)
// direction: 1 OR -1  ("1" for slide open; "-1" for slide closed. If no value is specified, or if "0" is entered, element will alternate between open and closed.)
// min: ANY NUMBER 0 OR GREATER  (When direction is "-1" for "close", minimum length element will contract to. Default value is "0".)
// speed: 1->100  ("1" is the slowest speed; "100" is the fastest.  Default is "5".  Entering "0" sets to default.)
// hide: TRUE OR FALSE  (When direction is "-1" for "close", if set to "TRUE", hides the element after it has completely closed. Default value is "TRUE".)
// callback: ANY JAVASCRIPT CODE  (runs a script after completion.)

function slide(element,max,dimension,direction,min,speed,hide,callback) {
	element.style.position='relative';
	if(max==undefined) {max=0;}
	if(dimension==undefined) {dimension=2;}
	if(min==undefined) {min=0;}
	marginMin=0;
	marginMax = -1*(max-min);
	if(speed==undefined | speed==0) {speed=5;}
	if(hide==undefined) {hide=true;}
	if(dimension==1 | dimension==3) {
		if(element.style.height=='') {theLength=min;}
		else {theLength = parseInt(element.style.height);}
		element.style.height=theLength+'px';
	}
	else {
		if(element.style.width=='') {theLength=min;}
		else {theLength = parseInt(element.style.width);}
		element.style.width=theLength+'px';
	}
	if(dimension==1) {theMargin=parseInt(element.style.marginTop);}
	if(dimension==2) {theMargin=parseInt(element.style.marginRight);}
	if(dimension==3) {theMargin=parseInt(element.style.marginBottom);}
	if(dimension==4) {theMargin=parseInt(element.style.marginLeft);}
	if(!theMargin) {theMargin=marginMin;}
	if(direction==undefined | direction==0) {
		if(theLength==max) {direction=-1;}
		if(theLength==min) {direction=1;}
	}
	increment = .01*speed*direction*max;
	element.style.display='block';
	animateSlide = function() {
		theLength = eval(theLength+'+'+increment);
		theMargin = theMargin-increment;
		if(theLength>max) {theLength=max;}
		if(theLength<min) {theLength=min;}
		if(theMargin<marginMax) {theMargin=marginMax;}
		if(theMargin>marginMin) {theMargin=marginMin;}
		if(dimension==1 | dimension==3) {element.style.height=theLength+'px';}
		else {element.style.width=theLength+'px';}
		if(dimension==1) {element.style.marginTop = theMargin+'px';}
		if(dimension==2) {element.style.marginRight = theMargin+'px';}
		if(dimension==3) {element.style.marginBottom = theMargin+'px';}
		if(dimension==4) {element.style.marginLeft = theMargin+'px';}
		if(theLength==min | theLength==max) {
			if(direction==-1 && hide==true) {element.style.display='none';}
			if(callback) {callback();}
			return false;
		}
		setTimeout(animateSlide);
	}
	animateSlide();
}




// SELECT TEXT
// start: ANY NUMBER 0 OR GREATER  (selection starting character offset.)
// end: ANY NUMBER 0 OR GREATER  (selection ending character offset.)
// text: ANY STRING  (define specific text to select.)

function selectText(element,start,end,text) {
	if(start==undefined) {start=0;}
	if(end==undefined) {end=element.innerText.length;}
	if (document.selection) {
		var range = document.body.createTextRange();
		range.moveToElementText(element);
 	    range.collapse(true);
 	   	if(text!=undefined) {range.findText(text);}
 	   	if(text==undefined) {
 	   		range.moveEnd('character',end);
 	    	range.moveStart('character',start);
 	    }
		range.select();
	}
	else if (window.getSelection) {
		if(text!=undefined) {
			exp = new RegExp(text,'i');
			for(i=0; i<element.childNodes.length; i++) {
				value = element.childNodes[i].nodeValue;
				if(value!=null) {
					search = value.search(exp);
					if(search!=-1) {
						start = search;
						node = element.childNodes[i];
					}
				}
			}
			end = start+text.length;
		}
		var range = document.createRange();
		window.getSelection().removeAllRanges();
		range.setStart(element,start);
		range.setEnd(element,end);
		window.getSelection().addRange(range);
	}
}




// SELECT ALL TEXT

function selectAllText(element) {
	start=0;
	end=element.innerHTML.length;
	if (document.selection) {
		var range = document.body.createTextRange();
		range.moveToElementText(element);
		range.collapse(true);
		range.moveEnd('character',end);
		range.moveStart('character',start);
		range.select();
	}
	else if (window.getSelection) {
		var range = document.createRange();
		window.getSelection().removeAllRanges();
		range.selectNode(element);
		window.getSelection().addRange(range);
	}
}




// DRAG & DROP
// evt: EVENT (The javascript event.)
// stack: TRUE OR FALSE (Brings selected element to the front of a stack.  Default is false.)

function drag(element,evt,stack) {
	var parentWidth,parentHeight,elementWidth,
	elementHeight,mouseStartX,mouseStartY,
	mouseX,mouseY,velX,velY,elementX,
	elementY,newX,newY,children,siblings,
	sortByZIndex,high,low,increment,zIndex,zKey;
	element.parentNode.style.position = 'relative';
	element.style.position = 'absolute';
	if(stack) {
		children = element.parentNode.childNodes;
		siblings = new Array();
		for (i=0; i<children.length; i++) {
			if(children[i].style) {
				siblings.push(children[i]);
				if(!children[i].style.zIndex) {children[i].style.zIndex=0;}
			}
		}
		sortByZIndex = function(a,b) {return a.style.zIndex - b.style.zIndex;}
		siblings.sort(sortByZIndex);
		high = siblings[siblings.length-1].style.zIndex;
		low = siblings[0].style.zIndex;
		increment = (high-low)/(siblings.length-1);
		var check = new Array();
		for(i=0; i<siblings.length; i++) {siblings[i].style.zIndex = (increment*i)+eval(low); check.push(siblings[i].style.zIndex);}
		//alert(check);
		var lower = false;
		for(i=0; i<siblings.length; i++) {
			if(lower==true) {siblings[i].style.zIndex = siblings[i].style.zIndex-increment;}
			if(siblings[i]==element) {
				lower = true;
				siblings[i].style.zIndex = increment*(siblings.length-1);
			}
		}
	}			
	document.onselectstart = function() {return false;}
	document.ondragstart = function() {return false;}
	parentWidth = element.parentNode.clientWidth;
	parentHeight = element.parentNode.clientHeight;
	element.style.left = element.offsetLeft+'px';
	element.style.top = element.offsetTop+'px';
	elementWidth = element.offsetWidth;
	elementHeight = element.offsetHeight;
	mouseStartX = evt.clientX;
	mouseStartY = evt.clientY;
	document.onmousemove = function(evt) {
		document.body.style.MozUserSelect = 'none';
		if(window.event) {evt = window.event;}
		document.onmouseup = function() {endDrag();}
		mouseX = evt.clientX;
		mouseY = evt.clientY;
		velX = mouseX - mouseStartX;
		velY = mouseY - mouseStartY;
		mouseStartX = mouseX;
		mouseStartY = mouseY;
		elementX = element.offsetLeft;
		elementY = element.offsetTop;
		if(velX<0 && elementX>0) {
			if((elementX+velX)<0) {newX=0;}
			else {newX = elementX+velX;}
			element.style.left = newX+'px';
		}
		if(velX>0 && (elementX+elementWidth)<parentWidth) {
			if((elementX+elementWidth+velX)>parentWidth) {newX = parentWidth-elementWidth;}
			else {newX = elementX+velX;}
			element.style.left = newX+'px';
		}
		if(velY<0 && elementY>0) {
			if((elementY+velY)<0) {newY=0;}
			else {newY = elementY+velY;}
			element.style.top = newY+'px';
		}
		if(velY>0 && (elementY+elementHeight)<parentHeight) {
			if((elementY+elementHeight+velY)>parentHeight) {newY = parentHeight-elementHeight;}
			else {newY = elementY+velY;}
			element.style.top = newY+'px';
		}
	}
	endDrag = function() {
		document.onmousemove = '';
		document.onselectstart = '';
		document.ondragstart = '';
		document.body.style.MozUserSelect = '';
	}
}




// FIND RELATIVE SCRIPT PATH
// name: NAME OF ANY JAVASCRIPT FILE LOADED IN <HEAD></HEAD>. (Function returns the relative path of the loaded script.)

function scriptPath(name) {
	var head = document.getElementsByTagName('head')[0];
	var scripts = head.getElementsByTagName('script');
	for (i=0; i<scripts.length; i++) {
		source = scripts[i].src;
		if(source.indexOf(name)!=-1) {path = source;}
	}
	var folder = path.replace(name,'');
	var rootPath = window.location.toString();
	var rootFolder = rootPath.slice(0,rootPath.lastIndexOf('/'));
	var path = folder.replace(rootFolder,'');
	if(path.charAt(0)=='/') {path = path.charReplace('/','');}
	return path;
}




// IMAGE SLIDESHOW
// slides_path: RELATIVE FOLDER PATH: required (Relative path to folder where slide images reside.)
// element_id: ANY ELEMENT ID: required (Id of element in which to display slide show.)
// speed: 0 < SPEED ≤ 100 (Speed at which slides are cross-faded. Default is 1.  If set to 0, speed is set to default.)
// time: ANY NUMBER (Time in seconds to display each slide before changing. Default is 3.  If set to 0, time is set to default.)
// shuffle: TRUE OR FALSE (When set to "true", slides are randomly shuffled.  Default is "false".)
// start: FILE NAME OR FALSE (Specify a starting slide.  Default is "false".)
// pause: TRUE OR FALSE (If "true", pauses slideshow onmouseover. Default is "false".)

function slideShow(slides_path,element_id,speed,time,shuffle,start,pause) {
	if(!pause) {pause=false;}
	if(!speed | speed==0) {var speed = 1;}
	if(!time | time==0) {var time=3;}
	time = time*1000;
	if(!shuffle) {var shuffle=false;}
	var element = $(element_id);
	var paused = false;
	if(pause) {
		element.style.cursor = 'pointer';
		var mouseover = function() {
			element.onmouseover = function() {
				var startPause = function() {mouseout(); paused=true; wait();}
				var timeout = setTimeout(startPause,1000);
				element.onmouseout = function() {clearTimeout(timeout);}
			}
		}
		var mouseout = function() {
			element.onmouseout = function() {
				var endPause = function() {mouseover(); paused=false; rotateImages();}
				var timeout = setTimeout(endPause,1000);
				element.onmouseover = function() {clearTimeout(timeout);}
			}
		}
		var wait = function() {if(paused==true) {setTimeout(wait);}}
		mouseover();
	}
	var relPath = scriptPath('application.js');
	var dirSplit = relPath.split('/');
	var dirs = new Array();
	for(i=0; i<dirSplit.length; i++) {if(dirSplit[i]!='') {dirs.push(dirSplit[i]);}}
	var upDirs = '';
	for (i=0; i<dirs.length; i++) {upDirs+='../';}
	var the_script = relPath+'list_files.php?path='+encodeURIComponent(slides_path)+'&upDirs='+encodeURIComponent(upDirs);
	var files = eval(ajax_request(the_script,false));
	if(shuffle) {files = files.shuffle();}
	if(start) {
		for(i=0; i<files.length; i++) {
			if(files[i]==start) {files.splice(i,1);}
		}
		files.unshift(start);
	}
	var images = new Array();
	element.style.position = 'relative';
	for (i=0; i<files.length; i++) {
		var image = new Image();
		image.style.display = 'none';
		image.style.position = 'absolute';
		image.style.width = element.style.width;
		image.style.height = element.style.height;
		image.src = slides_path+files[i];
		image.style.zIndex = 0;
		images.push(image);
		element.appendChild(image);
	}
	var div = document.createElement('div');
	div.style.clear = 'both';
	div.style.width = '100%';
	element.appendChild(div);
	var startIndex = 0;
	var image1 = images[startIndex];
	startIndex++;
	if(startIndex>images.length-1) {startIndex=0;}
	var image2 = images[startIndex];
	var rotateImages = function() {
		var func = function() {
			image1 = images[startIndex];
			startIndex++;
			if(startIndex>images.length-1) {startIndex=0;}
			image2 = images[startIndex];
			setTimeout(rotateImages,time);
		}
		if(paused==false) {
			image1.style.zIndex = 0;
			image2.style.zIndex = 1;
			fade(image1,0,speed,false);
			fade(image2,0,speed,false,'block',func);
		}
	}
	var func = function() {
		setTimeout(rotateImages,time);
	}
	image1.style.zIndex = 1;
	fade(image1,0,speed,false,'block',func);
}




// AJAX REQUEST
// theScript: RELATIVE PHP FILE PATH: required (Relative path to php script to be executed, including GET variables.)
// sync: TRUE OR FALSE (Indicate whether or not the call is assynchronous. Default is false.)
// callback: ANY JAVASCRIPT FUNCTION (Function to be executed after call is finished.)

function ajax_request(theScript,sync,callback) {
	if(!sync) {sync=false;}
	var GetXmlHttpObject = function() {
		if (window.XMLHttpRequest) {
  			// code for IE7+, Firefox, Chrome, Opera, Safari
 			return new XMLHttpRequest();
 		}
		else if (window.ActiveXObject) {
  			// code for IE6, IE5
  			return new ActiveXObject("Microsoft.XMLHTTP");
  		}
  	}
	var xmlhttp;
	xmlhttp = GetXmlHttpObject();
	if (xmlhttp==null) {alert("Your browser does not support XMLHTTP!");}
	if (sync == true) {
		xmlhttp.onreadystatechange=function() {
			if(xmlhttp.readyState == 4) {
				script_response = xmlhttp.responseText;
				if(callback) {callback(script_response);}
				else {return script_response;}
			}
		}
	}
	xmlhttp.open("GET",theScript,sync);
	xmlhttp.send(null);
	if (sync == false) {return xmlhttp.responseText;}
}




// TEXT AREA RESIZE
// margin: INTEGTER (Margin to be added to height of textarea after resize.)

function textAreaResize(element,margin) {
	if(!margin) {margin=5;}
	var borderHeight = parseInt(element.style.borderTopWidth)+parseInt(element.style.borderBottomWidth);
	if(!borderHeight) {borderHeight = 2;}
	if(!element.resizeInit) {
		element.style.height = eval(element.offsetHeight-borderHeight)+'px';
		element.resizeInit = true;
	}
	else {
		element.style.height = '0px';
		if(eval(element.offsetHeight-borderHeight)<element.scrollHeight) {
			element.style.height = element.scrollHeight+margin+'px';
		}
	}
}




// SWAP IMAGE
// changes <img> source to given image (usefull for rollover effects)

function swap(element,image) {
	var def = element.src;
	element.onmouseout = function() {
		element.src = def;
	}
	element.onclick = function() {
		element.src = def;
	}
	element.src = image;
}




// VALIDATE EMAIL ADDRESS
// returns true is email is valid, false if it is invalid

function validate_email(email) {
	pattern = /^[\w\.]+@([\w]+\.)+[a-z]{1,5}$/;
	if(email.match(pattern) == null) {return false;}
	else {return true;}
}
