/* ------------------------------ DETECTION ------------------------------ */

function browserDetect() {
	var agent 		= navigator.userAgent.toLowerCase();
	
	// detect platform
	this.isMac		= (agent.indexOf('mac') != -1);
	this.isWin		= (agent.indexOf('win') != -1);
	this.isWin2k	= (this.isWin && (
			agent.indexOf('nt 5') != -1));
	this.isWinSP2	= (this.isWin && (
			agent.indexOf('xp') != -1 || 
			agent.indexOf('sv1') != -1));
	this.isOther	= (
			agent.indexOf('unix') != -1 || 
			agent.indexOf('sunos') != -1 || 
			agent.indexOf('bsd') != -1 ||
			agent.indexOf('x11') != -1 || 
			agent.indexOf('linux') != -1);
	
	// detect browser
	this.isSafari	= (agent.indexOf('safari') != -1);
	this.isSafari2 	= (this.isSafari && (parseFloat(agent.substring(agent.indexOf("applewebkit/")+"applewebkit/".length,agent.length).substring(0,agent.substring(agent.indexOf("applewebkit/")+"applewebkit/".length,agent.length).indexOf(' '))) >=  300));
	this.isOpera	= (agent.indexOf('opera') != -1);
	this.isNN		= (agent.indexOf('netscape') != -1);
	this.isIE		= (agent.indexOf('msie') != -1);
	this.isFirefox	= (agent.indexOf('firefox') != -1);
}
var browser = new browserDetect();

/* ------------------------------ AJAX ------------------------------ */

function createAjaxObj() {
	// alert("createAjaxObj()");
	
	var reqObj = false;
	
	if (window.XMLHttpRequest) {
		// If Mozilla, Safari etc
		reqObj = new XMLHttpRequest();
		if (reqObj.overrideMimeType) {
			reqObj.overrideMimeType('text/xml');
		}
	} else {
		if (window.ActiveXObject) {
			// If IE
			var aXmlHttpVersions = ["Msxml2.XMLHTTP.7.0", "Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];

			for (var i = 0; i < aXmlHttpVersions.length; i++) {
				try {
					reqObj = new ActiveXObject(aXmlHttpVersions[i]);
					if (reqObj) {
						break;
					}
				}
				catch (objException) {
					// Catch object exception errors so they don't display to the user...
				}
			}
		}
	}
	return reqObj;
}

function newAjaxObject() {
	var ajaxObj = new Object();
	
	ajaxObj.basedomain = "http://" + window.location.hostname;
	ajaxObj.reqObj = createAjaxObj();
	ajaxObj.filetype = "txt";
	ajaxObj.addrandomnumber = 0; // Set to 1 or 0. See documentation.
	
	ajaxObj.getAjaxRequest = function(url, parameters, callbackfunc, filetype, callbackargs) {
		
		ajaxObj.reqObj = createAjaxObj(); // Recreate ajax object to defeat cache problem in IE
		
		if (ajaxObj.addrandomnumber == 1) { // Further defeat caching problem in IE?
			var parameters = parameters + "&ajaxcachebust=" + new Date().getTime();
		}
		
		if (this.reqObj) {
			this.filetype = filetype;
			this.callbackargs = callbackargs;
			this.reqObj.onreadystatechange = function() {
				callbackfunc(ajaxObj);
			}
			if (parameters == '') {
			    this.reqObj.open('GET', url, true);
			} else {
			    if (url.indexOf("?") == -1) {
			        url = url + "?";
			    }
			    this.reqObj.open('GET', url + parameters, true);
			}
			this.reqObj.send(null);
		}
	};
	
	ajaxObj.postAjaxRequest = function(url, parameters, callbackfunc, filetype, callbackargs) {
		ajaxObj.reqObj = createAjaxObj(); // Recreate ajax object to defeat cache problem in IE
		
		if (this.reqObj) {
			this.filetype = filetype;
			this.callbackargs = callbackargs;
			this.reqObj.onreadystatechange = function() {
				callbackfunc(ajaxObj);
			}
			this.reqObj.open('POST', url, true);
			this.reqObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			this.reqObj.setRequestHeader("Content-length", parameters.length);
			this.reqObj.setRequestHeader("Connection", "close");
			this.reqObj.send(parameters);
		}
	};
	
	return( ajaxObj );
}

/* ------------------------------ XML PARSING ------------------------------ */

function getElementTextNS(prefix, local, parentElem, index) {
	/**
	* Explorer for Windows (at least through Version 6) does not implement the DOM 
	* getElementsByTagNameNS() function. Instead it treats namespace tag names literally. 
	* For example, the <content:encoded> element is treated as an element whose tag name 
	* is content:encoded, rather than a tag whose local name is encoded and whose 
	* prefix is content.
	*/
	var result = "";
	if (prefix && browser.isIE) {
		result = parentElem.getElementsByTagName(prefix + ":" + local)[index];
	} else {
		result = parentElem.getElementsByTagName(local)[index];
	}
	if (result) {
		if (result.childNodes.length > 1) {
			return result.childNodes[1].nodeValue;
		} else {
			return result.firstChild.nodeValue;
		}
	} else {
		return "";
	}
}

/* ------------------------------ EVENT HOOKS ------------------------------ */

/**
* Attach event listener to page load
*
* Example:
* addLoadListener(tooltipInit);
*
* @param	functionRef		function	function reference
* @return	--				null		nothing
*/
function addLoadListener(functionRef) {
	if (typeof window.addEventListener != 'undefined') {
		window.addEventListener('load', functionRef, false);
	} else if (typeof document.addEventListener != 'undefined') {
		document.addEventListener('load', functionRef, false);
	} else if (typeof window.attachEvent != 'undefined') {
		window.attachEvent('onload', functionRef);
	} else {
		var oldFunction = window.onload;
		if (typeof window.onload != 'function') {
			window.onload = functionRef;
		} else {
			window.onload = function() {
				oldFunction();
				functionRef();
			};
		}
	}
}

/**
* Attach event listener
*
* Example:
* var a = document.getElementsByTagName('a')[0];
* attachEventListener(a, 'click', toggleMenuClick, false);
*
* @param	target			element		target element
* @param	eventType		string		event to hook
* @param	functionRef		function	function reference
* @param	capture			boolean		capture the event (so no bubbling occurs)
* @return	--				boolean		true
*/
function attachEventListener(target, eventType, functionRef, capture) {    
	if (typeof target.addEventListener != "undefined") {
		target.addEventListener(eventType, functionRef, capture);
	} else if (typeof target.attachEvent != "undefined") {
		target.attachEvent("on" + eventType, functionRef);
	} else {
		eventType = "on" + eventType;
		if (typeof target[eventType] == "function") {
			var oldListener = target[eventType];
			target[eventType] = function() {
				oldListener();
				return functionRef();
			};
		} else {
			target[eventType] = functionRef;
		}
	}	
	return true;	
}

/**
* Detach event listener
*
* @param	target			element		target element
* @param	eventType		string		event to hook
* @param	functionRef		function	function reference
* @param	capture			boolean		capture the event (so no bubbling occurs)
* @return	--				boolean		true
*/
function detachEventListener(target, eventType, functionRef, capture) {
	if (typeof target.removeEventListener != "undefined") {
		target.removeEventListener(eventType, functionRef, capture);
	} else if (typeof target.detachEvent != "undefined") {
		target.detachEvent("on" + eventType, functionRef);
	} else {
		target["on" + eventType] = null;
	}
	return true;
}

/**
* Get target object
*
* Example:
* var target = getEventTarget(event);
* while (target.nodeName.toLowerCase() != "a") { target = target.parentNode; }
*
* Example:
* var target = getEventTarget(event);
* while (target.className == null || !/(^| )hastooltip( |$)/.test(target.className)) { target = target.parentNode; }
*
* @param	event			object		event reference
* @return	--				element		target element
*/
function getEventTarget(event) {
  var targetElement = null;

  if (typeof event.target != "undefined") {
    targetElement = event.target;
  } else {
    targetElement = event.srcElement;
  }

  while (targetElement.nodeType == 3 && targetElement.parentNode != null) {
    targetElement = targetElement.parentNode;
  }

  return targetElement;
}

/* ------------------------------ DOM ------------------------------ */

/**
* Return array of element with matching attributes and values.
*
* Example:
* var tips = getElementsByAttribute("class", "hastooltip");
*
* @param	attribute		string		attribute
* @param	attributeValue	value		attribute value
* @param	target			element		target element
* @return	--				array		matched element array
*/
function getElementsByAttribute(attribute, attributeValue, target) {
	var elementArray = new Array();
	var matchedArray = new Array();
	
	if (target == null) {
		if (document.all) {
			elementArray = document.all;
		} else {
			elementArray = document.getElementsByTagName("*");
		}
	} else {
		if (target.all) {
			elementArray = target.all;
		} else {
			elementArray = target.getElementsByTagName("*");
		}
	}

	for (var i = 0; i < elementArray.length; i++) {
		if (attribute == "class") {
			var pattern = new RegExp("(^| )" + attributeValue + "( |$)");

			if (elementArray[i].className.match(pattern))
			{
				matchedArray[matchedArray.length] = elementArray[i];
			}
		} else if (attribute == "for") {
			if (elementArray[i].getAttribute("htmlFor") || elementArray[i].getAttribute("for"))
			{
				if (elementArray[i].htmlFor == attributeValue)
				{
					matchedArray[matchedArray.length] = elementArray[i];
				}
			}
		} else if (elementArray[i].getAttribute(attribute) == attributeValue) {
			matchedArray[matchedArray.length] = elementArray[i];
		}
	}

	return matchedArray;
}

/**
* Return the size of the viewport.
*
* Example:
* var viewportSize = getViewportSize();
*
* @return	--				array		the size of the viewport
*/
function getViewportSize() {
	var size = {
		'width': 0,
		'height': 0
	};

	if (typeof window.innerWidth != 'undefined') {
		size = {
			'width': window.innerWidth,
			'height': window.innerHeight
		};
	}
	else if (typeof document.documentElement != 'undefined'
			&& typeof document.documentElement.clientWidth != 'undefined'
			&& document.documentElement.clientWidth != 0) {
		size = {
			'width': document.documentElement.clientWidth,
			'height': document.documentElement.clientHeight
		};
	}
	else {
		size = {
			'width': document.getElementsByTagName('body')[0].clientWidth,
			'height': document.getElementsByTagName('body')[0].clientHeight
		};
	}

	return size;
}

/**
* Return the scrolling position of the page.
*
* Example:
* var scrollingPosition = getScrollingPosition();
*
* @return	--				array		the position of the page
*/
function getScrollingPosition() {
	//array for X and Y scroll position
	var position = {
		'x': 0,
		'y': 0
	};
	
	// if the window.pageYOffset property is supported
	if (typeof window.pageYOffset != 'undefined') {
		//store position values
		position = {
			'x': window.pageXOffset,
			'y': window.pageYOffset
		};
	}

	// if the documentElement.scrollTop property is supported
	// and the value is greater than zero
	else if (typeof document.documentElement.scrollTop != 'undefined'
		&& document.documentElement.scrollTop > 0) {
		//store position values
		position = {
			'x': document.documentElement.scrollLeft,
			'y': document.documentElement.scrollTop
		};
	}

	// if the body.scrollTop property is supported
	else if(typeof document.body.scrollTop != 'undefined') {
		//store position values
		position = {
			'x': document.body.scrollLeft,
			'y': document.body.scrollTop
		};
	}

	//return the array
	return position;
}

/**
* Return the size and position of an element.
*
* Example:
* var coords = getCoordinates(subnav_div);
* subnav_div.style.marginTop = (coords['height'] * -1.0) + "px";
* subnav_div.style['display'] = 'none';
*
* @param	element			element		target element
* @return	--				object		the elements coordinates
*/
function getCoordinates(element){
	var obj = {
		'width': element.offsetWidth,
		'height': element.offsetHeight,
		'left': element.offsetLeft,
		'top': element.offsetTop
	};
	obj.right = obj.left + obj.width;
	obj.bottom = obj.top + obj.height;
	return obj;
}


/**
* Set the opacity of an element.
*
* Example:
* setOpacity(tip, 0);
*
* @param	element			element		target element
* @param	opacity			number		opacity (0 to 1)
* @return	--				null		nothing
*/
function setOpacity(element, opacity){
	if (opacity == 0) {
		if (element.style.visibility != "hidden") element.style.visibility = "hidden";
	} else {
		if (element.style.visibility != "visible") element.style.visibility = "visible";
	}
	// if (!this.currentStyle || !this.currentStyle.hasLayout) this.style.zoom = 1;
	if (browser.isIE) {
		element.style.filter = "alpha(opacity=" + opacity*100 + ")";
	}
	element.style.opacity = element.opacity = opacity;
	// element.style.KHTMLOpacity, element.style.MozOpacity
}

/* ------------------------------ TOOL TIP ------------------------------ */

function tooltipInit() {
	var tips = getElementsByAttribute("class", "vote_link");
	
	for (var i = 0; i < tips.length; i++) {
		attachEventListener(tips[i], "onclick", showTip, false);
		// attachEventListener(tips[i], "mouseout", hideTip, false);
	}

	return true;
}

/* ------------------------------ MOUSE EVENTS ------------------------------ */

function showTip(event) {
	
	// Get target element
	if (typeof event == "undefined") {
		event = window.event;
	}
	
	var target = getEventTarget(event);
	while (target.className == null || !/(^| )hastooltip( |$)/.test(target.className)) {
		target = target.parentNode;
	}

	// Create tooltip HTML
	var tip = document.createElement("div");
	var content = target.getAttribute("title");
	
	if (content == null) {
		var arr = getElementsByAttribute("class", "tooltipdata", target);
		if (arr.length > 0) {
			content = arr[0].cloneNode(true);
		}
	}
	
	if (content == null) {
		return;
	}
	
	target.tooltip = tip;
	
	if (typeof content == "string") {
		target.setAttribute("title", "");
	}
	
	if (target.getAttribute("id") != "") {
		tip.setAttribute("id", target.getAttribute("id") + "tooltip");
	}
	tip.className = "tooltip_down";
	
	// Toolip top
	var tipTop = document.createElement("div");
	tipTop.className = "top";
	tip.appendChild(tipTop);
	
	// Toolip fill
	var tipFill = document.createElement("div");
	tipFill.className = "fill";
	if (typeof content == "string") {
		tipFill.appendChild(document.createTextNode(content));
	} else {
		tipFill.appendChild(content);
	}
	tip.appendChild(tipFill);
	
	// Toolip bottom
	var tipBottom = document.createElement("div");
	tipBottom.className = "bottom";
	tip.appendChild(tipBottom);
	
	// Initial position
	var scrollingPosition = getScrollingPosition();
	var cursorPosition = { 'x': 0, 'y': 0 }
	if (typeof event.pageX != "undefined" && typeof event.x != "undefined") {
		cursorPosition['x'] = event.pageX;
		cursorPosition['y'] = event.pageY;
	} else {
		cursorPosition['x'] = event.clientX + scrollingPosition['x'];
		cursorPosition['y'] = event.clientY + scrollingPosition['y'];
	}
	
	tip.style.position = "absolute";
	tip.style.left = "0px";
	tip.style.top = "0px";
	tip.style.visibility = "hidden";
	
	// Attach tooltip to DOM
	var tipDiv = document.getElementsByTagName("body")[0].appendChild(tip);
	
	// Reposition
	var tipCoords = getCoordinates(tip);
	var viewportSize = getViewportSize();
	
	var halign = "center";
	var valign = "top";
	var x = cursorPosition['x'] - tipCoords['width'] * .5 + "px";
	var y = cursorPosition['y'] - tipCoords['height'] - 10 + "px";
	
	// Left and right bounds
	if (cursorPosition['x'] - scrollingPosition['x'] + (tipCoords['width'] * .5) > viewportSize['width'] - 25) {
		halign = "left";
		x = scrollingPosition['x'] + viewportSize['width'] - 25 - tipCoords['width'];
	} else if (cursorPosition['x'] - scrollingPosition['x'] - (tipCoords['width'] * .5) < 10) {
		halign = "right";
		x = scrollingPosition['x'] + 10;
	} else {
		halign = "center";
		x = cursorPosition['x'] - tipCoords['width'] * .5;
	}
	
	// Top and bottom bounds
	if (cursorPosition['y'] - scrollingPosition['y'] - tipCoords['height'] < 10) {
		valign = "bottom";
		y = cursorPosition['y'] + 20;
		tip.className = "tooltip_up";
	} else {
		valign = "top";
		y = cursorPosition['y'] - tipCoords['height'] - 10;
	}
	
	tip.style.left = x + "px";
	if (valign == "top") {
		var ystart = y - 200;
	} else {
		var ystart = y + 200;
	}	
	tip.style.top = ystart + "px";
	
	doSlide(tip,'top',ystart,y,30,20);
	
	setOpacity(tip, 0);
	tip.style.visibility = "visible";

	return true;
}

function hideTip(event) {
	if (typeof event == "undefined") {
		event = window.event;
	}

	var target = getEventTarget(event);

	while (target.className == null || !target.className.match(/(^| )hastooltip( |$)/)) {
		target = target.parentNode;
	}

	if (target.tooltip != null) {
		var arr = getElementsByAttribute("class", "tooltipdata", target.tooltip);
		if (arr.length > 0) {
			// Don't reset title...
		} else {
			target.setAttribute("title", target.tooltip.childNodes[1].childNodes[0].nodeValue);		
		}
		target.tooltip.parentNode.removeChild(target.tooltip);
	}

	return false;
}

/* ------------------------------ CLICK EVENTS ------------------------------ */

/* ------------------------------ ANIMATION ------------------------------ */

// SMOOTH
function easeInOut(t, b, c, d) {
	// t = time
	// d = duration
	// c = change
	// b = begin
	if ((t/=d/2) < 1) {
		return c/2 * t * t + b;
	} else {
		return -c/2 * ((--t)*(t-2) - 1) + b;
	}
}

// BOUNCE
function easeOut(t, b, c, d) {
	if ((t/=d) < (1/2.75)) {
		return c*(7.5625*t*t) + b;
	} else if (t < (2/2.75)) {
		return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
	} else if (t < (2.5/2.75)) {
		return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
	} else {
		return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
	}
}
/*
function easeIn (t, b, c, d) {
	return c - easeOut (d-t, 0, c, d) + b;
}
function easeInOut (t, b, c, d) {
	if (t < d/2) return easeIn (t*2, 0, c, d) * .5 + b;
	else return easeOut (t*2-d, 0, c, d) * .5 + c*.5 + b;
}
*/

function doSlide(element,attribute,startValue,endValue,steps,intervals) {
	// doScrollDiv(categoriesnew,categoriesnew.scrollLeft,(targetLevel-3) * 194,10,35);
	
	if (element.valueChangeInterval) {
		window.clearInterval(element.valueChangeInterval);
	}
	
	var actStep = 0;
	element.valueChangeInterval = window.setInterval(
		function() {
			element.currentValue = easeOut(actStep,startValue,endValue-startValue,steps);
			element.style[attribute] = element.currentValue + "px";
			if (actStep<15) {
				var alpha = easeInOut(actStep,0,1,15);
			} else {
				alpha = 1;
			}
			setOpacity(element, alpha);
			actStep++;
			if (actStep > steps) {
				window.clearInterval(element.valueChangeInterval);
				//if (element.toggle == "hidden" ) { element.style['display'] = 'none'; }
			}
		} 
		,intervals)
}

function doFade(element,attribute,startValue,endValue,steps,intervals) {
	
	if (element.valueChangeInterval) {
		window.clearInterval(element.valueChangeInterval);
	}
	
	var actStep = 0;
	element.valueChangeInterval = window.setInterval(
		function() {
			element.currentValue = easeInOut(actStep,startValue,endValue-startValue,steps);
			element.style[attribute] = element.currentValue;
			actStep++;
			if (actStep > steps) {
				window.clearInterval(element.valueChangeInterval);
			}
		} 
		,intervals)
}

/* ------------------------------ VOTING ------------------------------ */

function alert_props(arr) {
	str = '';
	for (prop in arr) {
		str = str + prop + " = " + arr[prop] + "\r";
	}
	alert(str);
}
function alert_attributes(element) {
	str = '';
	for (var i=0; i<element.attributes.length; i++) {
		str = str + element.attributes[i].nodeName + " = " + element.attributes[i].nodeValue + "\r";
	}
	alert(str);
}

// CLICK
function associateVoteClick(thisObj, nomination_id, category_id) {
	
	// var ribbon_image = thisObj.childNodes[0];
	var ribbon_image = thisObj.firstChild;
	
	if (ribbon_image.src.indexOf('voted.gif') < 0 && ribbon_image.src.indexOf('voting.gif') < 0) {
		ribbon_image.src = "images/buttons/voting.gif";
		
		var number_of_votes = getElementsByAttribute('class', 'number_of_votes', thisObj.parentNode)[0];
		number_of_votes.innerHTML = '-';

		// Create an AJAX object
		var ajaxObj = newAjaxObject();
		
		params = "nomination="+nomination_id+"&category="+category_id;
		
		var callbackargs = {"ribbon_image": ribbon_image, "number_of_votes": number_of_votes};
		
		ajaxObj.postAjaxRequest("http://192.168.1.197/~macuser/bestofthenorthwest/vote.php", params, associateVoteCallback, "xml", callbackargs);
	}
}

// CALLBACK
function associateVoteCallback(o) {
	var ajaxObj = o.reqObj;
					
	if (ajaxObj.readyState == 4) { // If request of file completed
		if (ajaxObj.status == 200 || window.location.href.indexOf("http") == -1) { // If request was successful or running script locally
			if (o.filetype == "txt") {
				// alert(ajaxObj.responseText);
			} else {
				associateVoteDisplay(o.reqObj, o.callbackargs.ribbon_image, o.callbackargs.number_of_votes);
			}
		} else {
		    alert("There was a problem retrieving data:\n" + ajaxObj.statusText);
		}
	} else {
	    // readyState: 0 = uninitialized, 1 = loading, 2 = loaded, 3 = interactive, 4 = complete
		// readyStateArray = Array('uninitialized','loading','loaded','interactive','complete');
		// document.getElementById(mycallbackargs).innerHTML = readyStateArray[ajaxObj.readyState];
	}
}

// DISPLAY
function associateVoteDisplay(reqObj, ribbon_image, number_of_votes) {

	if (window.ActiveXObject) {
		var xmlobject = new ActiveXObject("Microsoft.XMLDOM");
		xmlobject.async = "false";
		xmlobject.loadXML(reqObj.responseText);
	} else {
		// var parser = new DOMParser();
		// var xmlobject = parser.parseFromString(reqObj.responseText, "text/xml");
		var xmlobject = reqObj.responseXML;
	}
	var data = xmlobject.getElementsByTagName("data");
	
	// var data = reqObj.responseXML.getElementsByTagName("data");
	
	for (var i = 0; i < data.length; i++) {
		var votes = getElementTextNS("", "votes", data[i],0);
		var nomination = getElementTextNS("", "nomination", data[i],0);
		var category = getElementTextNS("", "category", data[i],0);
		
		if (votes != null && votes != '') {
			// alert(votes);
			number_of_votes.innerHTML = votes;
		}
		if (nomination != null && nomination != '') {
			// alert(nomination);
		}
		if (category != null && category != '') {
			// alert(category);
		}
	}
	
	ribbon_image.src = "images/buttons/voted.gif"
}

/* ------------------------------ INIT ------------------------------ */
	
function confirmDelete(str) {
	var result = confirm(str);
	return result;
}

// addLoadListener(tooltipInit);