// *** prototype extensions ***

/*
 * returns true if the string ends with the given suffix.
 */
String.prototype.endsWith = function(suffix) {
    var pos = this.indexOf(suffix);
    return pos >= 0 && pos + suffix.length == this.length;
}

/*
 * returns true if the string starts with the given prefix.
 */
String.prototype.startsWith = function(prefix) {
    return this.indexOf(prefix) == 0;
}

/*
 * returns a true array from an Arguments object
 */
function arrayFromArgs(args) {
    var result = new Array();
    for (var i = 0; i < args.length; i++)
	result[i] = args[i];
    return result;
}

/*
 * Pushes the contents of the supplied array onto the end of this one.
 *
 * Example [1,2,3].append([4,5,6]) = [1,2,3,4,5,6]
 */
Array.prototype.append = function(array) {
    for (var i = 0; i < array.length; i++)
	this.push(array[i]);
}

if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function(obj) {
	for (var i = 0; i < this.length; i++)
	    if (this[i] === obj)
		return i;
	return -1;
    }
}

// *** core functions ***

/*
 * Finds the first parameter with the specified name
 */
function getPageParam(name) {
    var re = new RegExp(name + "=([^&=]*)(&|$)?");
    var match = re.exec(window.location.search);
    return match ? decodeURIComponent(match[1]) : null;
}

/*
 * Returns an array of all the parameters that have that name
 */
function getPageParams(name) {
    var re = new RegExp(name + "=([^&=]*)(&|$)?", "g");
    var result = new Array();
    var match;
    while (match = re.exec(window.location.search))
	result.push(decodeURIComponent(match[1]));
    return result.length == 0 ? null : result;
}

/*
 * Takes a map and rewrites parameters with key names to the new values. Assumes
 * that the current url only has 1 parameter with each name.
 * If set, addNew will fill in any gaps if the parameter was missing.
 * Values of null for properties of the toReplace map will delete the parameter
 */
function replacePageParams(toReplace, addNew) {
    var href = window.location.href;
    for (var param in toReplace) {
	var value = toReplace[param];
	var re = RegExp("([?&]" + param + "=)[^?&#]*");
	var match = re.exec(href);
	if (match) {
	    if (value)
		href = href.replace(re, "$1" + toReplace[param]);
	    else
		href = href.substring(0, match.index) + href.substring(match.index + match[0].length);
	} else if (addNew && value) {
	    href += (href.indexOf('?') == -1 ? '?' : '&') + param + "=" + value;
	}
    }
    return href;
}

/*
 * Browser independent way of obtaining an HTTP request for use by Ajax
 */
function httpRequest() {
    if (window.XMLHttpRequest)
	return new XMLHttpRequest();
    else if (window.ActiveXObject)
	return new ActiveXObject("Microsoft.XMLHTTP");
}

// returns the last non-false result from a queued function, or false if one
// is encountered
function processHandlerQueue(event) {
    event = event || window.event;
    var elem = event.target || event.srcElement;
    // annoying bug in moz, it seems to dispatch onsubmit events with the
    // wrong source element if no inputs have been changed, and enter pressed
    // in input element
    if (event.type == "submit" && elem.form)
	elem = elem.form;
    var queue = elem.handlerQueue[event.type];
    var result;
    for (var i = 0; i < queue.length; i++) {
	result = queue[i].call(elem, event);
	// !result not good enough here, if handler returns undefined we want
	// to continue processing queue
	if (result == false)
	    return false;
    }
    return result;
}

// note, if func returns false, queue processing is aborted
// ignoring the case of image map onmouseover where returning true == abort
function queueEventHandler(obj, event, func) {
    if (!obj.handlerQueue)
	obj.handlerQueue = new Array();
    if (obj.handlerQueue[event]) {
	obj.handlerQueue[event].push(func);
    } else {
	var handlers = new Array();
	obj.handlerQueue[event] = handlers;
	var existingHandler = eval("obj.on" + event);
	if (existingHandler)
	    handlers.push(existingHandler);
	handlers.push(func);
	// bit of an ugly hack, but can't find any other way of aborting form
	// submission. seems to ignore retval if using addEventListener
	eval("obj.on" + event + " = processHandlerQueue");
    }
}

function findAncestor(obj, type) {
    type = type.toUpperCase();
    for (;;) {
	obj = obj.parentNode;
	if (!obj || obj.tagName == type)
	    break;
    }
    return obj;
}

function addClass(obj, className) {
    var appliedClasses = obj.className.split(' ');
    for (var i = 0; i < appliedClasses.length; i++)
	if (appliedClasses[i] == className)
	    return;
    obj.className += " " + className;
}

function removeClass(obj, className) {
    changeClass(obj, className, null);
}

function changeClass(obj, oldClass, newClass) {
    var appliedClasses = obj.className.split(' ');
    for (var i = 0; i < appliedClasses.length; i++)
	if (appliedClasses[i] == oldClass)
	    appliedClasses[i] = newClass;
    obj.className = appliedClasses.join(' ');
}

function hasClass(obj, className) {
    var appliedClasses = obj.className.split(' ');
    for (var i = 0; i < appliedClasses.length; i++)
	if (appliedClasses[i] == className)
	    return true;
    return false;
}

/**
 * performs an asynchronous request to the given url via a POST, sending it
 * the given args (which can be null).  If the callback is non-null, it will
 * be passed the response text when the request has completed.  If sync is true,
 * the call will be synchronous. retry should not be given a value.
 */
function ajax(url, args, callback, sync, retry) {
    var req = window.ActiveXObject ?
	new ActiveXObject("Microsoft.XMLHTTP") :
	new XMLHttpRequest();
    req.open("POST", url, !sync);
    req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 
    req.onreadystatechange = function() {
	if (req.readyState == 4) {
	    try {
		var st = req.status;
	    } catch (e) {
		return;
	    }
	    if (st == 200 || st == undefined) {
		var text = req.responseText;
		req = null;
		if (callback && text)
		    callback(text);
	    } else {
		req = null;
		var retry = retry || 0;
		if (retry >= 5) {
		    callback(undefined);
		} else {
		    setTimeout(function() {
			ajax(url, args, callback, retry + 1);
		    }, 10000);
		}
	    }
	}
    }
    var vars = "";
    if (args) {
	for (var a in args)
	    vars += a + "=" + encodeURIComponent(args[a]) + "&";
	vars = vars.substring(0, vars.length - 1);
    }
    req.send(vars);
}

/*
 * Creates a popup window.
 *
 * Any of the arguments to this function can be null or omitted.
 * If url is null, an empty popup will be created.
 * If no name is specified, a randomly generated name will be assigned.
 * If noreload is true, the window will be raised but not reloaded.
 */
function popup(url, width, height, features, name, noreload) {
    if (!url)
	url = "";
    var f = "";
    if (width)
	f += "width=" + width;
    if (height) {
	if (f.length > 0)
	    f += ",";
	f += "height=" + height;
    }
    if (features) {
	if (f.length > 0)
	    f += ",";
	f += features;
    }
    if (!name)
        name = "popup" + Math.round(Math.random() * 1000);
    var popup = window.open("", name, f);
    if (!popup.opener)
	popup.opener = self;
    try {
	if (!noreload || !popup.location.href.endsWith(url))
	    popup.location = url;
    } catch (e) {
	// looking at the location can throw an exception
    }
    popup.focus();
    return popup;
}
function openChat(script) {
    if (script)
	ajax(script, null, null, true);
    popup("/ec/chat.jtp",700,500,"resizable=1","chat",true);
}
