var gAnimationStack 				= new Array();
var isWindows						= (navigator.userAgent.indexOf("Windows") >= 0);
var isLinux							= (navigator.userAgent.indexOf("Linux") >= 0);
var isMac							= (navigator.userAgent.indexOf("Mac") >= 0);
var isIE 							= (document.all && !window.opera ? true : false);
var isFirefox						= (navigator.userAgent.indexOf("Firefox") >= 0);
var isOpera 						= (window.opera ? true : false);
var isSafari						= (navigator.userAgent.indexOf("Safari") >= 0);
var isCamino						= (navigator.userAgent.indexOf("Camino") >= 0);
var isKonquerer						= (navigator.appName == "Konquerer");
var ieVersion						= -1;

if (isIE){
	var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
	
	if (re.exec(navigator.userAgent) != null){
		ieVersion = parseFloat(RegExp.$1);
	}
}


/* *********** Form Functions *********** */
// IfEmpty
function errorIfEmpty(id, errorMsg){
	return errorIfEmptyV(document.getElementById(id).value, errorMsg);
}


function errorIfEmptyV(value, errorMsg){
	if (isEmptyV(value)){
		return errorMsg;
	} else {
		return "";
	}
}


function isEmpty(id){
	return isEmptyV(document.getElementById(id).value);
}


function isEmptyV(value){
	if (value.length == 0){
		return true;
	} else {
		return false;
	}
}


// IfLessThen
function errorIfLessThan(id, length, errorMsg){
	return errorIfLessThanV(document.getElementById(id).value, length, errorMsg);
}


function errorIfLessThanV(value, length, errorMsg){
	if (isLessThanV(value, length)){
		return errorMsg;
	} else {
		return "";
	}
}


function isLessThan(id, length){
	return isLessThanV(document.getElementById(id).value, length);
}


function isLessThanV(value, length){
	if (value.length < length){
		return true;
	} else {
		return false;
	}
}


// IfNotEqualTo
function errorIfNotEqual(id1, id2, errorMsg){
	return errorIfNotEqualV(document.getElementById(id1).value, document.getElementById(id2).value, errorMsg);
}


function errorIfNotEqualV(value1, value2, errorMsg){
	if (value1 == value2){
		return "";
	} else {
		return errorMsg;
	}
}


// IfEqualTo
function errorIfEqual(id1, id2, errorMsg){
	return errorIfEqualV(document.getElementById(id1).value, document.getElementById(id2).value, errorMsg);
}


function errorIfEqualV(value1, value2, errorMsg){
	if (value1 == value2){
		return errorMsg;
	} else {
		return "";
	}
}


// IfEqual
function isEqual(id1, id2){
	return isEqualV(document.getElementById(id1).value, document.getElementById(id2).value);
}


function isEqualV(value1, value2){
	if (value1 == value2){
		return true;
	} else {
		return false;
	}
}


// IfNotValidEmail
function errorIfNotValidEmail(id, errorMsg){
	return errorIfNotValidEmailV(document.getElementById(id).value, errorMsg);
}


function errorIfNotValidEmailV(value, errorMsg){
	if (isValidEmail(value)){
		return "";
	} else {
		return errorMsg;
	}
}


function isChecked(id){
	return document.getElementById(id).checked;
}


function formatErrorMessage(errorMsg){
	var errors = errorMsg.split("|");
	var output = "<ul class=\"error-list\">";
	
	for (var i = 0; i < errors.length - 1; i++){
		output += "<li>" + errors[i] + "</li>";
	}
	
	output += "</ul>";
	
	if (errors.length == 0){
		return "";
	} else {
		return output;
	}
}


// ---------- Misc functions ----------
function isValidEmail(email){
	var re = new RegExp("^([-!#\$%&'*+./0-9=?A-Z^_`a-z{|}~])+@([-!#\$%&'*+/0-9=?A-Z^_`a-z{|}~]+\\.)+[a-zA-Z]{2,6}\$","i");  
	
	return re.test(email);
}


function selectOption(list){
	document.getElementById(list).checked = true;
}


function getSelectValue(element){
	if (element.selectedIndex != -1){
		return element.options[element.selectedIndex].value;
	} else {
		return null;	// Nothing selected
	}
}


// Returns a URL encoded string of the select's selected values
function getSelectValuesEncodedForURL(id){
	var select = document.getElementById(id);
	var encodedName = encodeURIComponent(select.name);
	var querystring = "";
	
	if (select.selectedIndex != -1){
		for (var i = 0; i < select.options.length; i++){
			if (select.options[i].selected){
				querystring += encodedName + "=" + encodeURIComponent(select.options[i].value) + "&";
			}
		}
		
		querystring = querystring.substr(0, querystring.length - 1);
	}
	
	return querystring;
}


function setListboxValue(listId, selectedValue){
	var select = document.getElementById(listId);
	
	for (var i = 0; i < select.options.length; i++){
		if (select.options[i].value == selectedValue){
			select.options[i].selected = true;
		} else {
			select.options[i].selected = false;
		}
	}
}


// Returns a URL encoded string of the textbox's value
function getTextboxValueEncodedForURL(id){
	var querystring = "";
	var textbox = document.getElementById(id);
	
	querystring = encodeURIComponent(textbox.name) + "=" + encodeURIComponent(textbox.value);
	
	return querystring;
}


function getCheckboxValueEncodedForURL(id){
	var querystring = "";
	var checkbox = document.getElementById(id);
	
	if (checkbox.checked){
		querystring = encodeURIComponent(checkbox.name) + "=" + encodeURIComponent(checkbox.value);
	} else {
		querystring = "";
	}
	
	return querystring;
}



function contactLinkClicked(event){
	event.preventDefault();
	event.stopPropagation();
	
	var userId = '';
	var parameters = this.toString().split("?");
	
	if (parameters.length > 1){
		var pairs = parameters[parameters.length - 1].split("&");
		
		for (var i = 0; i < pairs.length; i++){
			var pair = pairs[i].split("=");
			
			if (pair.length > 1){
				if (pair[0] == 'to'){
					userId = pair[1];
					break;
				}
			}
		}
	}
	 
	openContactWindow(userId);
}


function openContactWindow(userId){
	openCenteredWindow("/contact/index.php?to=" + userId + "&popupmode=1", "contactPopup", "directories=no,location=no,resizable=yes,menubar=no,toolbar=no,scrollbars=yes,status=no", 640, 680);
}


function openCenteredWindow(url, name, options, width, height){
	var left = (screen.width  - width) / 2;
	var top = (screen.height - height) / 2;
	
	return openWindow(url, name, 'left=' + left + ',top=' + top + ',width=' + width + ',height=' + height + (options.length ? ',' + options : ''));
}


/*
directories no		should the directories bar be shown? (Links bar)
location	no		specifies the presence of the location bar
resizable	no		specifies whether the window can be resized.
menubar		no		specifies the presence of the menu bar
toolbar		no		specifies the presence of the toolbar
scrollbars	no		specifies the presence of the scrollbars
status 		no		specifies the presence of the statusbar
*/

function openWindow(url, name, options){
	var popupWindow  = window.open(url, name, options);
	
	popupWindow.focus();
	
	return popupWindow;
}


// Animates the opening/closing of the error message box
// If animate is false, it does the fallback animation (instant)
// callback is optional, if provided, callback will be invoked when the animation has ended
// duration is optional, defaults to 350
function animateBox(element, expanding, animate, duration, callback){
	// Browser FX whitelist
	if ((
		(isWindows && ((isIE && ieVersion >= 6.0) || isFirefox || isOpera)) ||
		(isLinux && (isFirefox)) ||
		(isMac && (isOpera))
		) && animate
	){
		// Do fancy animation
		if (gAnimationStack[element.id] != null){
			// Reverse the direction of the current animation
			var animate 			= gAnimationStack[element.id];
			var time 				= new Date().getTime();
			
			animate.percent			= 1 - animate.percent;
			animate.endTime			= time + animate.duration;
			animate.startTime 		= (animate.percent * animate.endTime - time) / (animate.percent - 1);
			animate.expanding 		= expanding;
			animate.currentFrame 	= 1;
		} else {
			// Starting a new animation
			element.style.display = "block";
			
			var animate 			= new animateStackItem();
			animate.element 		= element;
			animate.expanding 		= expanding;
			animate.startTime 		= new Date().getTime();
			animate.duration		= (typeof(duration) == "number" ? duration : 350);
			animate.height			= getElementHeight(element);
			animate.callback		= (typeof(callback) == "function" ? callback : null);
			animate.intervalID 		= window.setInterval("animateBoxStep('" + element.id + "')", 33);	// Limits animation to 30 fps
	
			gAnimationStack[element.id] = animate;
		}
	} else {
		// Do simple animation
		element.style.display = (expanding ? "block" : "none");
		element.style.overflow = "visible";
		element.style.height = "auto";

		if (typeof(callback) == "function"){
			callback();
		}
	}
}


// This is called on every loop of the animation by window.setInterval()
function animateBoxStep(elementID){
	var time 	= new Date().getTime();
	var animate = gAnimationStack[elementID];
	
	if (animate.currentFrame == 0){
		animate.frameLength = 1000 / animate.fps;
		animate.lastTime 	= time - animate.frameLength;
		animate.endTime 	= animate.startTime + animate.duration;
	}
	
	if (time >= animate.endTime){
		// End animation
		animate.element.style.height = (animate.expanding ? animate.height : 0) + "px";
		animate.element.style.overflow = (animate.expanding ? "visible" : "hidden");
	    setElementOpacity(animate.element, (animate.expanding ? 1 : 0));
		
		window.clearInterval(animate.intervalID);
		delete gAnimationStack[elementID];

		if (typeof(animate.callback) == "function"){
			animate.callback();
		}
	} else {
		// Check if it time to render another frame
		if (animate.lastTime + animate.frameLength <= time){
			animate.percent = (time - animate.startTime) / (animate.endTime - animate.startTime);	// Percent of animation progress

			var percent = (animate.expanding ? animate.percent : (1 - animate.percent));			// Reverses percent if we are going in the other direction

			animate.element.style.overflow = "hidden";
			animate.element.style.height = (Math.sin(percent * Math.PI / 2) * animate.height) + "px";	// Smoothly animate motion
			setElementOpacity(animate.element, percent);
			animate.lastTime = time;
			animate.currentFrame++;
		}
	}
}


// element is a DOM node
function getElementHeight(element){
	if (getCurrentStyle(element, "overflow") == "visible"){
		// The item is already at full height
		return element.offsetHeight;
	} else {
		// The item is currently collapsed, need to temporarily expand it to get its full height
		element.style.visibility 	= "hidden";
		element.style.position 		= "absolute";
		element.style.overflow		= "visible";
		element.style.height		= "auto";
		
		var offsetHeight = element.offsetHeight;
	
		element.style.height		= "0";
		element.style.overflow		= "hidden";
		element.style.position 		= "relative";
		element.style.visibility 	= "visible";

		return offsetHeight;
	}
}


function animateStackItem(){
	this.element 		= null;
	this.expanding 		= null;
	this.callback		= null;
	this.intervalID 	= 0;
	this.startTime 		= 0;	// Time animation started
	this.endTime 		= 0;	// Time animation will end
	this.lastTime		= 0;	// The last time a frame was actually rendered
	this.percent		= 0;	// Percent of animation complete (time-wise)
	this.duration		= 0;	// Length of time the animation will last
	this.currentFrame 	= 0;	// Counts frames rendered
	this.height			= 0;
	this.fps			= 30;	// Frames per second
	this.frameLength	= 0;	// Milliseconds per frame
}


// element is a DOM element, opacity is a 0 to 1 float value
function setElementOpacity(element, opacity){
	if (isIE){
	    element.style.filter 		= "alpha(opacity=" + (opacity * 100) + ")";	// Internet Explorer
	} else {
	    element.style.opacity 		= opacity;	// CSS3 compliant browsers (Opera 9)
	    element.style.MozOpacity 	= opacity;	// Mozilla/FF
	    element.style.KhtmlOpacity 	= opacity;	// Konquerer/Safari
	}
}


// Returns the style of an element not explicit set via CSS or javascript
// element is a DOM element
// property is a string, with the name of the CSS property to return
// Supported by IE, Opera 7+, Mozilla, iCab 3+ and Konqueror 3.5+
function getCurrentStyle(element, property){
	if (element.currentStyle){
		return eval("element.currentStyle." + property);
	} else if (window.getComputedStyle){
		return eval("window.getComputedStyle(element, null)." + property);
	}
	
	return "";
}


// Closes the box if needed, then changes it's class, and re-opens it
function setFormMessage(boxId, messageId, expanded, animate, className, content, callback){
	var boxElement = document.getElementById(boxId);
	var messageElement = document.getElementById(messageId);
	
	if (boxElement.style.display == "block" && animate){
		animateBox(boxElement, false, animate, null, function (){
			boxElement.className = className
			messageElement.innerHTML = content;
			animateBox(boxElement, expanded, true, null, callback);
		});
	} else {
		boxElement.className = className
		messageElement.innerHTML = content;
		animateBox(boxElement, expanded, animate, null, callback);
	}
}


// content should be URL encoded and look like a querystring
// callbacks are all optional, the xmlhttprequest object is provided as a parameter when they are called
// onFailureCallback is when a comm/server error has occured, not with the form validation (since it doesn't do any)
function ajaxPost(url, content, onSuccessCallback, onFailureCallback, onReadyStateChange){
	var xmlhttp = new XMLHttpRequest();		// XMLHttpRequest is browser neutralized by Sarissa

	xmlhttp.open("POST", url, true);
	xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	xmlhttp.onreadystatechange = function() {
									if (typeof(onReadyStateChange) == "function"){
										onReadyStateChange(xmlhttp);
									}

									if (xmlhttp.readyState == 4) {
										if (xmlhttp.status == 200){
											if (typeof(onSuccessCallback) == "function"){
												onSuccessCallback(xmlhttp);
											}
										} else {
											if (typeof(onFailureCallback) == "function"){
												onFailureCallback(xmlhttp);
											}
										}
									}
	}
	
	xmlhttp.send('ajax=1' + (content ? '&' +content : ''));
//	delete xmlhttp;
}

function print_r(array) {
    // http://kevin.vanzonneveld.net
    // +   original by: Michael White (http://getsprink.com)
    // +   improved by: Ben Bryan
    // *     example 1: print_r(1, true);
    // *     returns 1: 1
    
    var output = "", pad_char = " ", pad_val = 4;
 
    var formatArray = function (obj, cur_depth, pad_val, pad_char) {
        if (cur_depth > 0) {
            cur_depth++;
        }
 
        var base_pad = repeat_char(pad_val*cur_depth, pad_char);
        var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char);
        var str = "";
 
        if (obj instanceof Array || obj instanceof Object) {
            str += "Array\n" + base_pad + "(\n";
            for (var key in obj) {
                if (obj[key] instanceof Array) {
                    str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char);
                } else {
                    str += thick_pad + "["+key+"] => " + obj[key] + "\n";
                }
            }
            str += base_pad + ")\n";
        } else if(obj == null || obj == undefined) {
            str = '';
        } else {
            str = obj.toString();
        }
 
        return str;
    };
 
    var repeat_char = function (len, pad_char) {
        var str = "";
        for(var i=0; i < len; i++) { 
            str += pad_char; 
        };
        return str;
    };
    output = formatArray(array, 0, pad_val, pad_char);
 
    return output;
}

