//globals

kArrowLeft = 37;
kArrowRight = 39;
kArrowUp = 38;
kArrowDown = 40;
kPageUp = 33;
kPageDown = 34;
kHome = 36;
kEnd = 35;

// generic functio
function $(id) {
	return document.getElementById(id);
}

// array manipulation

function inArray(ar, value) {
	for (var i =0; i < ar.length; i++) {
		if (ar[i] == value)
			return true;	
	}
	return false;
}

// class handling

function getElementsByClassName(root,clsName,htmltag){ 
	var arr = []; 
	var elems = root.getElementsByTagName(htmltag);
	for ( var cls, i = 0; ( elem = elems[i] ); i++ ) {
		if ( elem.className.search("(\\b|^)" + clsName + "(\\b|$)") != -1 ) {
			arr[arr.length] = elem;
		}
	}
	return arr;
}

function hasClassName(e,c) {
	if (typeof e == "string") e = $(e);
	classes = e.className;
	if (!classes) return false;
	if (classes == c) return true
	return e.className.search("\\b" + c + "\\b") != -1;
}

function addClassName(e,c) {
	if (typeof e == "string") e = $(e);
	if (hasClassName(e, c)) return;
	if (e.className) e.className = e.className + " " + c;
}

function removeClassName(e,c) {
	if (typeof e == "string") e = $(e);
	e.className = e.className.replace(new RegExp("\\b" + c + "\\b\\s*", "g"), "");
}

//looks for name-value pairs in classnames, useful for unobtrusive scripting. Pairs must be separated by a dash.
//If a class name contains multiple dashes, then the value will be an array of the remaining tokens (the first will be the var's name)
function getVarsFromClass(node) {
	var classNames = node.className.split(' ');
	var vars = [];
	var tokens = [];
	for (var i = 0; i < classNames.length; i++) {
		tokens = classNames[i].split('-');
		if (tokens.length > 1)
			vars[tokens[0]] = tokens.length > 2 ? tokens.splice(1) : tokens[1]; // either store a single value ore multiple values as an array
	}
	return vars;
}

// focus handling
function setFocusTo(nodeOrId) {
	var node = typeof nodeOrId == "string" ? $(nodeOrdid) : nodeOrId;
	if (!node) return;
	node.focus();
}

function isFocusable(nodeOrId) {
	var focusableElements = ['a', 'input', 'textarea', 'select', 'button', 'body', 'frame', 'iframe', 'object', 'applet'];
	if (typeof nodeOrId == "string") nodeOrId = $(nodeOrId);
	if (!nodeOrId || nodeOrId.nodeType !== 1) return false;
	for (var i = 0; i < focusableElements; i++) {
		if (nodeOrId.nodeName.toLowerCase() == focusableElements[i])
			return true;
	}
	if (nodeOrId.getAttribute('tabindex') !== undefined && parseInt(nodeOrId.getAttribute('tabindex')) >= -1 && nodeOrId.style.display != "none") {
		return true;
	}
	return false;
}

function getAdjacentFocusNode (node, backwards, stopAtBorders) {
	if (!node || !node.parentNode) return;
	var siblingCount = node.parentNode.childNodes.length;
	var startNode = node;
	if (siblingCount <= 0) return false;
	for (var i = 0; i < siblingCount; i++) {
		try {
			node = !backwards ? node.nextSibling : node.previousSibling;
		}
		catch(e) { //happens when edge node was used (first or last)
			if (!node && !stopAtBorders)
				node = !backwards ? startNode.parentNode.firstChild : startNode.parentNode.lastChild;
		}
		if (isFocusable(node)) 
		 return node;
	}
	return false ;
}

/***** EVENT HANDLING *****/

function addHandler(element, type, handler, capture) {
	if (document.addEventListener)
		element.addEventListener(type, handler, capture);
	else if (document.attachEvent)
		element.attachEvent('on' + type, handler)
	else
		element['on' + type] = handler;
}

function removeHandler(element, type, handler, capture ) {
	if (document.removeEventListener)
		element.removeEventListener(type, handler, capture);
	else if (document.detachEvent)
		element.detachEvent('on' + type, handler)
	else
		element['on' + type] = null;
}

// attempts to create an Xbrowser consistent event object, by adding custom properties
function getEvent(event) {
	var e = event || window.event;
	e.myTarget = e.target || e.srcElement;
	e.myKeyCode = e.keyCode || e.chsrCode;
	return e;
}

//Assigns event handlers to a nodelist 
function addEventToNodes(rootNode, className, nodeName, eventType, handler ) {
	var nodes = getElementsByClassName(rootNode, className, nodeName);
	for (var i = 0; i < nodes.length; i++)
		nodes[i]['on' + eventType] = handler;
	nodes = undefined;
}

/***** KEY HANDLING *****/

function isArrowKey(code) {
	return isVerticalArrowKey(code) || isHorizontalArrowKey(code);
}
function isVerticalArrowKey(code) {
	return code == kArrowUp || code == kArrowDown;
}

function isHorizontalArrowKey(code) {
	return code == kArrowLeft || code == kArrowRight;
}

function feedbackHH(type, msg) {
    var startCountAt = 2, myType = type, myMsg = msg, consoleCall;
    var evalParams = "";
    if (type != "log" && type != "warn" && type != "info") {
        myMsg = type;
        myType = 'log';
        startCountAt = 1;
    }
    if (arguments.length > startCountAt) {
       for (var i = startCountAt; i < arguments.length; i++) {
           evalParams += "'"+arguments[i]+"'";
           if (i < arguments.length -1)
               evalParams += ",";
       }
    }
    if (typeof console == "undefined") {
		try {
            if (!$('logPaneHH')) {
				var logger = document.createElement('div');
				logger.id = "logPaneHH";
				logger.style.position = "fixed";
				logger.style.bottom = "15px";
				logger.style.right = "15px";				
				logger.style.padding = "10px";			
				logger.style.width = "300px";
				logger.style.height = "200px";
				logger.style.overflow = "scroll";				
				logger.style.border = "1px solid black";
				logger.style.background = "white";				
				logger.style.font = "10px Arial";
				logger.style.color = "#333333";
				logger.style.zIndex = "999999";
				document.body.appendChild(logger);
			}
			
			var logPane = $('logPaneHH');
            
			var printFStr = myMsg;
            var logList = logPane.getElementsByTagName('OL')[0];
            if (!logList) {
                logPane.innerHTML = "<ol></ol>";
                logList = logPane.getElementsByTagName('OL')[0];
				logList.style.listStyle = "none";
            }
			//alert(logList.nodeName);
            var now = new Date();
            var logItem = document.createElement('LI');
            var consoleCall = 'logItem.appendChild(document.createTextNode(now.toLocaleTimeString() +": " + printFStr + "('+evalParams+')"))';
            /*logItem.appendChild(document.createTextNode(now.toLocaleTimeString() +
                    ": " + printFStr.printf(
                            logItem.eval(evalParams))));*/
            if (type == "warn") logItem.className = "logWarning";

			eval(consoleCall);

            logList.appendChild(logItem);
            logItem.scrollIntoView();
        }
        catch(e){}
    }
    else {
        var now = new Date();
        evalParams = evalParams == "" ? "": "," + evalParams;
        consoleCall = "console."+myType+"(now.toLocaleTimeString() + ':' + '"+myMsg +"'"+evalParams+")";
        try { eval(consoleCall);} catch(e){}//*/
    }
}


/*
Adds or replaces a part of the title. This considers the title to be a string split up into tokens based on a delimeter (which defaults to ' - ').
'levels' specifies how many tokens (starting from the right) should be replaced / removed. The 'newSuffix' parameter can be a single value or an array.
*/
function changeTitleSuffix(newSuffix, levels, delimeter) {
	levels = levels > 0 ? levels : 0;
	delimeter = !delimeter ? ' - ' : delimeter;
	if (!(newSuffix instanceof Array )) newSuffix = [newSuffix];
	var title = document.title;
	var tokens = title.split(delimeter);
	var indicesToKeep = levels <= tokens.length ? tokens.length - levels: tokens.length;
	document.title = (tokens.splice(0, indicesToKeep).concat(newSuffix)).join(delimeter);
	return document.title;
	
}