function xbGetWindowWidth(windowRef)
{
  var width = 0;

  if (!windowRef)
  {
    windowRef = window;
  }
  
  if (typeof(windowRef.innerWidth) == 'number')
  {
    width = windowRef.innerWidth;
  }
  else if (windowRef.document.documentElement && typeof(windowRef.document.documentElement.clientWidth) == 'number' && windowRef.document.documentElement.clientWidth != 0)
  {
    width = windowRef.document.documentElement.clientWidth;    
  }
  else if (windowRef.document.body && typeof(windowRef.document.body.clientWidth) == 'number')
  {
    width = windowRef.document.body.clientWidth;  
  }
    
  return width;
}

function xbGetWindowHeight(windowRef)
{
  var height = 0;
  
  if (!windowRef)
  {
    windowRef = window;
  }

  if (typeof(windowRef.innerWidth) == 'number')
  {
    height = windowRef.innerHeight;
  }
  else if (windowRef.document.documentElement && typeof(windowRef.document.documentElement.clientHeight) == 'number' && windowRef.document.documentElement.clientHeight != 0)
  {
    height = windowRef.document.documentElement.clientHeight;    
  }
  else if (windowRef.document.body && typeof(windowRef.document.body.clientWidth) == 'number')
  {
    height = windowRef.document.body.clientHeight;    
  }
  
  /*alert("window:" + windowRef.name + " xbDom height:" + height);*/
  
  return height;
}

/**********************************************
tinyMCE
**********************************************/

/*font_size_classes : "fontSize1,fontSize2,fontSize3,fontSize4,fontSize5,fontSize6,fontSize7"*/
/*font_size_style_values : "0.8em,0.8em,0.9em,1em,1.4em,1.7em,2.0.em",content_css:"*/
function initMCEEditor(editor_id, body, doc)
{
	var iobj = $(editor_id);
	var inst = tinyMCE.getInstanceById(editor_id);
	//html = tinyMCE._cleanupHTML(inst, inst.getDoc(), tinyMCE.settings, inst.getBody(), false, true);    
	if (inst.startContent.length < 1) {
		inst.getBody().innerHTML = "<p>";
		tinyMCE.triggerSave();
	}
	return;
		 
	//var the_form = getFormNode(o);
	//var attr = getElementAttribute(the_form, 'class');
	
	//var l=document.createElement("input");
	//l.setAttribute("name", "mce_editor");
	//l.setAttribute("value", "transformed");
	//the_form.appendChild(l);

	//alert(show_props(i.oldTargetElement, '  i'));	
}

/**********************************************
troubleshooting
**********************************************/

/* Displays contents of an object via alert dialog */

function show_props(obj, objName) {
	var result = "<!--";
	for (var i in obj) {
		if (typeof(obj[i]) != 'function' && i != 'innerHTML') {
			result += objName + "." + i + " = " + obj[i] ;
		}
	}
	
	result += "-->";
	return result;
}

/**********************************************
date and time
**********************************************/

function get_now_stamp()
{
	var now = new Date();
	now = now.getTime();
	return now;
}
	
function makeDate(the_year, the_month, the_day)
{

	/*When creating a date object, the month number is calculated based
	on January being 0 and December being 11*/
	
	var new_date = new Date(the_year, (the_month - 1), the_day);
	return new_date;
}

function format_date(the_date)
{

	var	date_string = "";
	
	if (typeof(the_date) == "undefined") {
		return date_string;
	}
	
	//date_string += the_date.getDate() + "&nbsp;";
	switch (the_date.getMonth()) {
		case 0: date_string += "jan&nbsp;"; break;
		case 1: date_string += "feb&nbsp;"; break;
		case 2: date_string += "mar&nbsp;"; break;
		case 3: date_string += "apr&nbsp;"; break;
		case 4: date_string += "may&nbsp;"; break;
		case 5: date_string += "jun&nbsp;"; break;
		case 6: date_string += "jul&nbsp;"; break;
		case 7: date_string += "aug&nbsp;"; break;
		case 8: date_string += "sep&nbsp;"; break;
		case 9: date_string += "oct&nbsp;"; break;
		case 10: date_string += "nov&nbsp;"; break;
		case 11: date_string += "dec&nbsp;"; break;
	}
	date_string += the_date.getFullYear();
	return date_string;

}

/**********************************************
*
*	The Central Randomizer 1.3 (C) 1997 by Paul Houle (houle@msc.cornell.edu)
*	See:  http://www.msc.cornell.edu/~houle/javascript/randomizer.html
*	To create a random floating point number use: rnd(), to create a random integer, say between 1 and 10, use rand(10).
*
**********************************************/

rnd.today=new Date();
rnd.seed=rnd.today.getTime();

function rnd()
{
	rnd.seed = (rnd.seed*9301+49297) % 233280;
	return rnd.seed/(233280.0);
};

function rand(number)
{
	return Math.ceil(rnd()*number);
};

/* The Central Randomizer, end */

function get_random(n) {
	return rand(n);
}

/**********************************************
DOM
**********************************************/

function getElementAttribute(elementObj, att)
{
	var value;
	
	if (typeof(elementObj) == 'object' && typeof(att) == 'string') {
	
		/* Are we getting class attribute? Use className */
		/* According to Quirksmode, all browsers understand obj.className... */
		if (att == 'class' && typeof(elementObj.className) != 'undefined') {
			value = elementObj.className;
		} else {
			if (typeof(elementObj.att) == 'string' || typeof(elementObj.att) == 'number') {
				value = elementObj.att;
			} else {
				value = elementObj[att];
			}

			/* By the way, IE seems to say "Yes, I have the getAttribute method," but then doesn't deliver the goods! */
			if (typeof(value) != 'string' && typeof(value) != 'number') {
				if (elementObj.getAttribute) {
					value = elementObj.getAttribute(att);
				}
			}
		}
	}
	
	return value;
}

function setElementAttribute(elementObj, att, the_value)
{	
	if (typeof(elementObj) == 'object' && typeof(att) == 'string' && typeof(the_value) != 'undefined') {
	
		/* Use className for setting class attribute */
		if (att == 'class' && typeof(elementObj.className) != 'undefined') {
			elementObj.className = the_value;
		} else {
			if (elementObj.att) {
				elementObj.att = the_value;
			} else {
				elementObj[att] = the_value;
			}

			if (typeof((getElementAttribute(elementObj, att))) != 'string' && typeof((getElementAttribute(elementObj, att))) != 'number') {
				if (elementObj.setAttribute) {
					elementObj.setAttribute(att, the_value);
				}
			}
		}
	}
}

function getFormNode(inputObj)
{
	/* object, argument inputObj is derived from a tag contained in an HTML form tag */
	/* Function moves up DOM tree and returns the first form object found, the parent form containing the inputObj */

	var i;
	if (typeof(inputObj) == 'object') {
		do {
			i = inputObj.nodeName.toLowerCase();
			if (i != 'form') {
				inputObj = inputObj.parentNode;
			}
		} while (i != 'form');
	}
	
	return inputObj;
}

function getPreviousNode(inputObj, tag_to_find)
{
	/* Function moves up DOM tree, parent by parent, starting at inputObj */
	/* and returns the first tag_to_find object found... */

	var i;
	if (typeof(inputObj) == 'object' && typeof(tag_to_find) == 'string') {
		tag_to_find = tag_to_find.toLowerCase();
		do {
			i = inputObj.nodeName.toLowerCase();
			if (i != tag_to_find) {
				inputObj = inputObj.parentNode;
			}
		} while (i != tag_to_find);
	}
	return inputObj;
}


/**********************************************
DOM - Create Element
**********************************************/

function createElement(element)
{
	/* http://simon.incutio.com/archive/2003/06/15/javascriptWithXML */
	if (typeof document.createElementNS != 'undefined') {
		return document.createElementNS('http://www.w3.org/1999/xhtml', element);
	}
	if (typeof document.createElement != 'undefined') {
		return document.createElement(element);
	}
	return false;
}

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

var validateFormInput = function (e)
{
	var ele = getSourceElement(e);
	var frm = getFormNode(ele);
	var cdata_name = getElementAttribute(frm, 'id');
		
	eval(cdata_name + "_CFormData.fromForm(frm);");
	eval("result = handleSubmit_" + cdata_name + "(" + cdata_name + "_CFormData);");
	
	if (result === false) {
		stopEvent(e);
		stopDefault(e);
	}

	return result;
}

function stopDefault(e)
{
	if (e.preventDefault) {
		e.preventDefault();
	}
}

function stopEvent(e)
{
	/* http://www.quirksmode.org/js/events_order.html */
	if (!e) {
		var e = window.event;
	}
	e.cancelBubble = true;
	if (e.stopPropagation) {
		e.stopPropagation();
	}
}

function getEventType(e)
{
	/* http://www.quirksmode.org/js/events_properties.html */
	if (!e) var e = window.event;
	return (e.type);
}

function getSourceElement(e)
{
	/* http://www.quirksmode.org/js/events_properties.html */
	
	var targ;
	
	if (!e) {
		var e = window.event;
	}
	
	if (typeof(e.currentTarget) != 'undefined') {
		targ = e.currentTarget
	} else if (typeof(e.target) != 'undefined') {
		/* In my previous function (see getSourceElementMine), I used currentTarget. */
		/* According to Quirksmode, target will support Explorer for Mac where currentTarget won't */
		/* Not my favorite browser, but why leave it out when alternative is available? */
		targ = e.target;
	} else if (typeof(e.srcElement) != 'undefined') {
		targ = e.srcElement;
	}
	
	/* defeat Safari bug */
	if (typeof(targ.nodeType) != 'undefined') {
		if (targ.nodeType == 3) {
			targ = targ.parentNode;
		}
	}
	
	return targ;
}

function getSourceElementStyle(e)
{
	//return new xbStyle(getSourceElement(e));
}

function getSourceElementClass(e)
{
	return Element.classNames(Event.element(e))
	//return getElementAttribute(getSourceElement(e), 'class')
}

function getSourceElementId(e)
{
	return getElementAttribute(getSourceElement(e), 'id')
}

function classContains(needle, haystack)
{
	classRegExp = new RegExp(("\\b" + needle + "\\b"));
	if (classRegExp.test(haystack)) {
		return true;
	} else {
		return false;
	}
}

function collectTags(theTagName, theClassName, inclusive)
{
	var classAttribute;
	var classRegExp;
	var debug = false;
	if (debug === true) {
		var tagNames = new String();
	}

	if (typeof(theTagName) != 'string') {
		return false;
	}

	if (typeof(theClassName) != 'string') {
		theClassName = false;
	} else {
		classRegExp = new RegExp(("\\b" + theClassName + "\\b"));
	}
	
	/* Default is that the function returns, for intstance, div tags with class 'blah'. */
	/* With inclusive set to false, function returns div tags not set to 'blah' */
	if (typeof(inclusive) != 'boolean') {
		inclusive = true;
	}

	var tagList = document.getElementsByTagName(theTagName);
	var collection = new Array();
	
	for (b = 0; b < tagList.length; b++) {
	
		classAttribute = getElementAttribute(tagList[b], 'class');
		
		if (typeof(theClassName) == 'string') {
			if (debug === true) {
				alert(theClassName + "\n" + classAttribute + "\n" + classRegExp.test(classAttribute));
			}
			if ((classRegExp.test(classAttribute) && inclusive) || (!classRegExp.test(classAttribute) && !inclusive)) {
				collection[ (collection.length) ] = tagList[b];
				if (debug === true) {
					tagNames += getElementAttribute(tagList[b], 'id') + ", ";
				}
			}
		} else {
			collection[ (collection.length) ] = tagList[b];
			if (debug === true) {
				tagNames += getElementAttribute(tagList[b], 'id') + ", ";
			}
		}
	}
	
	if (debug === true) {
		tagNames = "tag: " + theTagName + "\nclass: " + theClassName + "\nincl: " + inclusive + "\n ids: " + tagNames;
		alert(tagNames);
	}
	return collection;
}

function attachAnEvent(theTagName, theEventName, theHandlerName, theClassName, inclusive, incomingTagList)
{
	/* Attaches an event handler to a document tag (element) set (with/without) class attribute. */
	/* Elements without a class attribute do not match a theClassName is passed as an argument. */
	
	var flag;
	var taglist;
	var result;
	
	if (typeof(inclusive) != 'boolean') {
		inclusive = true;
	}
	
	if (typeof(incomingTagList) =='object') {
		tagList = incomingTagList;
	} else {
		tagList = collectTags(theTagName, theClassName, inclusive);
	}
	
	if (typeof(tagList) == 'object' && tagList.length > 0) {
		for (b = 0; b < tagList.length; b++) {
			if (tagList[b].addEventListener) {
				/* Last argument: false means events are triggered in bubbling phase */
				eval("tagList[b].addEventListener(\"" + theEventName + "\", " + theHandlerName + ", false);");
			} else {
				if (tagList[b].attachEvent) {
					result = eval("tagList[b].attachEvent('on" + theEventName + "', " + theHandlerName + ");");
				} else {
					/* So called traditional method. See http://www.quirksmode.org/js/events_tradmod.html */
					/* Main drawback is that only one event can be registered per element. New events overwrite previously registered ones. */		
					eval("tagList[b].on" + theEventName + " = " + theHandlerName + ";");
				}
			}
		}
	}
}

function removeAnEvent(theTagName, theEventName, theHandlerName, theClassName, inclusive, incomingTagList)
{	
	var flag;
	var taglist;
	var result;
	
	if (typeof(inclusive) != 'boolean') {
		inclusive = true;
	}
	
	if (typeof(incomingTagList) == 'object') {
		tagList = incomingTagList;
	} else {
		tagList = collectTags(theTagName, theClassName, inclusive);
	}

	if (typeof(tagList) == 'object' && tagList.length > 0) {
		for (b = 0; b < tagList.length; b++) {
			if (tagList[b].removeEventListener) {
				eval("tagList[b].removeEventListener(\"" + theEventName + "\", " + theHandlerName + ", false);");
			} else {
				if (tagList[b].removeEvent) {
					result = eval("tagList[b].removeEvent('on" + theEventName + "', " + theHandlerName + ");");
				} else {
					/* So called traditional method. See http://www.quirksmode.org/js/events_tradmod.html */
					/* Main drawback is that only one event can be registered per element. New events overwrite previously registered ones. */		
					eval("tagList[b].on" + theEventName + " = undefined;");
				}
			}
		}
	}
}

/**********************************************
Miscellaneous
**********************************************/

function isUndefined(v)
{
	/* From/see http://v2studio.com/k/code/lib/ */
	/* Used for Popup.js */
	
	if (typeof(v) == 'undefined') {
		return true;
	}
	
    var undef;
    return v===undef;
}

function stripQuerystring(theURI)
{
	/* Takes a URI (string) as argument and
	returns the URI minus any querystring pairs.*/
	
	var theQ = theURI.indexOf('?');
	if (theQ < 0) {
		return theURI;
	} else {
		return theURI.substr(0,theQ);
	}
}

/**********************************************
Array - Miscellaneous - source unknown
**********************************************/

/* Check whether array contains given string */
Array.prototype.contains = function(s) {
    for (var i = 0; i < this.length; ++i) {
        if (this[i] === s) { return true; }
    }
    return false;
};

/* Indicates whether some other array is "equal to" this one */
Array.prototype.equals = function(a) {
    if (this.length != a.length) { return false; }
    for (var i = 0; i < this.length; ++i) {
        if (this[i] !== a[i]) { return false; }
    }
    return true;
};

/* Finds the index of the first occurence of item in the array, or -1 if not found */
Array.prototype.indexOf = function(item) {
    for (var i = 0; i < this.length; ++i) {
        if (this[i] === item) { return i; }
    }
    return -1;
};

/* Get the last element from the array */
Array.prototype.getLast = function() {
    return this[this.length-1];
};

/* Remove elements judged 'false' by the passed function (mutates) */
Array.prototype.filter = function(func) {
    var i, indexes = [];
    for (i = 0; i < this.length; ++i) {
        if (!func(this[i])) { indexes.push(i); }
    }
    for (i = indexes.length - 1; i >= 0; --i) {
        this.splice(indexes[i], 1);
    }
};

/* Apply custom function to every element of an array (mutates) */
Array.prototype.map = function(func) {
    for (var i = 0; i < this.length; ++i) {
        this[i] = func(this[i]);
    }
};

/* Push an element at specified index */
Array.prototype.pushAtIndex = function(el, index) {
    this.splice(index, 0, el);
};

/* Remove element with given index (mutates) */
Array.prototype.removeByIndex = function(index) {
    this.splice(index, 1);
};

/* Remove elements with such value (mutates) */
Array.prototype.removeByValue = function(value) {
    var i, indexes = [];
    for (i = 0; i < this.length; ++i) {
        if (this[i] === value) { indexes.push(i); }
    }
    for (i = indexes.length - 1; i >= 0; --i) {
        this.splice(indexes[i], 1);
    }
};
 
/* Remove duplicate values (mutates)
 * Dependencies: Array.indexOf() */
Array.prototype.removeDuplicates = function() {
    var i, unique = [], indexes = [];
    for (i = 0; i < this.length; ++i) {
        if (unique.indexOf(this[i]) == -1) { unique.push(this[i]); }
        else { indexes.push(i); }
    }
    for (i = indexes.length - 1; i >= 0; --i) {
        this.splice(indexes[i], 1);
    }
};
 
/* Returns copy of an array */
Array.prototype.copy = function() {
    var copy = [];
    for (var i = 0; i < this.length; ++i) {
        copy[i] = (typeof this[i].copy != "undefined") ? this[i].copy() : this[i];
    }
    return copy;
};
 
/* Swaps the values of two indicies (mutates) */
Array.prototype.swap = function(index1, index2) {
    var temp = this[index1];
    this[index1] = this[index2];
    this[index2] = temp;
};

/* Randomly shuffles array (mutates)
 * Dependencies: Array.swap() */
Array.prototype.shuffle = function() {
    for (var i = 0; i < this.length; ++i) {
        var ind1 = Math.floor(Math.random() * this.length);
        var ind2 = Math.floor(Math.random() * this.length);
        this.swap(ind1, ind2);
    }
};
