/*** form/X stuff ***/






var currentInput, currentChild, currentStatic;

function saveSCTContent (to, from) {
	var j = false, i;
	to.value = "";
	for (i = 0; i < from.length; i ++) {
		if (!j) j = true; else to.value = to.value + ",";
		to.value = to.value + from[i].value;
	}
}

function getSCTValues (from) {
	var j = false, i;
	var v = "";
	for (i = 0; i < from.length; i ++) {
		if (!j) j = true; else {
			v = v + ",";
		}
		v = v + from[i].value;
	}
	return v;
}

function getSCTNames (from) {
	var j = false, i;
	var n = "";
	for (i = 0; i < from.length; i ++) {
		if (!j) j = true; else {
			n = n + ",";
		}
		n = n + from.options[i].text;
	}
	return n;
}


function moveListElement (list1, list2, elementIndex){
	if(elementIndex>-1){
		var insertIndex=0;
		var notLast=false;
		for(var i=0;i<list2.options.length;i++){
			if(list1.options[elementIndex].text>=list2.options[i].text){
				insertIndex=i+1;
			}
		}
		list2.options.length++;
		for(var i=list2.options.length-1;i>insertIndex;i--){
			 if(i>0){
				list2.options[i].text=list2.options[i-1].text;
				list2.options[i].value=list2.options[i-1].value;
			 }
		}
		list2.options[insertIndex].value=list1.options[elementIndex].value;
		list2.options[insertIndex].text=list1.options[elementIndex].text;
		for(var i=elementIndex;i<list1.options.length-1;i++){
			list1.options[i].text=list1.options[i+1].text;
			list1.options[i].value=list1.options[i+1].value;
		}
		list1.options[list1.options.length-1]=null;
	}
	return true;
}

function showFilePopup (url, id) {
	if (currentChild) currentChild.close ();
	fileWin = window.open (url, 'fileWin', 'width=640,height=480,status=no,navbar=no,scrollbars=yes');
	currentChild = fileWin;
	currentInput = document.getElementById (id);
	fileWin.focus ();
}

var popupSetFileMode = 0;
var popupSetFileModeOpt = '';
var popupSetFileModeObj = null;



function popupSetFile (value) {

	if (popupSetFileMode == 0) {
		currentInput.value = value;
		currentChild.close ();
		currentChild = false;
		currentInput = false;
	} else if (popupSetFileMode == 1) {
		value = value.substr(popupSetFileModeOpt.length, value.length - popupSetFileModeOpt.length);
		popupSetFileModeObj.options.length++;
		popupSetFileModeObj.options[popupSetFileModeObj.options.length-1].text = value;
		popupSetFileModeObj.options[popupSetFileModeObj.options.length-1].key = value;
		currentChild.close();
	}
}



function showStaticPopup (url, id, xsize, ysize) {
	if (currentChild) currentChild.close ();
	popupWin = window.open (url, 'popupWin', 'width='+xsize+',height='+ysize+',status=no,navbar=no');
	currentChild = popupWin;
	currentInput = document.getElementById (id);
	currentStatic = document.getElementById ('static_' + id);
	popupWin.focus ();
}

function popupSetStatic (text,value) {
	currentInput.value = value;
	currentStatic.innerHTML = text;
	currentChild.close ();
	currentChild = false;
	currentInput = false;
	currentStatic = false;
}


/*** calendar ***/

/*  Copyright Mihai Bazon, 2002  |  http://students.infoiasi.ro/~mishoo
 * ---------------------------------------------------------------------
 *
 * The DHTML Calendar, version 0.9.2 "The art of date selection"
 *
 * Details and latest version at:
 * http://students.infoiasi.ro/~mishoo/site/calendar.epl
 *
 * Feel free to use this script under the terms of the GNU Lesser General
 * Public License, as long as you do not remove or alter this notice.
 */

// $Id: common.js,v 1.34 2005/03/02 14:39:39 kzed Exp $

/** The Calendar object constructor. */
Calendar = function (mondayFirst, dateStr, onSelected, onClose) {
	// member variables
	this.activeDiv = null;
	this.currentDateEl = null;
	this.checkDisabled = null;
	this.timeout = null;
	this.onSelected = onSelected || null;
	this.onClose = onClose || null;
	this.dragging = false;
	this.hidden = false;
	this.minYear = 1970;
	this.maxYear = 2050;
	this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
	this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
	this.isPopup = true;
	this.weekNumbers = true;
	this.mondayFirst = mondayFirst;
	this.dateStr = dateStr;
	this.ar_days = null;
	// HTML elements
	this.table = null;
	this.element = null;
	this.tbody = null;
	this.firstdayname = null;
	// Combo boxes
	this.monthsCombo = null;
	this.yearsCombo = null;
	this.hilitedMonth = null;
	this.activeMonth = null;
	this.hilitedYear = null;
	this.activeYear = null;

	// one-time initializations
	if (!Calendar._DN3) {
		// table of short day names
		var ar = new Array();
		for (var i = 8; i > 0;) {
			ar[--i] = Calendar._DN[i].substr(0, 3);
		}
		Calendar._DN3 = ar;
		// table of short month names
		ar = new Array();
		for (var i = 12; i > 0;) {
			ar[--i] = Calendar._MN[i].substr(0, 3);
		}
		Calendar._MN3 = ar;
	}
};

// ** constants

/// "static", needed for event handlers.
Calendar._C = null;

/// detect a special case of "web browser"
Calendar.is_ie = ( (navigator.userAgent.toLowerCase().indexOf("msie") != -1) &&
		   (navigator.userAgent.toLowerCase().indexOf("opera") == -1) );

// short day names array (initialized at first constructor call)
Calendar._DN3 = null;

// short month names array (initialized at first constructor call)
Calendar._MN3 = null;

// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
//        library, at some point.

Calendar.getAbsolutePos = function(el) {
	var r = { x: el.offsetLeft, y: el.offsetTop };
	if (el.offsetParent) {
		var tmp = Calendar.getAbsolutePos(el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}
	return r;
};

Calendar.isRelated = function (el, evt) {
	var related = evt.relatedTarget;
	if (!related) {
		var type = evt.type;
		if (type == "mouseover") {
			related = evt.fromElement;
		} else if (type == "mouseout") {
			related = evt.toElement;
		}
	}
	while (related) {
		if (related == el) {
			return true;
		}
		related = related.parentNode;
	}
	return false;
};

Calendar.removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

Calendar.addClass = function(el, className) {
	Calendar.removeClass(el, className);
	el.className += " " + className;
};

Calendar.getElement = function(ev) {
	if (Calendar.is_ie) {
		return window.event.srcElement;
	} else {
		return ev.currentTarget;
	}
};

Calendar.getTargetElement = function(ev) {
	if (Calendar.is_ie) {
		return window.event.srcElement;
	} else {
		return ev.target;
	}
};

Calendar.stopEvent = function(ev) {
	if (Calendar.is_ie) {
		window.event.cancelBubble = true;
		window.event.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
};

Calendar.addEvent = function(el, evname, func) {
	if (Calendar.is_ie) {
		el.attachEvent("on" + evname, func);
	} else {
		el.addEventListener(evname, func, true);
	}
};

Calendar.removeEvent = function(el, evname, func) {
	if (Calendar.is_ie) {
		el.detachEvent("on" + evname, func);
	} else {
		el.removeEventListener(evname, func, true);
	}
};

Calendar.createElement = function(type, parent) {
	var el = null;
	if (document.createElementNS) {
		// use the XHTML namespace; IE won't normally get here unless
		// _they_ "fix" the DOM2 implementation.
		el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
	} else {
		el = document.createElement(type);
	}
	if (typeof parent != "undefined") {
		parent.appendChild(el);
	}
	return el;
};

// END: UTILITY FUNCTIONS

// BEGIN: CALENDAR STATIC FUNCTIONS

/** Internal -- adds a set of events to make some element behave like a button. */
Calendar._add_evs = function(el) {
	with (Calendar) {
		addEvent(el, "mouseover", dayMouseOver);
		addEvent(el, "mousedown", dayMouseDown);
		addEvent(el, "mouseout", dayMouseOut);
		if (is_ie) {
			addEvent(el, "dblclick", dayMouseDblClick);
			el.setAttribute("unselectable", true);
		}
	}
};

Calendar.findMonth = function(el) {
	if (typeof el.month != "undefined") {
		return el;
	} else if (typeof el.parentNode.month != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.findYear = function(el) {
	if (typeof el.year != "undefined") {
		return el;
	} else if (typeof el.parentNode.year != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.showMonthsCombo = function () {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var mc = cal.monthsCombo;
	if (cal.hilitedMonth) {
		Calendar.removeClass(cal.hilitedMonth, "hilite");
	}
	if (cal.activeMonth) {
		Calendar.removeClass(cal.activeMonth, "active");
	}
	var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
	Calendar.addClass(mon, "active");
	cal.activeMonth = mon;
	mc.style.left = cd.offsetLeft + "px";
	mc.style.top = (cd.offsetTop + cd.offsetHeight) + "px";
	mc.style.display = "block";
};

Calendar.showYearsCombo = function (fwd) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var yc = cal.yearsCombo;
	if (cal.hilitedYear) {
		Calendar.removeClass(cal.hilitedYear, "hilite");
	}
	if (cal.activeYear) {
		Calendar.removeClass(cal.activeYear, "active");
	}
	cal.activeYear = null;
	var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
	var yr = yc.firstChild;
	var show = false;
	for (var i = 12; i > 0; --i) {
		if (Y >= cal.minYear && Y <= cal.maxYear) {
			yr.firstChild.data = Y;
			yr.year = Y;
			yr.style.display = "block";
			show = true;
		} else {
			yr.style.display = "none";
		}
		yr = yr.nextSibling;
		Y += fwd ? 2 : -2;
	}
	if (show) {
		yc.style.left = cd.offsetLeft + "px";
		yc.style.top = (cd.offsetTop + cd.offsetHeight) + "px";
		yc.style.display = "block";
	}
};

// event handlers

Calendar.tableMouseUp = function(ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	if (cal.timeout) {
		clearTimeout(cal.timeout);
	}
	var el = cal.activeDiv;
	if (!el) {
		return false;
	}
	var target = Calendar.getTargetElement(ev);
	Calendar.removeClass(el, "active");
	if (target == el || target.parentNode == el) {
		Calendar.cellClick(el);
	}
	var mon = Calendar.findMonth(target);
	var date = null;
	if (mon) {
		date = new Date(cal.date);
		if (mon.month != date.getMonth()) {
			date.setMonth(mon.month);
			cal.setDate(date);
		}
	} else {
		var year = Calendar.findYear(target);
		if (year) {
			date = new Date(cal.date);
			if (year.year != date.getFullYear()) {
				date.setFullYear(year.year);
				cal.setDate(date);
			}
		}
	}
	with (Calendar) {
		removeEvent(document, "mouseup", tableMouseUp);
		removeEvent(document, "mouseover", tableMouseOver);
		removeEvent(document, "mousemove", tableMouseOver);
		cal._hideCombos();
		stopEvent(ev);
		_C = null;
	}
};

Calendar.tableMouseOver = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return;
	}
	var el = cal.activeDiv;
	var target = Calendar.getTargetElement(ev);
	if (target == el || target.parentNode == el) {
		Calendar.addClass(el, "hilite active");
		Calendar.addClass(el.parentNode, "rowhilite");
	} else {
		Calendar.removeClass(el, "active");
		Calendar.removeClass(el, "hilite");
		Calendar.removeClass(el.parentNode, "rowhilite");
	}
	var mon = Calendar.findMonth(target);
	if (mon) {
		if (mon.month != cal.date.getMonth()) {
			if (cal.hilitedMonth) {
				Calendar.removeClass(cal.hilitedMonth, "hilite");
			}
			Calendar.addClass(mon, "hilite");
			cal.hilitedMonth = mon;
		} else if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
	} else {
		var year = Calendar.findYear(target);
		if (year) {
			if (year.year != cal.date.getFullYear()) {
				if (cal.hilitedYear) {
					Calendar.removeClass(cal.hilitedYear, "hilite");
				}
				Calendar.addClass(year, "hilite");
				cal.hilitedYear = year;
			} else if (cal.hilitedYear) {
				Calendar.removeClass(cal.hilitedYear, "hilite");
			}
		}
	}
	Calendar.stopEvent(ev);
};

Calendar.tableMouseDown = function (ev) {
	if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
		Calendar.stopEvent(ev);
	}
};

Calendar.calDragIt = function (ev) {
	var cal = Calendar._C;
	if (!(cal && cal.dragging)) {
		return false;
	}
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posX = ev.pageX;
		posY = ev.pageY;
	}
	cal.hideShowCovered();
	var st = cal.element.style;
	st.left = (posX - cal.xOffs) + "px";
	st.top = (posY - cal.yOffs) + "px";
	Calendar.stopEvent(ev);
};

Calendar.calDragEnd = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	cal.dragging = false;
	with (Calendar) {
		removeEvent(document, "mousemove", calDragIt);
		removeEvent(document, "mouseover", stopEvent);
		removeEvent(document, "mouseup", calDragEnd);
		tableMouseUp(ev);
	}
	cal.hideShowCovered();
};

Calendar.dayMouseDown = function(ev) {
	var el = Calendar.getElement(ev);
	if (el.disabled) {
		return false;
	}
	var cal = el.calendar;
	cal.activeDiv = el;
	Calendar._C = cal;
	if (el.navtype != 300) with (Calendar) {
		addClass(el, "hilite active");
		addEvent(document, "mouseover", tableMouseOver);
		addEvent(document, "mousemove", tableMouseOver);
		addEvent(document, "mouseup", tableMouseUp);
	} else if (cal.isPopup) {
		cal._dragStart(ev);
	}
	Calendar.stopEvent(ev);
	if (el.navtype == -1 || el.navtype == 1) {
		cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
	} else if (el.navtype == -2 || el.navtype == 2) {
		cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
	} else {
		cal.timeout = null;
	}
};

Calendar.dayMouseDblClick = function(ev) {
	Calendar.cellClick(Calendar.getElement(ev));
	if (Calendar.is_ie) {
		document.selection.empty();
	}
};

Calendar.dayMouseOver = function(ev) {
	var el = Calendar.getElement(ev);
	if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
		return false;
	}
	if (el.ttip) {
		if (el.ttip.substr(0, 1) == "_") {
			var date = null;
			with (el.calendar.date) {
				date = new Date(getFullYear(), getMonth(), el.caldate);
			}
			el.ttip = date.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
		}
		el.calendar.tooltips.firstChild.data = el.ttip;
	}
	if (el.navtype != 300) {
		Calendar.addClass(el, "hilite");
		if (el.caldate) {
			Calendar.addClass(el.parentNode, "rowhilite");
		}
	}
	Calendar.stopEvent(ev);
};

Calendar.dayMouseOut = function(ev) {
	with (Calendar) {
		var el = getElement(ev);
		if (isRelated(el, ev) || _C || el.disabled) {
			return false;
		}
		removeClass(el, "hilite");
		if (el.caldate) {
			removeClass(el.parentNode, "rowhilite");
		}
		el.calendar.tooltips.firstChild.data = _TT["SEL_DATE"];
		stopEvent(ev);
	}
};

/**
 *  A generic "click" handler :) handles all types of buttons defined in this
 *  calendar.
 */
Calendar.cellClick = function(el) {
	var cal = el.calendar;
	var closing = false;
	var newdate = false;
	var date = null;
	if (typeof el.navtype == "undefined") {
		Calendar.removeClass(cal.currentDateEl, "selected");
		Calendar.addClass(el, "selected");
		closing = (cal.currentDateEl == el);
		if (!closing) {
			cal.currentDateEl = el;
		}
		cal.date.setDate(el.caldate);
		date = cal.date;
		newdate = true;
	} else {
		if (el.navtype == 200) {
			Calendar.removeClass(el, "hilite");
			cal.callCloseHandler();
			return;
		}
		date = (el.navtype == 0) ? new Date() : new Date(cal.date);
		var year = date.getFullYear();
		var mon = date.getMonth();
		function setMonth(m) {
			var day = date.getDate();
			var max = date.getMonthDays(m);
			if (day > max) {
				date.setDate(max);
			}
			date.setMonth(m);
		};
		switch (el.navtype) {
		    case -2:
			if (year > cal.minYear) {
				date.setFullYear(year - 1);
			}
			break;
		    case -1:
			if (mon > 0) {
				setMonth(mon - 1);
			} else if (year-- > cal.minYear) {
				date.setFullYear(year);
				setMonth(11);
			}
			break;
		    case 1:
			if (mon < 11) {
				setMonth(mon + 1);
			} else if (year < cal.maxYear) {
				date.setFullYear(year + 1);
				setMonth(0);
			}
			break;
		    case 2:
			if (year < cal.maxYear) {
				date.setFullYear(year + 1);
			}
			break;
		    case 100:
			cal.setMondayFirst(!cal.mondayFirst);
			return;
		}
		if (!date.equalsTo(cal.date)) {
			cal.setDate(date);
			newdate = el.navtype == 0;
		}
	}
	if (newdate) {
		cal.callHandler();
	}
	if (closing) {
		Calendar.removeClass(el, "hilite");
		cal.callCloseHandler();
	}
};

// END: CALENDAR STATIC FUNCTIONS

// BEGIN: CALENDAR OBJECT FUNCTIONS

/**
 *  This function creates the calendar inside the given parent.  If _par is
 *  null than it creates a popup calendar inside the BODY element.  If _par is
 *  an element, be it BODY, then it creates a non-popup calendar (still
 *  hidden).  Some properties need to be set before calling this function.
 */
Calendar.prototype.create = function (_par) {
	var parent = null;
	if (! _par) {
		// default parent is the document body, in which case we create
		// a popup calendar.
		parent = document.getElementsByTagName("body")[0];
		this.isPopup = true;
	} else {
		parent = _par;
		this.isPopup = false;
	}
	this.date = this.dateStr ? new Date(this.dateStr) : new Date();

	var table = Calendar.createElement("table");
	this.table = table;
	table.cellSpacing = 0;
	table.cellPadding = 0;
	table.calendar = this;
	Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);

	var div = Calendar.createElement("div");
	this.element = div;
	div.className = "calendar";
	if (this.isPopup) {
		div.style.position = "absolute";
		div.style.display = "none";
	}
	div.appendChild(table);

	var thead = Calendar.createElement("thead", table);
	var cell = null;
	var row = null;

	var cal = this;
	var hh = function (text, cs, navtype) {
		cell = Calendar.createElement("td", row);
		cell.colSpan = cs;
		cell.className = "button";
		Calendar._add_evs(cell);
		cell.calendar = cal;
		cell.navtype = navtype;
		if (text.substr(0, 1) != "&") {
			cell.appendChild(document.createTextNode(text));
		}
		else {
			// FIXME: dirty hack for entities
			cell.innerHTML = text;
		}
		return cell;
	};

	row = Calendar.createElement("tr", thead);
	var title_length = 6;
	(this.isPopup) && --title_length;
	(this.weekNumbers) && ++title_length;

	hh("-", 1, 100).ttip = Calendar._TT["TOGGLE"];
	this.title = hh("", title_length, 300);
	this.title.className = "title";
	if (this.isPopup) {
		this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
		this.title.style.cursor = "move";
		hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
	}

	row = Calendar.createElement("tr", thead);
	row.className = "headrow";

	this._nav_py = hh("&#x00ab;", 1, -2);
	this._nav_py.ttip = Calendar._TT["PREV_YEAR"];

	this._nav_pm = hh("&#x2039;", 1, -1);
	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];

	this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0);
	this._nav_now.ttip = Calendar._TT["GO_TODAY"];

	this._nav_nm = hh("&#x203a;", 1, 1);
	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];

	this._nav_ny = hh("&#x00bb;", 1, 2);
	this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"]

	// day names
	row = Calendar.createElement("tr", thead);
	row.className = "daynames";
	if (this.weekNumbers) {
		cell = Calendar.createElement("td", row);
		cell.className = "name wn";
		cell.appendChild(document.createTextNode(Calendar._TT["WK"]));
	}
	for (var i = 7; i > 0; --i) {
		cell = Calendar.createElement("td", row);
		cell.appendChild(document.createTextNode(""));
		if (!i) {
			cell.navtype = 100;
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}
	this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
	this._displayWeekdays();

	var tbody = Calendar.createElement("tbody", table);
	this.tbody = tbody;

	for (i = 6; i > 0; --i) {
		row = Calendar.createElement("tr", tbody);
		if (this.weekNumbers) {
			cell = Calendar.createElement("td", row);
			cell.appendChild(document.createTextNode(""));
		}
		for (var j = 7; j > 0; --j) {
			cell = Calendar.createElement("td", row);
			cell.appendChild(document.createTextNode(""));
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}

	var tfoot = Calendar.createElement("tfoot", table);

	row = Calendar.createElement("tr", tfoot);
	row.className = "footrow";

	cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
	cell.className = "ttip";
	if (this.isPopup) {
		cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
		cell.style.cursor = "move";
	}
	this.tooltips = cell;

	div = Calendar.createElement("div", this.element);
	this.monthsCombo = div;
	div.className = "combo";
	for (i = 0; i < Calendar._MN.length; ++i) {
		var mn = Calendar.createElement("div");
		mn.className = "label";
		mn.month = i;
		mn.appendChild(document.createTextNode(Calendar._MN3[i]));
		div.appendChild(mn);
	}

	div = Calendar.createElement("div", this.element);
	this.yearsCombo = div;
	div.className = "combo";
	for (i = 12; i > 0; --i) {
		var yr = Calendar.createElement("div");
		yr.className = "label";
		yr.appendChild(document.createTextNode(""));
		div.appendChild(yr);
	}

	this._init(this.mondayFirst, this.date);
	parent.appendChild(this.element);
};

/** keyboard navigation, only for popup calendars */
Calendar._keyEvent = function(ev) {
	if (!window.calendar) {
		return false;
	}
	(Calendar.is_ie) && (ev = window.event);
	var cal = window.calendar;
	var act = (Calendar.is_ie || ev.type == "keypress");
	if (ev.ctrlKey) {
		switch (ev.keyCode) {
		    case 37: // KEY left
			act && Calendar.cellClick(cal._nav_pm);
			break;
		    case 38: // KEY up
			act && Calendar.cellClick(cal._nav_py);
			break;
		    case 39: // KEY right
			act && Calendar.cellClick(cal._nav_nm);
			break;
		    case 40: // KEY down
			act && Calendar.cellClick(cal._nav_ny);
			break;
		    default:
			return false;
		}
	} else switch (ev.keyCode) {
	    case 32: // KEY space (now)
		Calendar.cellClick(cal._nav_now);
		break;
	    case 27: // KEY esc
		act && cal.hide();
		break;
	    case 37: // KEY left
	    case 38: // KEY up
	    case 39: // KEY right
	    case 40: // KEY down
		if (act) {
			var date = cal.date.getDate() - 1;
			var el = cal.currentDateEl;
			var ne = null;
			var prev = (ev.keyCode == 37) || (ev.keyCode == 38);
			switch (ev.keyCode) {
			    case 37: // KEY left
				(--date >= 0) && (ne = cal.ar_days[date]);
				break;
			    case 38: // KEY up
				date -= 7;
				(date >= 0) && (ne = cal.ar_days[date]);
				break;
			    case 39: // KEY right
				(++date < cal.ar_days.length) && (ne = cal.ar_days[date]);
				break;
			    case 40: // KEY down
				date += 7;
				(date < cal.ar_days.length) && (ne = cal.ar_days[date]);
				break;
			}
			if (!ne) {
				if (prev) {
					Calendar.cellClick(cal._nav_pm);
				} else {
					Calendar.cellClick(cal._nav_nm);
				}
				date = (prev) ? cal.date.getMonthDays() : 1;
				el = cal.currentDateEl;
				ne = cal.ar_days[date - 1];
			}
			Calendar.removeClass(el, "selected");
			Calendar.addClass(ne, "selected");
			cal.date.setDate(ne.caldate);
			cal.currentDateEl = ne;
		}
		break;
	    case 13: // KEY enter
		if (act) {
			cal.callHandler();
			cal.hide();
		}
		break;
	    default:
		return false;
	}
	Calendar.stopEvent(ev);
};

/**
 *  (RE)Initializes the calendar to the given date and style (if mondayFirst is
 *  true it makes Monday the first day of week, otherwise the weeks start on
 *  Sunday.
 */
Calendar.prototype._init = function (mondayFirst, date) {
	var today = new Date();
	var year = date.getFullYear();
	if (year < this.minYear) {
		year = this.minYear;
		date.setFullYear(year);
	} else if (year > this.maxYear) {
		year = this.maxYear;
		date.setFullYear(year);
	}
	this.mondayFirst = mondayFirst;
	this.date = new Date(date);
	var month = date.getMonth();
	var mday = date.getDate();
	var no_days = date.getMonthDays();
	date.setDate(1);
	var wday = date.getDay();
	var MON = mondayFirst ? 1 : 0;
	var SAT = mondayFirst ? 5 : 6;
	var SUN = mondayFirst ? 6 : 0;
	if (mondayFirst) {
		wday = (wday > 0) ? (wday - 1) : 6;
	}
	var iday = 1;
	var row = this.tbody.firstChild;
	var MN = Calendar._MN3[month];
	var hasToday = ((today.getFullYear() == year) && (today.getMonth() == month));
	var todayDate = today.getDate();
	var week_number = date.getWeekNumber();
	var ar_days = new Array();
	for (var i = 0; i < 6; ++i) {
		if (iday > no_days) {
			row.className = "emptyrow";
			row = row.nextSibling;
			continue;
		}
		var cell = row.firstChild;
		if (this.weekNumbers) {
			cell.className = "day wn";
			cell.firstChild.data = week_number;
			cell = cell.nextSibling;
		}
		++week_number;
		row.className = "daysrow";
		for (var j = 0; j < 7; ++j) {
			cell.className = "day";
			if ((!i && j < wday) || iday > no_days) {
				// cell.className = "emptycell";
				cell.innerHTML = "&nbsp;";
				cell.disabled = true;
				cell = cell.nextSibling;
				continue;
			}
			cell.disabled = false;
			cell.firstChild.data = iday;
			if (typeof this.checkDisabled == "function") {
				date.setDate(iday);
				if (this.checkDisabled(date)) {
					cell.className += " disabled";
					cell.disabled = true;
				}
			}
			if (!cell.disabled) {
				ar_days[ar_days.length] = cell;
				cell.caldate = iday;
				cell.ttip = "_";
				if (iday == mday) {
					cell.className += " selected";
					this.currentDateEl = cell;
				}
				if (hasToday && (iday == todayDate)) {
					cell.className += " today";
					cell.ttip += Calendar._TT["PART_TODAY"];
				}
				if (wday == SAT || wday == SUN) {
					cell.className += " weekend";
				}
			}
			++iday;
			((++wday) ^ 7) || (wday = 0);
			cell = cell.nextSibling;
		}
		row = row.nextSibling;
	}
	this.ar_days = ar_days;
	this.title.firstChild.data = Calendar._MN[month] + ", " + year;
	// PROFILE
	// this.tooltips.firstChild.data = "Generated in " + ((new Date()) - today) + " ms";
};

/**
 *  Calls _init function above for going to a certain date (but only if the
 *  date is different than the currently selected one).
 */
Calendar.prototype.setDate = function (date) {
	if (!date.equalsTo(this.date)) {
		this._init(this.mondayFirst, date);
	}
};

/** Modifies the "mondayFirst" parameter (EU/US style). */
Calendar.prototype.setMondayFirst = function (mondayFirst) {
	this._init(mondayFirst, this.date);
	this._displayWeekdays();
};

/**
 *  Allows customization of what dates are enabled.  The "unaryFunction"
 *  parameter must be a function object that receives the date (as a JS Date
 *  object) and returns a boolean value.  If the returned value is true then
 *  the passed date will be marked as disabled.
 */
Calendar.prototype.setDisabledHandler = function (unaryFunction) {
	this.checkDisabled = unaryFunction;
};

/** Customization of allowed year range for the calendar. */
Calendar.prototype.setRange = function (a, z) {
	this.minYear = a;
	this.maxYear = z;
};

/** Calls the first user handler (selectedHandler). */
Calendar.prototype.callHandler = function () {
	if (this.onSelected) {
		this.onSelected(this, this.date.print(this.dateFormat));
	}
};

/** Calls the second user handler (closeHandler). */
Calendar.prototype.callCloseHandler = function () {
	if (this.onClose) {
		this.onClose(this);
	}
	this.hideShowCovered();
};

/** Removes the calendar object from the DOM tree and destroys it. */
Calendar.prototype.destroy = function () {
	var el = this.element.parentNode;
	el.removeChild(this.element);
	Calendar._C = null;
	delete el;
};

/**
 *  Moves the calendar element to a different section in the DOM tree (changes
 *  its parent).
 */
Calendar.prototype.reparent = function (new_parent) {
	var el = this.element;
	el.parentNode.removeChild(el);
	new_parent.appendChild(el);
};

// This gets called when the user presses a mouse button anywhere in the
// document, if the calendar is shown.  If the click was outside the open
// calendar this function closes it.
Calendar._checkCalendar = function(ev) {
	if (!window.calendar) {
		return false;
	}
	var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
	for (; el != null && el != calendar.element; el = el.parentNode);
	if (el == null) {
		// calls closeHandler which should hide the calendar.
		window.calendar.callCloseHandler();
		Calendar.stopEvent(ev);
	}
};

/** Shows the calendar. */
Calendar.prototype.show = function () {
	var rows = this.table.getElementsByTagName("tr");
	for (var i = rows.length; i > 0;) {
		var row = rows[--i];
		Calendar.removeClass(row, "rowhilite");
		var cells = row.getElementsByTagName("td");
		for (var j = cells.length; j > 0;) {
			var cell = cells[--j];
			Calendar.removeClass(cell, "hilite");
			Calendar.removeClass(cell, "active");
		}
	}
	this.element.style.display = "block";
	this.hidden = false;
	if (this.isPopup) {
		window.calendar = this;
		Calendar.addEvent(document, "keydown", Calendar._keyEvent);
		Calendar.addEvent(document, "keypress", Calendar._keyEvent);
		Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.hideShowCovered();
};

/**
 *  Hides the calendar.  Also removes any "hilite" from the class of any TD
 *  element.
 */
Calendar.prototype.hide = function () {
	if (this.isPopup) {
		Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
		Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
		Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.element.style.display = "none";
	this.hidden = true;
	this.hideShowCovered();
};

/**
 *  Shows the calendar at a given absolute position (beware that, depending on
 *  the calendar element style -- position property -- this might be relative
 *  to the parent's containing rectangle).
 */
Calendar.prototype.showAt = function (x, y) {
	var s = this.element.style;
	s.left = x + "px";
	s.top = y + "px";
	this.show();
};

/** Shows the calendar near a given element. */
Calendar.prototype.showAtElement = function (el) {
	var p = Calendar.getAbsolutePos(el);
	this.showAt(p.x, p.y + el.offsetHeight);
};

/** Customizes the date format. */
Calendar.prototype.setDateFormat = function (str) {
	this.dateFormat = str;
};

/** Customizes the tooltip date format. */
Calendar.prototype.setTtDateFormat = function (str) {
	this.ttDateFormat = str;
};

/**
 *  Tries to identify the date represented in a string.  If successful it also
 *  calls this.setDate which moves the calendar to the given date.
 */
Calendar.prototype.parseDate = function (str, fmt) {
	var y = 0;
	var m = -1;
	var d = 0;
	var a = str.split(/\W+/);
	if (!fmt) {
		fmt = this.dateFormat;
	}
	var b = fmt.split(/\W+/);
	var i = 0, j = 0;
	for (i = 0; i < a.length; ++i) {
		if (b[i] == "D" || b[i] == "DD") {
			continue;
		}
		if (b[i] == "d" || b[i] == "dd") {
			d = parseInt(a[i]);
		}
		if (b[i] == "m" || b[i] == "mm") {
			m = parseInt(a[i]) - 1;
		}
		if (b[i] == "y") {
			y = parseInt(a[i]);
		}
		if (b[i] == "yy") {
			y = parseInt(a[i]) + 1900;
		}
		if (b[i] == "M" || b[i] == "MM") {
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
			}
		}
	}
	if (y != 0 && m != -1 && d != 0) {
		this.setDate(new Date(y, m, d));
		return;
	}
	y = 0; m = -1; d = 0;
	for (i = 0; i < a.length; ++i) {
		if (a[i].search(/[a-zA-Z]+/) != -1) {
			var t = -1;
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
			}
			if (t != -1) {
				if (m != -1) {
					d = m+1;
				}
				m = t;
			}
		} else if (parseInt(a[i]) <= 12 && m == -1) {
			m = a[i]-1;
		} else if (parseInt(a[i]) > 31 && y == 0) {
			y = a[i];
		} else if (d == 0) {
			d = a[i];
		}
	}
	if (y == 0) {
		var today = new Date();
		y = today.getFullYear();
	}
	if (m != -1 && d != 0) {
		this.setDate(new Date(y, m, d));
	}
};

Calendar.prototype.hideShowCovered = function () {
	var tags = new Array("applet", "iframe", "select");
	var el = this.element;

	var p = Calendar.getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	for (var k = tags.length; k > 0; ) {
		var ar = document.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];

			p = Calendar.getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;

			if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				cc.style.visibility = "visible";
			} else {
				cc.style.visibility = "hidden";
			}
		}
	}
};

/** Internal function; it displays the bar with the names of the weekday. */
Calendar.prototype._displayWeekdays = function () {
	var MON = this.mondayFirst ? 0 : 1;
	var SUN = this.mondayFirst ? 6 : 0;
	var SAT = this.mondayFirst ? 5 : 6;
	var cell = this.firstdayname;
	for (var i = 0; i < 7; ++i) {
		cell.className = "day name";
		if (!i) {
			cell.ttip = this.mondayFirst ? Calendar._TT["SUN_FIRST"] : Calendar._TT["MON_FIRST"];
			cell.navtype = 100;
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
		if (i == SUN || i == SAT) {
			Calendar.addClass(cell, "weekend");
		}
		cell.firstChild.data = Calendar._DN3[i + 1 - MON];
		cell = cell.nextSibling;
	}
};

/** Internal function.  Hides all combo boxes that might be displayed. */
Calendar.prototype._hideCombos = function () {
	this.monthsCombo.style.display = "none";
	this.yearsCombo.style.display = "none";
};

/** Internal function.  Starts dragging the element. */
Calendar.prototype._dragStart = function (ev) {
	if (this.dragging) {
		return;
	}
	this.dragging = true;
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posY = ev.clientY + window.scrollY;
		posX = ev.clientX + window.scrollX;
	}
	var st = this.element.style;
	this.xOffs = posX - parseInt(st.left);
	this.yOffs = posY - parseInt(st.top);
	with (Calendar) {
		addEvent(document, "mousemove", calDragIt);
		addEvent(document, "mouseover", stopEvent);
		addEvent(document, "mouseup", calDragEnd);
	}
};

// BEGIN: DATE OBJECT PATCHES

/** Adds the number of days array to the Date object. */
Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);

/** Constants used for time computations */
Date.SECOND = 1000 /* milliseconds */;
Date.MINUTE = 60 * Date.SECOND;
Date.HOUR   = 60 * Date.MINUTE;
Date.DAY    = 24 * Date.HOUR;
Date.WEEK   =  7 * Date.DAY;

/** Returns the number of days in the current month */
Date.prototype.getMonthDays = function(month) {
	var year = this.getFullYear();
	if (typeof month == "undefined") {
		month = this.getMonth();
	}
	if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
		return 29;
	} else {
		return Date._MD[month];
	}
};

/** Returns the number of the week.  The algorithm was "stolen" from PPK's
 * website, hope it's correct :) http://www.xs4all.nl/~ppk/js/week.html */
Date.prototype.getWeekNumber = function() {
	var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var then = new Date(this.getFullYear(), 0, 1, 0, 0, 0);
	var time = now - then;
	var day = then.getDay();
	(day > 3) && (day -= 4) || (day += 3);
	return Math.round(((time / Date.DAY) + day) / 7);
};

/** Checks dates equality (ignores time) */
Date.prototype.equalsTo = function(date) {
	return ((this.getFullYear() == date.getFullYear()) &&
		(this.getMonth() == date.getMonth()) &&
		(this.getDate() == date.getDate()));
};

/** Prints the date in a string according to the given format. */
Date.prototype.print = function (frm) {
	var str = new String(frm);
	var m = this.getMonth();
	var d = this.getDate();
	var y = this.getFullYear();
	var wn = this.getWeekNumber();
	var w = this.getDay();
	var s = new Array();
	s["d"] = d;
	s["dd"] = (d < 10) ? ("0" + d) : d;
	s["m"] = 1+m;
	s["mm"] = (m < 9) ? ("0" + (1+m)) : (1+m);
	s["y"] = y;
	s["yy"] = new String(y).substr(2, 2);
	s["w"] = wn;
	s["ww"] = (wn < 10) ? ("0" + wn) : wn;
	with (Calendar) {
		s["D"] = _DN3[w];
		s["DD"] = _DN[w];
		s["M"] = _MN3[m];
		s["MM"] = _MN[m];
	}
	var re = /(.*)(\W|^)(d|dd|m|mm|y|yy|MM|M|DD|D|w|ww)(\W|$)(.*)/;
	while (re.exec(str) != null) {
		str = RegExp.$1 + RegExp.$2 + s[RegExp.$3] + RegExp.$4 + RegExp.$5;
	}
	return str;
};

// END: DATE OBJECT PATCHES

// global object that remembers the calendar
window.calendar = null;

// This function shows the calendar under the element having the given id.
// It takes care of catching "mousedown" signals on document and hiding the
// calendar if the click was outside.
function showCalendar(id) {
  var el = document.getElementById(id);
  if (calendar != null) {
    // we already have some calendar created
    calendar.hide();                 // so we hide it first.
  } else {
    // first-time call, create the calendar.
    var cal = new Calendar(false, null, selected, closeHandler);
    // uncomment the following line to hide the week numbers
    // cal.weekNumbers = false;
    calendar = cal;                  // remember it in the global var
    cal.setRange(1900, 2070);        // min/max year allowed.
    cal.create();
  }
//  calendar.setDateFormat(format);    // set the specified date format
  calendar.parseDate(el.value);      // try to parse the text in field
  calendar.sel = el;                 // inform it what input field we use
  calendar.showAtElement(el);        // show the calendar below it

  return false;
}

// This function gets called when the end-user clicks on some date.
function selected(cal, date) {
  cal.sel.value = date; // just update the date in the input field.
  cal.callCloseHandler();
}

// And this gets called when the end-user clicks on the _selected_ date,
// or clicks on the "Close" button.  It just hides the calendar without
// destroying it.
function closeHandler(cal) {
  cal.hide();                        // hide the calendar
}

/*
-----------------------------------------------------------------------------
	dTree 2.0  |  www.destroydrop.com/javascript/tree/
-----------------------------------------------------------------------------
	Copyright (c) 2002 Geir Landrö

	This script can be used freely as long as all copyright messages are
	intact.
-----------------------------------------------------------------------------
*/


// Node object
function Node(id, pid, name, url, title, target, isopen, img)
{
	this.id			= id;
	this.pid		= pid;
	this.name		= name;
	this.url		= url;
	this.title	= title;
	this.target	= target;
	this.img		= img;

	this._io		= isopen || false;
	this._ls		= false;
	this._hc		= false;
	this._is		= false;
}


// Tree object
function dTree(objName)
{

// Variables
// ----------------------------------------------------------------------------

	this.arrNodes			= [];
	this.arrRecursed	= [];
	this.arrIcons			= [];
	this.rootNode			= -1;
	this.strOutput		= '';
	this.selectedNode	= null;

	this.instanceName = objName;
	this.imgFolder		= 'img/';
	this.target				= null;
	this.hasLines			= true;
	this.clickSelect	= true;
	this.folderLinks	= true;
	this.useCookies		= true;


// Functions
// ----------------------------------------------------------------------------


	// Adds a new node to the node array
	this.add = function(id, pid, name, url, title, target, isopen, img)
	{
		this.arrNodes[this.arrNodes.length] = new Node(id, pid, name, url, title, target, isopen, img);
	}

	// Outputs the tree to the page
	this.draw = function()
	{
		if (document.getElementById)
		{
			this.preloadIcons();
			// if (this.useCookies) this.selectedNode = this.getSelected();
			this.addNode(this.rootNode);

			document.writeln(this.strOutput);
		}
		else
		{
			document.writeln('Browser not supported.');
		}
	}

	this.openAll = function()
	{
		this.oAll(true);
	}

	this.closeAll = function()
	{
		this.oAll(false);
	}


// Private
// ----------------------------------------------------------------------------

	// Prealoads images that are used in the tree
	this.preloadIcons = function()
	{
		if (this.hasLines)
		{
			this.arrIcons[0] = new Image();
			this.arrIcons[0].src = this.imgFolder + 'plus.gif';
			this.arrIcons[1] = new Image();
			this.arrIcons[1].src = this.imgFolder + 'plusbottom.gif';
			this.arrIcons[2] = new Image();
			this.arrIcons[2].src = this.imgFolder + 'minus.gif';
			this.arrIcons[3] = new Image();
			this.arrIcons[3].src = this.imgFolder + 'minusbottom.gif';
		}
		else
		{
			this.arrIcons[0] = new Image();
			this.arrIcons[0].src = this.imgFolder + 'nolines_plus.gif';
			this.arrIcons[1] = new Image();
			this.arrIcons[1].src = this.imgFolder + 'nolines_plus.gif';
			this.arrIcons[2] = new Image();
			this.arrIcons[2].src = this.imgFolder + 'nolines_minus.gif';
			this.arrIcons[3] = new Image();
			this.arrIcons[3].src = this.imgFolder + 'nolines_minus.gif';
		}
		this.arrIcons[4] = new Image();
		this.arrIcons[4].src = this.imgFolder + 'folder.gif';
		this.arrIcons[5] = new Image();
		this.arrIcons[5].src = this.imgFolder + 'folderopen.gif';
	}

	// Recursive function that creates the tree structure
	this.addNode = function(pNode)
	{
		for (var n=0; n<this.arrNodes.length; n++)
		{
			if (this.arrNodes[n].pid == pNode)
			{
				var cn = this.arrNodes[n];
				cn._hc = this.hasChildren(cn);
				cn._ls = (this.hasLines) ? this.lastSibling(cn) : false;
				if (cn._hc && !cn._io && this.useCookies) cn._io = this.isOpen(cn.id);

				if (this.clickSelect && cn.id == this.selectedNode)
				{
						cn._is = true;
//						this.selectedNode = n;
				}

				if (!this.folderLinks && cn._hc) cn.url = null;


				// If the current node is not the root
				if (this.rootNode != cn.pid)
				{
					// Write out line & empty icons
					for (r=0; r<this.arrRecursed.length; r++)
						this.strOutput += '<img src="' + this.imgFolder + ( (this.arrRecursed[r] == 1 && this.hasLines) ? 'line' : 'empty' ) + '.gif" alt="" />';

					// Line & empty icons
					(cn._ls) ? this.arrRecursed.push(0) : this.arrRecursed.push(1);

					// Write out join icons
					if (cn._hc)
					{
						this.strOutput += '<a href="javascript: ' + this.instanceName + '.o(' + n + ');">'
							+ '<img border="0" id="j' + this.instanceName + n + '" src="' + this.imgFolder;
						if (!this.hasLines)
							this.strOutput += 'nolines_';

						this.strOutput += ( (cn._io) ? ((cn._ls && this.hasLines) ? 'minusbottom' : 'minus') : ((cn._ls && this.hasLines) ? 'plusbottom' : 'plus' ) )
							+ '.gif" alt="" /></a>';
					}
					else
						this.strOutput += '<img border="0" src="' + this.imgFolder + ( (this.hasLines) ? ((cn._ls) ? 'joinbottom' : 'join' ) : 'empty') + '.gif" alt="" />';
				}

				// Start the node link
				if (cn.url)
				{
					this.strOutput += '<a href="' + cn.url + '"';
					if (cn.title) this.strOutput += ' title="' + cn.title + '"';
					if (cn.target) this.strOutput += ' target="' + cn.target + '"';
					if (this.target && !cn.target) this.strOutput += ' target="' + this.target + '"';

					// If hightlight link is on
					if (this.clickSelect)
					{
						if (cn._hc)
						{
							if (this.folderLinks)
								this.strOutput += ' onclick="javascript: ' + this.instanceName + '.s(' + n + ');"';
						}
						else
						{
							this.strOutput += ' onclick="javascript: ' + this.instanceName + '.s(' + n + ');"';
						}
					}

					this.strOutput += '>';
				}
/*				if ((!this.folderLinks || !cn.url) && cn._hc && cn.pid != this.rootNode)
				{
					this.strOutput += '<a href="javascript: ' + this.instanceName + '.o(' + n + ');">';
				} // this fucks up stuff */

				// Write out folder & page icons
				this.strOutput += '<img border="0" id="i' + this.instanceName + n + '" src="' + this.imgFolder;
				this.strOutput += (cn.img) ? cn.img : ((this.rootNode == cn.pid) ? 'base' : (cn._hc) ? ((cn._io) ? 'folderopen' : 'folder') : 'folder') + '.gif';
				this.strOutput += '" alt="" />';

				// Write out span
				this.strOutput += '<span id="s' + this.instanceName + n + '" class="' + ((this.clickSelect) ? ((cn._is ? 'nodeSel' : 'node')) : 'node') + '">';


				// Write out node name
				this.strOutput += cn.name;

					this.strOutput += '</span>';

				// Close the link
				if (cn.url || (!this.folderLinks && cn._hc)) this.strOutput += '</a>';

				this.strOutput += '<br />\n';

				// If node has children write out divs and go deeper
				if (cn._hc)
				{
					this.strOutput += '<div id="d' + this.instanceName + n + '" style="display:'
					+ ((this.rootNode == cn.pid || cn._io) ? 'block' : 'none')
					+ ';">\n';
					this.addNode(cn.id);
					this.strOutput += '</div>\n';
				}
				this.arrRecursed.pop();
			}
		}
	}

	// Checks if a node has any children
	this.hasChildren = function(node)
	{
		for (n=0; n<this.arrNodes.length; n++)
			if (this.arrNodes[n].pid == node.id) return true;
		return false;
	}

	// Checks if a node is the last sibling
	this.lastSibling = function(node)
	{
		var lastId;
		for (n=0; n< this.arrNodes.length; n++)
			if (this.arrNodes[n].pid == node.pid) lastId = this.arrNodes[n].id;
		if (lastId==node.id) return true;
		return false;
	}

	// Checks if a node id is in a cookie
	this.isOpen = function(id)
	{
		openNodes = this.getCookie('co' + this.instanceName).split('.');
		for (n=0;n<openNodes.length;n++)
			if (openNodes[n] == id) return true;
		return false;
	}

	// Checks if the node is selected
	this.isSelected = function(id)
	{
		selectedNode = this.getCookie('cs' + this.instanceName);
		if (selectedNode)
		{
			if (id==selectedNode)
			{
				this.selectedNode = id;
				return true
			}
		}
		return false;
	}

	// Returns the selected node
	this.getSelected = function()
	{
		selectedNode = this.getCookie('cs' + this.instanceName);
		if (selectedNode)	return selectedNode;
		return null;
	}

	// Highlights the selected node
	this.s = function(id)
	{
		cn = this.arrNodes[id];
		if (this.selectedNode != id)
		{
			if (this.selectedNode)
			{
				eOldSpan = document.getElementById("s" + this.instanceName + this.selectedNode);
				eOldSpan.className = "node";
			}

			eNewSpan = document.getElementById("s" + this.instanceName + id);
			eNewSpan.className = "nodeSel";

			this.selectedNode = id;
			if (this.useCookies) this.setCookie('cs' + this.instanceName, cn.id);
		}
	}

	// Toggle Open or close
	this.o = function(id)
	{
		cn = this.arrNodes[id];

		(cn._io) ? this.nodeClose(id,cn._ls) : this.nodeOpen(id,cn._ls);
		cn._io = !cn._io;

		if (this.useCookies) this.updateCookie();
	}

	// Open or close all nodes
	this.oAll = function(open)
	{
		for (n=0;n<this.arrNodes.length;n++)
		{
			if (this.arrNodes[n]._hc && this.arrNodes[n].pid != this.rootNode)
			{
				if (open)
				{
					this.nodeOpen(n, this.arrNodes[n]._ls);
					this.arrNodes[n]._io = true;
				}
				else
				{
					this.nodeClose(n, this.arrNodes[n]._ls);
					this.arrNodes[n]._io = false;
				}
			}
		}
		if (this.useCookies) this.updateCookie();
	}

	// Open a node
	this.nodeOpen = function(id, bottom)
	{
		eDiv	= document.getElementById('d' + this.instanceName + id);
		eJoin	= document.getElementById('j' + this.instanceName + id);
		eIcon	= document.getElementById('i' + this.instanceName + id);
		eJoin.src = (bottom) ?  this.arrIcons[3].src : this.arrIcons[2].src;
		if (!this.arrNodes[id].img) eIcon.src = this.arrIcons[5].src;
		eDiv.style.display = 'block';
	}

	// Close a node
	this.nodeClose = function(id, bottom)
	{
		eDiv	= document.getElementById('d' + this.instanceName + id);
		eJoin	= document.getElementById('j' + this.instanceName + id);
		eIcon	= document.getElementById('i' + this.instanceName + id);
		eJoin.src = (bottom) ? this.arrIcons[1].src : this.arrIcons[0].src;
		if (!this.arrNodes[id].img) eIcon.src = this.arrIcons[4].src;
		eDiv.style.display = 'none';
	}

	// Clears a cookie
	this.clearCookie = function()
	{
		var now = new Date();
		var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);
		this.setCookie('co'+this.instanceName, 'cookieValue', yesterday);
		this.setCookie('cs'+this.instanceName, 'cookieValue', yesterday);
	}

	// Sets value in a cookie
	this.setCookie = function(cookieName, cookieValue, expires, path, domain, secure) {
		document.cookie =
			escape(cookieName) + '=' + escape(cookieValue)
			+ (expires ? '; expires=' + expires.toGMTString() : '')
			+ (path ? '; path=' + path : '')
			+ (domain ? '; domain=' + domain : '')
			+ (secure ? '; secure' : '');
	}

	// Gets a value from a cookie
	this.getCookie = function(cookieName) {
		var cookieValue = '';
		var posName = document.cookie.indexOf(escape(cookieName) + '=');
		if (posName != -1)
		{
			var posValue = posName + (escape(cookieName) + '=').length;
			var endPos = document.cookie.indexOf(';', posValue);
			if (endPos != -1)
				cookieValue = unescape(document.cookie.substring(posValue, endPos));
			else
				cookieValue = unescape(document.cookie.substring(posValue));
		}
		return (cookieValue);
	}

	// Returns ids of open nodes as a string
	this.updateCookie = function()
	{
		sReturn = '';
		for (n=0;n<this.arrNodes.length;n++)
		{
			if (this.arrNodes[n]._io && this.arrNodes[n].pid != this.rootNode)
			{
				if (sReturn) sReturn += '.';
				sReturn += this.arrNodes[n].id;
			}
		}
		this.setCookie('co' + this.instanceName, sReturn);
	}

// tree object ends
}


// Functions used by the dTree object but are not really a part of it
// ------------------------------------------------------------------------------------------------

// Push and pop for arrays is not implemented in Internet Explorer
if (!Array.prototype.push) {
	Array.prototype.push = function array_push() {
		for(var i=0;i<arguments.length;i++)
			this[this.length]=arguments[i];
		return this.length;
	}
}
if (!Array.prototype.pop) {
	Array.prototype.pop = function array_pop() {
		lastElement = this[this.length-1];
		this.length = Math.max(this.length-1,0);
		return lastElement;
	}
}


/********************* ********  HTML AREA  ******** ***********************************/

//
// htmlArea v3.0 - Copyright (c) 2002 interactivetools.com, inc.
// This copyright notice MUST stay intact for use (see license.txt).
//
// A free WYSIWYG editor replacement for <textarea> fields.
// For full source code and docs, visit http://www.interactivetools.com/
//
// Version 3.0 developed by Mihai Bazon for InteractiveTools.
//           http://students.infoiasi.ro/~mishoo
//
// $Id: common.js,v 1.34 2005/03/02 14:39:39 kzed Exp $

// Creates a new HTMLArea object.  Tries to replace the textarea with the given
// ID with it.
function HTMLArea(textarea, config) {
	if (HTMLArea.checkSupportedBrowser()) {
		if (typeof config == "undefined") {
			this.config = new HTMLArea.Config();
		} else {
			this.config = config;
		}
		if (this.config.debug) {
			// alert("DEBUG ON!!");
		}
		this._htmlArea = null;
		this._textArea = textarea;
		this._mode = "wysiwyg";
	}
};

HTMLArea.Config = function () {
	this.version = "3.0";

	//this.width = "auto";
	//this.height = "auto";
	this.width = "430px";
	this.height = "200px";

	// the next parameter specifies whether the toolbar should be included
	// in the size or not.
	this.sizeIncludesToolbar = true;

	this.bodyStyle = "background-color: #fff; font-family: verdana,sans-serif; font-size: 10pt;";
	this.editorURL = "";

	// URL-s
	this.imgURL = g_root + 'editor/images/';
	this.popupURL = g_root + "editor/popups/";

	this.debug = 0;

	this.replaceNextLines = 0;
	this.plainTextInput = 0;

	/*this.toolbar = [ [ "fontname", "space" ],
			 [ "fontsize", "space" ],
			 [ "formatblock", "space"],
			 [ "bold", "italic", "underline", "separator" ],
			 [ "strikethrough", "subscript", "superscript", "linebreak" ],
			 [ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator" ],
			 [ "orderedlist", "unorderedlist", "outdent", "indent", "separator" ],
			 [ "forecolor", "backcolor", "textindicator", "separator" ],
			 [ "horizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator" ],
			 [ "popupeditor", "about" ]
		];*/
	this.toolbar = [ [ "fontname", "space" ],
			 [ "fontsize", "space" ],
			 [ "formatblock", "space"],
			 [ "bold", "italic", "underline", "separator" ],
			 [ "strikethrough", "subscript", "superscript", "linebreak" ],
			 [ "justifyleft", "justifycenter", "justifyright", "justifyfull", "separator" ],
			 [ "orderedlist", "unorderedlist", "outdent", "indent", "separator" ],
			 [ "forecolor", "backcolor", "textindicator", "separator" ],
			 [ "horizontalrule", "createlink", "insertimage", "inserttable", "htmlmode", "separator","popupeditor","word" ]
		];

	this.fontname = {
		"Arial":           'arial,helvetica,sans-serif',
		"Courier New":     'courier new,courier,monospace',
		"Georgia":         'georgia,times new roman,times,serif',
		"Tahoma":          'tahoma,arial,helvetica,sans-serif',
		"Times New Roman": 'times new roman,times,serif',
		"Verdana":         'verdana,arial,helvetica,sans-serif',
		"impact":          'impact',
		"WingDings":       'wingdings'
	};

	this.fontsize = {
		"1 (8 pt)":  "1",
		"2 (10 pt)": "2",
		"3 (12 pt)": "3",
		"4 (14 pt)": "4",
		"5 (18 pt)": "5",
		"6 (24 pt)": "6",
		"7 (36 pt)": "7"
	};

	this.formatblock = {
		"Heading 1": "h1",
		"Heading 2": "h2",
		"Heading 3": "h3",
		"Heading 4": "h4",
		"Heading 5": "h5",
		"Heading 6": "h6",
		"Normal": "p",
		"Address": "address",
		"Formatted": "pre"
	};

	//      ID              CMD                      ToolTip               Icon                        Enabled in text mode?
	this.btnList = {
		bold:           ["Bold",                 "Bold",               "ed_format_bold.gif",       false],
		italic:         ["Italic",               "Italic",             "ed_format_italic.gif",     false],
		underline:      ["Underline",            "Underline",          "ed_format_underline.gif",  false],
		strikethrough:  ["StrikeThrough",        "Strikethrough",      "ed_format_strike.gif",     false],
		subscript:      ["SubScript",            "Subscript",          "ed_format_sub.gif",        false],
		superscript:    ["SuperScript",          "Superscript",        "ed_format_sup.gif",        false],
		justifyleft:    ["JustifyLeft",          "Justify Left",       "ed_align_left.gif",        false],
		justifycenter:  ["JustifyCenter",        "Justify Center",     "ed_align_center.gif",      false],
		justifyright:   ["JustifyRight",         "Justify Right",      "ed_align_right.gif",       false],
		justifyfull:    ["JustifyFull",          "Justify Full",       "ed_align_justify.gif",     false],
		orderedlist:    ["InsertOrderedList",    "Ordered List",       "ed_list_num.gif",          false],
		unorderedlist:  ["InsertUnorderedList",  "Bulleted List",      "ed_list_bullet.gif",       false],
		outdent:        ["Outdent",              "Decrease Indent",    "ed_indent_less.gif",       false],
		indent:         ["Indent",               "Increase Indent",    "ed_indent_more.gif",       false],
		forecolor:      ["ForeColor",            "Font Color",         "ed_color_fg.gif",          false],
		backcolor:      ["BackColor",            "Background Color",   "ed_color_bg.gif",          false],
		horizontalrule: ["InsertHorizontalRule", "Horizontal Rule",    "ed_hr.gif",                false],
		createlink:     ["CreateLink",           "Insert Web Link",    "ed_link.gif",              false],
		insertimage:    ["InsertImage",          "Insert Image",       "ed_image.gif",             false],
		inserttable:    ["InsertTable",          "Insert Table",       "insert_table.gif",         false],
		htmlmode:       ["HtmlMode",             "Toggle HTML Source", "ed_html.gif",              true],
		popupeditor:    ["popupeditor",          "Enlarge Editor",     "fullscreen_maximize.gif",  true],
		word:			["word",				 "Import a Word document", "ed_word.png",	       true],
		about:          ["about",                "About this editor",  "ed_about.gif",             true],
		help:           ["showhelp",             "Help using editor",  "ed_help.gif",              true]
	};

	// initialize tooltips from the I18N module
	for (var i in this.btnList) {
		var btn = this.btnList[i];
		if (typeof HTMLArea.I18N.tooltips[i] != "undefined") {
			btn[1] = HTMLArea.I18N.tooltips[i];
		}
	}
};

/** Helper function: replace all TEXTAREA-s in the document with HTMLArea-s. */
HTMLArea.replaceAll = function() {
	var tas = document.getElementsByTagName("textarea");
	for (var i = tas.length; i > 0; (new HTMLArea(tas[--i])).generate());
};

// Creates the toolbar and appends it to the _htmlarea
HTMLArea.prototype._createToolbar = function () {
	var editor = this;	// to access this in nested functions

	var toolbar = document.createElement("div");
	this._toolbar = toolbar;
	toolbar.className = "toolbar";
	toolbar.unselectable = "1";
	if (editor.config.debug) {
		toolbar.style.border = "1px solid red";
	}
	var tb_row = null;
	var tb_objects = new Object();
	this._toolbarObjects = tb_objects;

	// creates a new line in the toolbar
	function newLine() {
		var table = document.createElement("table");
		table.border = "0px";
		table.cellSpacing = "0px";
		table.cellPadding = "0px";
		toolbar.appendChild(table);
		// TBODY is required for IE, otherwise you don't see anything
		// in the TABLE.
		var tb_body = document.createElement("tbody");
		table.appendChild(tb_body);
		tb_row = document.createElement("tr");
		tb_body.appendChild(tb_row);
	};
	// init first line
	newLine();

	// appends a new button to toolbar
	function createButton(txt) {
		// updates the state of a toolbar element
		function setButtonStatus(id, newval) {
			var oldval = this[id];
			var el = this.element;
			if (oldval != newval) {
				switch (id) {
				    case "enabled":
					if (newval) {
						HTMLArea._removeClass(el, "buttonDisabled");
						el.disabled = false;
					} else {
						HTMLArea._addClass(el, "buttonDisabled");
						el.disabled = true;
					}
					break;
				    case "active":
					if (newval) {
						HTMLArea._addClass(el, "buttonPressed");
					} else {
						HTMLArea._removeClass(el, "buttonPressed");
					}
					break;
				}
				this[id] = newval;
			}
		};
		// this function will handle creation of combo boxes
		function createSelect() {
			var options = null;
			var el = null;
			var cmd = null;
			switch (txt) {
			    case "fontsize":
			    case "fontname":
			    case "formatblock":
				options = editor.config[txt]; // HACK ;)
				cmd = txt;
				break;
			}
			if (options) {
				el = document.createElement("select");
				var obj = {
					name: txt,     // field name
					element: el,   // the UI element (SELECT)
					enabled: true, // is it enabled?
					text: false,   // enabled in text mode?
					cmd: cmd,      // command ID
					state: setButtonStatus // for changing state
				};
				tb_objects[txt] = obj;
				for (var i in options) {
					var op = document.createElement("option");
					op.appendChild(document.createTextNode(i));
					op.value = options[i];
					el.appendChild(op);
				}
				HTMLArea._addEvent(el, "change", function () {
					editor._comboSelected(el, txt);
				});
			}
			return el;
		};
		// the element that will be created
		var el = null;
		var btn = null;
		switch (txt) {
		    case "separator":
			el = document.createElement("div");
			el.className = "separator";
			break;
		    case "space":
			el = document.createElement("div");
			el.className = "space";
			break;
		    case "linebreak":
			newLine();
			return false;
		    case "textindicator":
			el = document.createElement("div");
			el.appendChild(document.createTextNode("A"));
			el.className = "indicator";
			el.title = HTMLArea.I18N.tooltips.textindicator;
			var obj = {
				name: txt,     // the button name (i.e. 'bold')
				element: el,   // the UI element (DIV)
				enabled: true, // is it enabled?
				active: false, // is it pressed?
				text: false,   // enabled in text mode?
				cmd: "textindicator", // the command ID
				state: setButtonStatus // for changing state
			};
			tb_objects[txt] = obj;
			break;
		    default:
			btn = editor.config.btnList[txt];
			break;
		}
		if (!el && btn) {
			el = document.createElement("div");
			el.title = btn[1];
			el.className = "button";
			// let's just pretend we have a button object, and
			// assign all the needed information to it.
			var obj = {
				name: txt,     // the button name (i.e. 'bold')
				element: el,   // the UI element (DIV)
				enabled: true, // is it enabled?
				active: false, // is it pressed?
				text: btn[3],  // enabled in text mode?
				cmd: btn[0],   // the command ID
				state: setButtonStatus // for changing state
			};
			tb_objects[txt] = obj;
			// handlers to emulate nice flat toolbar buttons
			HTMLArea._addEvent(el, "mouseover", function () {
				if (obj.enabled) {
					HTMLArea._addClass(el, "buttonHover");
				}
			});
			HTMLArea._addEvent(el, "mouseout", function () {
				if (obj.enabled) with (HTMLArea) {
					_removeClass(el, "buttonHover");
					_removeClass(el, "buttonActive");
					(obj.active) && _addClass(el, "buttonPressed");
				}
			});
			HTMLArea._addEvent(el, "mousedown", function (ev) {
				if (obj.enabled) with (HTMLArea) {
					_addClass(el, "buttonActive");
					_removeClass(el, "buttonPressed");
					_stopEvent(is_ie ? window.event : ev);
				}
			});
			// when clicked, do the following:
			HTMLArea._addEvent(el, "click", function (ev) {
				if (obj.enabled) with (HTMLArea) {
					_removeClass(el, "buttonActive");
					_removeClass(el, "buttonHover");
					editor._buttonClicked(txt);
					_stopEvent(is_ie ? window.event : ev);
				}
			});
			var img = document.createElement("img");
			img.src = editor.imgURL(btn[2]);
			el.appendChild(img);
		} else if (!el) {
			el = createSelect();
		}
		if (el) {
			var tb_cell = document.createElement("td");
			tb_row.appendChild(tb_cell);
			tb_cell.appendChild(el);
		} else {
			alert("FIXME: Unknown toolbar item: " + txt);
		}
		return el;
	};

	for (var i in this.config.toolbar) {
		var group = this.config.toolbar[i];
		for (var j in group) {
			createButton(group[j]);
		}
	}

	this._htmlArea.appendChild(toolbar);
};

// Creates the HTMLArea object and replaces the textarea with it.
HTMLArea.prototype.generate = function () {
	var editor = this;	// we'll need "this" in some nested functions
	// get the textarea
	var textarea = this._textArea;
	if (typeof textarea == "string") {
		// it's not element but ID
		this._textArea = textarea = document.getElementById(textarea);
	}
	this._ta_size = {
		w: textarea.offsetWidth,
		h: textarea.offsetHeight
	};
	// hide the textarea
	textarea.style.display = "none";

	// create the editor framework
	var htmlarea = document.createElement("div");
	htmlarea.className = "htmlarea";
	this._htmlArea = htmlarea;

	// insert the editor before the textarea.
	textarea.parentNode.insertBefore(htmlarea, textarea);

	// retrieve the HTML on submit
	HTMLArea._addEvent(textarea.form, "submit", function (event) {
		editor._formSubmit(HTMLArea.is_ie ? window.event : event);
	});

	// creates & appends the toolbar
	this._createToolbar();

	// create the IFRAME
	var iframe = document.createElement("iframe");
	htmlarea.appendChild(iframe);
	this._iframe = iframe;

	// remove the default border as it keeps us from computing correctly
	// the sizes.  (somebody tell me why doesn't this work in IE)
	// iframe.style.border = "none";
	// iframe.frameborder = "0";

	// size the IFRAME according to user's prefs or initial textarea
	var height = (this.config.height == "auto" ? (this._ta_size.h + "px") : this.config.height);
	height = parseInt(height);
	var width = (this.config.width == "auto" ? (this._ta_size.w + "px") : this.config.width);
	width = parseInt(width);

	iframe.style.width = width + "px";
	if (this.config.sizeIncludesToolbar) {
		// substract toolbar height
		height -= this._toolbar.offsetHeight;
	}
	iframe.style.height = height + "px";

	// now create a secondary textarea so that we can switch between
	// WYSIWYG & text mode.
	textarea = document.createElement("textarea");

	// hidden by default
	textarea.style.display = "none";

	// make it the same size as the editor
	textarea.style.width = iframe.style.width;
	textarea.style.height = iframe.style.height;

	// insert it after the iframe
	htmlarea.appendChild(textarea);

	// remember it for later
	this._textArea2 = textarea;

	// IMPORTANT: we have to allow Mozilla a short time to recognize the
	// new frame.  Otherwise we get a stupid exception.
	function initIframe() {
		var doc = editor._iframe.contentWindow.document;
		if (!doc) {
			if (HTMLArea.is_gecko) {
				setTimeout(function () { editor._initIframe(); }, 10);
				return false;
			} else {
				alert("ERROR: IFRAME can't be initialized.");
			}
		}
		if (HTMLArea.is_gecko) {
			// enable editable mode for Mozilla
			doc.designMode = "on";
		}
		editor._doc = doc;
		doc.open();
		var html = "<html>\n";
		html += "<head>\n";
		html += "<style> body { " + editor.config.bodyStyle + " } </style>\n";
		html += "</head>\n";
		html += "<body>\n";
		html += editor._textArea.value;
		html += "</body>\n";
		html += "</html>";
		doc.write(html);
		doc.close();

		if (HTMLArea.is_ie) {
			// enable editable mode for IE.  For some reason this
			// doesn't work if done in the same place as for Gecko
			// (above).
			doc.body.contentEditable = true;
		}

		editor.focusEditor();
		// intercept some events; for updating the toolbar & keyboard handlers
		HTMLArea._addEvents
			(doc, ["keydown", "keypress", "mousedown", "mouseup", "drag"],
			 function (event) {
				 return editor._editorEvent(HTMLArea.is_ie ? editor._iframe.contentWindow.event : event);
			 });
		editor.updateToolbar();
		editor.focusEditor();
	};
	setTimeout(initIframe, HTMLArea.is_gecko ? 10 : 0);
};

// Switches editor mode; parameter can be "textmode" or "wysiwyg"
HTMLArea.prototype.setMode = function(mode) {
	switch (mode) {
	    case "textmode":
		this._textArea2.value = this.getHTML();
		this._iframe.style.display = "none";
		this._textArea2.style.display = "block";
		break;
	    case "wysiwyg":
		this._doc.body.innerHTML = this.getHTML();
		this._iframe.style.display = "block";
		this._textArea2.style.display = "none";
		if (HTMLArea.is_gecko) {
			// we need to refresh that info for Moz-1.3a
			this._doc.designMode = "on";
		}
		break;
	    default:
		alert("Mode <" + mode + "> not defined!");
		return false;
	}
	this._mode = mode;
	this.focusEditor();
};

/***************************************************
 *  Category: EDITOR UTILITIES
 ***************************************************/

// focuses the iframe window.  returns a reference to the editor document.
HTMLArea.prototype.focusEditor = function() {
	switch (this._mode) {
	    case "wysiwyg":
		this._iframe.contentWindow.focus();
		break;
	    case "textmode":
		this._textArea2.focus();
		break;
	    default:
		alert("ERROR: mode " + this._mode + " is not defined");
		break;
	}
	return this._doc;
};

// updates enabled/disable/active state of the toolbar elements
HTMLArea.prototype.updateToolbar = function() {
	var doc = this._doc;
	var text = (this._mode == "textmode");
	for (var i in this._toolbarObjects) {
		var btn = this._toolbarObjects[i];
		var cmd = btn.cmd;
		if (typeof cmd == "function") {
			continue;
		}
		cmd = cmd.toLowerCase();
		btn.state("enabled", !text || btn.text);
		switch (cmd) {
		    case "fontname":
		    case "fontsize":
		    case "formatblock":
			if (!text) {
				var value = ("" + doc.queryCommandValue(cmd)).toLowerCase();
				if (!value) {
					// FIXME: what do we do here?
					break;
				}
				var options = this.config[i]; // HACK!!
				var k = 0;
				// btn.element.selectedIndex = 0;
				for (var j in options) {
					// FIXME: the following line is scary.
					if ((j.toLowerCase() == value) ||
					    (options[j].substr(0, value.length).toLowerCase() == value)) {
						btn.element.selectedIndex = k;
						break;
					}
					++k;
				}
			}
			break;
		    case "textindicator":
			if (!text) {
				try {with (btn.element.style) {
					backgroundColor = HTMLArea._makeColor(doc.queryCommandValue("backcolor"));
					color = HTMLArea._makeColor(doc.queryCommandValue("forecolor"));
					fontFamily = doc.queryCommandValue("fontname");
					fontWeight = doc.queryCommandState("bold") ? "bold" : "normal";
					fontStyle = doc.queryCommandState("italic") ? "italic" : "normal";
				}} catch (e) {
					alert(e + "\n\n" + cmd);
				}
			}
			break;
		    case "htmlmode":
			btn.state("active", text);
			break;
		    default:
			try {
				btn.state("active", (!text && doc.queryCommandState(cmd)));
			} catch (e) {}
			break;
		}
	}
};

/** Returns a node after which we can insert other nodes, in the current
 * selection.  The selection is removed.  It splits a text node, if needed.
 */
HTMLArea.prototype.insertNodeAtSelection = function(toBeInserted) {
	if (!HTMLArea.is_ie) {
		var sel = this._getSelection();
		var range = this._createRange(sel);
		// remove the current selection
		sel.removeAllRanges();
		range.deleteContents();
		var node = range.startContainer;
		var pos = range.startOffset;
		range = this._createRange();
		switch (node.nodeType) {
		    case 3: // Node.TEXT_NODE
			// we have to split it at the caret position.
			if (toBeInserted.nodeType == 3) {
				// do optimized insertion
				node.insertData(pos, toBeInserted.data);
				range.setEnd(node, pos + toBeInserted.length);
				range.setStart(node, pos + toBeInserted.length);
			} else {
				node = node.splitText(pos);
				node.parentNode.insertBefore(toBeInserted, node);
				range.setStart(node, 0);
				range.setEnd(node, 0);
			}
			break;
		    case 1: // Node.ELEMENT_NODE
			node = node.childNodes[pos];
			node.parentNode.insertBefore(toBeInserted, node);
			range.setStart(node, 0);
			range.setEnd(node, 0);
			break;
		}
		sel.addRange(range);
	} else {
		return null;	// this function not yet used for IE <FIXME>
	}
};

/** Call this function to insert HTML code at the current position.  It deletes
 * the selection, if any.
 */
HTMLArea.prototype.insertHTML = function(html) {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	if (HTMLArea.is_ie) {
		range.pasteHTML(html);
	} else {
		// construct a new document fragment with the given HTML
		var fragment = this._doc.createDocumentFragment();
		var div = this._doc.createElement("div");
		div.innerHTML = html;
		while (div.firstChild) {
			// the following call also removes the node from div
			fragment.appendChild(div.firstChild);
		}
		// this also removes the selection
		var node = this.insertNodeAtSelection(fragment);
	}
};

/**
 *  Call this function to surround the existing HTML code in the selection with
 *  your tags.
 */
HTMLArea.prototype.surroundHTML = function(startTag, endTag) {
	var html = this.getSelectedHTML();
	// the following also deletes the selection
	this.insertHTML(startTag + html + endTag);
};

/// Retrieve the selected block
HTMLArea.prototype.getSelectedHTML = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	var existing = null;
	if (HTMLArea.is_ie) {
		existing = range.htmlText;
	} else {
		existing = HTMLArea.getHTML(range.cloneContents(), false);
	}
	return existing;
};

// Called when the user clicks on "InsertImage" button
HTMLArea.prototype._insertImage = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	var editor = this;	// for nested functions
	this._popupDialog("insert_image.php?Iurl=" + this.Iurl, function(param) {
		if (!param) {	// user must have pressed Cancel
			return false;
		}
		editor._execCommand("insertimage", false, param["f_url"]);
		var img = null;
		if (HTMLArea.is_ie) {
			img = range.parentElement();
			// wonder if this works...
			if (img.tagName.toLowerCase() != "img") {
				img = img.previousSibling;
			}
		} else {
			img = range.startContainer.previousSibling;
		}
		for (field in param) {
			var value = param[field];
			if (!value) {
				continue;
			}
			switch (field) {
			    case "f_alt":
				img.alt = value;
				break;
			    case "f_border":
				img.border = parseInt(value);
				break;
			    case "f_align":
				img.align = value;
				break;
			    case "f_vert":
				img.vspace = parseInt(value);
				break;
			    case "f_horiz":
				img.hspace = parseInt(value);
				break;
			}
		}
	}, null);
};

// Called when the user clicks on "InsertFile" button
HTMLArea.prototype._insertFile = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	var len = 1;
	if (sel.type=="Text" || sel.type=="text") len = range.text.length;
	var editor = this;	// for nested functions
	this._popupDialog("insert_file.php?Iurl=" + this.Iurl + "&Durl=" + this.Durl, function(param) {
		if (!param) {	// user must have pressed Cancel
			return false;
		}
		var doc = editor._doc;
		//var sp = doc.createElement("span");
		var url = param["f_url"];
		if (len==0) {
			range.pasteHTML("<a href='"+url+"'>"+url+"</a>");
		} else {
			doc.execCommand("createlink", false, url);
		}
		//sp.innerHTML = "Hi~";
	}, null);
};

// Called when the user clicks the Insert Table button
HTMLArea.prototype._insertTable = function() {
	var sel = this._getSelection();
	var range = this._createRange(sel);
	var editor = this;	// for nested functions
	this._popupDialog("insert_table.html", function(param) {
		if (!param) {	// user must have pressed Cancel
			return false;
		}
		var doc = editor._doc;
		// create the table element
		var table = doc.createElement("table");
		// assign the given arguments
		for (var field in param) {
			var value = param[field];
			if (!value) {
				continue;
			}
			switch (field) {
			    case "f_width":
				table.style.width = value + param["f_unit"];
				break;
			    case "f_align":
				table.align = value;
				break;
			    case "f_border":
				table.border = parseInt(value);
				break;
			    case "f_spacing":
				table.cellspacing = parseInt(value);
				break;
			    case "f_padding":
				table.cellpadding = parseInt(value);
				break;
			}
		}
		var tbody = doc.createElement("tbody");
		table.appendChild(tbody);
		for (var i = 0; i < param["f_rows"]; ++i) {
			var tr = doc.createElement("tr");
			tbody.appendChild(tr);
			for (var j = 0; j < param["f_cols"]; ++j) {
				var td = doc.createElement("td");
				tr.appendChild(td);
				if (HTMLArea.is_gecko) {
					// Mozilla likes to see something
					// inside the cell.
					td.appendChild(doc.createElement("br"));
				}
			}
		}
		if (HTMLArea.is_ie) {
			range.pasteHTML(HTMLArea.getHTML(table, true));
		} else {
			// insert the table
			editor.insertNodeAtSelection(table);
		}
		return true;
	}, null);
};

/***************************************************
 *  Category: EVENT HANDLERS
 ***************************************************/

// txt is the name of the button, as in config.toolbar
HTMLArea.prototype._buttonClicked = function(txt) {
	var editor = this;	// needed in nested functions
	this.focusEditor();
	var btn = this.config.btnList[txt];
	if (!btn) {
		alert("FIXME: Unconfigured button!");
		return false;
	}
	var cmd = btn[0];
	if (typeof cmd == "function") {
		return cmd(this, txt);
	}
	switch (cmd.toLowerCase()) {
	    case "htmlmode":
		this.setMode(this._mode != "textmode" ? "textmode" : "wysiwyg");
		break;
	    case "forecolor":
	    case "backcolor":
		this._popupDialog("select_color.html", function(color) {
			editor._execCommand(cmd, false, "#" + color);
		}, HTMLArea._colorToRgb(this._doc.queryCommandValue(btn[0])));
		break;
	    case "createlink":
		//this._execCommand(cmd, true);
		this._insertFile();
		break;
	    case "insertimage":
		this._insertImage();
		break;
	    case "inserttable":
		this._insertTable();
		break;
		case "word":
			HTMLArea._object = this;
			var furl = "index.php/engineCommon/popup/EditorImport";
			if (HTMLArea.is_ie) {
				window.open(g_root+furl, "punishment",
				    	"toolbar=no,location=no,directories=no,status=yes,menubar=no," +
				    	"scrollbars=no,resizable=yes,width=400,height=300,left=0,top=0");
			} else {
				window.open(g_root+furl, "punishment",
				    	"toolbar=no,menubar=no,personalbar=no,width=400,height=300,left=0,top=0" +
				    	"scrollbars=no,resizable=yes");
			}

		break;
	    case "popupeditor":
		var furl = "index.php/engineCommon/popup/EditorPopup";
		/*if (HTMLArea.is_ie) {
			window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",
				    "toolbar=no,location=no,directories=no,status=yes,menubar=no," +
				    "scrollbars=no,resizable=yes,width=640,height=480");
		} else {
			window.open(this.popupURL("fullscreen.html"), "ha_fullscreen",
				    "toolbar=no,menubar=no,personalbar=no,width=640,height=480," +
				    "scrollbars=no,resizable=yes");
		}*/

		if (HTMLArea.is_ie) {
			window.open(g_root+furl, "ha_fullscreen",
				    "toolbar=no,location=no,directories=no,status=yes,menubar=no," +
				    "scrollbars=no,resizable=yes,width=800,height=600,left=0,top=0");
		} else {
			window.open(g_root+furl, "ha_fullscreen",
				    "toolbar=no,menubar=no,personalbar=no,width=800,height=600,left=0,top=0" +
				    "scrollbars=no,resizable=yes");
		}


		// pass this object to the newly opened window
		HTMLArea._object = this;
		break;
	    case "about":
		this._popupDialog("about.html", null, null);
		break;
	    case "help":
		alert("Help not implemented");
		break;
	    default:
		this._execCommand(btn[0], false, "");
		break;
	}
	this.updateToolbar();
	return false;
};

// el is reference to the SELECT object
// txt is the name of the select field, as in config.toolbar
HTMLArea.prototype._comboSelected = function(el, txt) {
	this.focusEditor();
	var value = el.options[el.selectedIndex].value;
	switch (txt) {
	    case "fontname":
	    case "fontsize":
		this._execCommand(txt, false, value);
		break;
	    case "formatblock":
		if (HTMLArea.is_ie) { // sad but true
			value = "<" + value + ">";
		}
		this._execCommand(txt, false, value);
		break;
	    default:
		alert("FIXME: combo box " + txt + " not implemented");
		break;
	}
};

// the execCommand function (intercepts some commands and replaces them with
// our own implementation)
HTMLArea.prototype._execCommand = function(cmdID, UI, param) {
	switch (cmdID.toLowerCase()) {
	    case "createlink":
		if (HTMLArea.is_ie || !UI) {
			this._doc.execCommand(cmdID, UI, param);
		} else {
			// browser is Mozilla & wants UI
			if ((param = prompt("Enter URL"))) {
				this._doc.execCommand(cmdID, false, param);
			}
		}
		break;
	    case "backcolor":
		if (HTMLArea.is_ie) {
			this._doc.execCommand(cmdID, UI, param);
		} else {
			this._doc.execCommand("hilitecolor", UI, param);
		}
		break;
	    default:
		this._doc.execCommand(cmdID, UI, param);
		break;
	}
	this.focusEditor();
};

/** A generic event handler for things that happen in the IFRAME's document.
 * This function also handles key bindings. */
HTMLArea.prototype._editorEvent = function(ev) {
	var editor = this;
	var keyEvent = (HTMLArea.is_ie && ev.type == "keydown") || (ev.type == "keypress");
	if (keyEvent && ev.ctrlKey) {
		var sel = null;
		var range = null;
		var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase();
		var cmd = null;
		var value = null;
		switch (key) {
		    case 'a':
			if (!HTMLArea.is_ie) {
				// KEY select all
				sel = this._getSelection();
				sel.removeAllRanges();
				range = this._createRange();
				range.selectNodeContents(this._doc.body);
				sel.addRange(range);
				HTMLArea._stopEvent(ev);
			}
			break;

			// simple key commands follow

		    case 'b':	// KEY bold
			(!HTMLArea.is_ie) && (cmd = "bold");
			break;
		    case 'i':	// KEY italic
			(!HTMLArea.is_ie) && (cmd = "italic");
			break;
		    case 'u':	// KEY underline
			(!HTMLArea.is_ie) && (cmd = "underline");
			break;
		    case 's':	// KEY justify full
			cmd = "strikethrough";
			break;
		    case 'l':	// KEY justify left
			cmd = "justifyleft";
			break;
		    case 'e':	// KEY justify center
			cmd = "justifycenter";
			break;
		    case 'r':	// KEY justify right
			cmd = "justifyright";
			break;
		    case 'j':	// KEY justify full
			cmd = "justifyfull";
			break;

			// headings
		    case '1':	// KEY heading 1
		    case '2':	// KEY heading 2
		    case '3':	// KEY heading 3
		    case '4':	// KEY heading 4
		    case '5':	// KEY heading 5
		    case '6':	// KEY heading 6
			cmd = "formatblock";
			value = "h" + key;
			if (HTMLArea.is_ie) {
				value = "<" + value + ">";
			}
			break;
		}
		if (cmd) {
			// execute simple command
			this._execCommand(cmd, false, value);
			HTMLArea._stopEvent(ev);
		}
	}
	/*
	else if (keyEvent) {
		// other keys here
		switch (ev.keyCode) {
		    case 13: // KEY enter
			// if (HTMLArea.is_ie) {
			this.insertHTML("<br />");
			HTMLArea._stopEvent(ev);
			// }
			break;
		}
	}
	*/
	// update the toolbar state after some time
	setTimeout(function() {
		editor.updateToolbar();
	}, 50);
};

// gets called before the form is submitted
HTMLArea.prototype._formSubmit = function(ev) {
	// retrieve the HTML
	this._textArea.value = this.getHTML();
};

// retrieve the HTML
HTMLArea.prototype.getHTML = function() {
	switch (this._mode) {
	    case "wysiwyg":
		return HTMLArea.getHTML(this._doc.body, false);
	    case "textmode":
		return this._textArea2.value;
	    default:
		alert("Mode <" + mode + "> not defined!");
		return false;
	}
};

// retrieve the HTML (fastest version, but uses innerHTML)
HTMLArea.prototype.getInnerHTML = function() {
	switch (this._mode) {
	    case "wysiwyg":
		return this._doc.body.innerHTML;
	    case "textmode":
		return this._textArea2.value;
	    default:
		alert("Mode <" + mode + "> not defined!");
		return false;
	}
};

// completely change the HTML inside
HTMLArea.prototype.setHTML = function(html) {
	switch (this._mode) {
	    case "wysiwyg":
		this._doc.body.innerHTML = html;
		break;
	    case "textmode":
		this._textArea2.value = html;
		break;
	    default:
		alert("Mode <" + mode + "> not defined!");
	}
	return false;
};

/***************************************************
 *  Category: UTILITY FUNCTIONS
 ***************************************************/

// browser identification

HTMLArea.agt = navigator.userAgent.toLowerCase();
HTMLArea.is_ie     = ((HTMLArea.agt.indexOf("msie") != -1) && (HTMLArea.agt.indexOf("opera") == -1));
HTMLArea.is_opera  = (HTMLArea.agt.indexOf("opera") != -1);
HTMLArea.is_mac    = (HTMLArea.agt.indexOf("mac") != -1);
HTMLArea.is_mac_ie = (HTMLArea.is_ie && HTMLArea.is_mac);
HTMLArea.is_win_ie = (HTMLArea.is_ie && !HTMLArea.is_mac);
HTMLArea.is_gecko  = (navigator.product == "Gecko");

// variable used to pass the object to the popup editor window.
HTMLArea._object = null;

// FIXME!!! this should return false for IE < 5.5
HTMLArea.checkSupportedBrowser = function() {
	/*
	var gigi = "Navigator:\n\n";
	for (var i in navigator) {
		gigi += i + " = " + navigator[i] + "\n";
	}
	alert(gigi);
	*/
	if (HTMLArea.is_gecko) {
		if (navigator.productSub < 20021201) {
			alert("You need at least Mozilla-1.3 Alpha.\n" +
			      "Sorry, your Gecko is not supported.");
			return false;
		}
		if (navigator.productSub < 20030210) {
			alert("Mozilla < 1.3 Beta is not supported!\n" +
			      "I'll try, though, but it might not work.");
		}
	}
	return HTMLArea.is_gecko || HTMLArea.is_ie;
};

// selection & ranges

// returns the current selection object
HTMLArea.prototype._getSelection = function() {
	if (HTMLArea.is_ie) {
		return this._doc.selection;
	} else {
		return this._iframe.contentWindow.getSelection();
	}
};

// returns a range for the current selection
HTMLArea.prototype._createRange = function(sel) {
	if (HTMLArea.is_ie) {
		return sel.createRange();
	} else {
		this.focusEditor();
		if (sel) {
			return sel.getRangeAt(0);
		} else {
			return this._doc.createRange();
		}
	}
};

// event handling

HTMLArea._addEvent = function(el, evname, func) {
	if (HTMLArea.is_ie) {
		el.attachEvent("on" + evname, func);
	} else {
		el.addEventListener(evname, func, true);
	}
};

HTMLArea._addEvents = function(el, evs, func) {
	for (var i in evs) {
		HTMLArea._addEvent(el, evs[i], func);
	}
};

HTMLArea._removeEvent = function(el, evname, func) {
	if (HTMLArea.is_ie) {
		el.detachEvent("on" + evname, func);
	} else {
		el.removeEventListener(evname, func, true);
	}
};

HTMLArea._removeEvents = function(el, evs, func) {
	for (var i in evs) {
		HTMLArea._removeEvent(el, evs[i], func);
	}
};

HTMLArea._stopEvent = function(ev) {
	if (HTMLArea.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
};

HTMLArea._removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

HTMLArea._addClass = function(el, className) {
	// remove the class first, if already there
	HTMLArea._removeClass(el, className);
	el.className += " " + className;
};

HTMLArea._hasClass = function(el, className) {
	if (!(el && el.className)) {
		return false;
	}
	var cls = el.className.split(" ");
	for (var i = cls.length; i > 0;) {
		if (cls[--i] == className) {
			return true;
		}
	}
	return false;
};

HTMLArea._isBlockElement = function(el) {
	var blockTags = " body form textarea fieldset ul ol dl li div " +
		"p h1 h2 h3 h4 h5 h6 quote pre table thead " +
		"tbody tfoot tr td iframe ";
	return (blockTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
};

HTMLArea._needsClosingTag = function(el) {
	var closingTags = " script style div span ";
	return (closingTags.indexOf(" " + el.tagName.toLowerCase() + " ") != -1);
};

// Retrieves the HTML code from the given node.  This is a replacement for
// getting innerHTML, using standard DOM calls.
HTMLArea.getHTML = function(root, outputRoot) {
	function encode(str) {
		// we don't need regexp for that, but.. so be it for now.
		str = str.replace(/&/ig, "&amp;");
		str = str.replace(/</ig, "&lt;");
		str = str.replace(/>/ig, "&gt;");
		str = str.replace(/\"/ig, "&quot;");
		return str;
	};
	var html = "";
	switch (root.nodeType) {
	    case 1: // Node.ELEMENT_NODE
	    case 11: // Node.DOCUMENT_FRAGMENT_NODE
		var closed;
		var i;
		if (outputRoot) {
			closed = (!(root.hasChildNodes() || HTMLArea._needsClosingTag(root)));
			html = "<" + root.tagName.toLowerCase();
			var attrs = root.attributes;
			for (i = 0; i < attrs.length; ++i) {
				var a = attrs.item(i);
				if (!a.specified) {
					continue;
				}
				var name = a.name.toLowerCase();
				if (name.substr(0, 4) == "_moz") {
					// Mozilla reports some special tags
					// here; we don't need them.
					continue;
				}
				var value;
				if (name != 'style') {
					value = a.value;
				} else { // IE fails to put style in attributes list
					value = root.style.cssText.toLowerCase();
				}
				if (value.substr(0, 4) == "_moz") {
					// Mozilla reports some special tags
					// here; we don't need them.
					continue;
				}
				html += " " + name + '="' + value + '"';
			}
			html += closed ? " />" : ">";
		}
		for (i = root.firstChild; i; i = i.nextSibling) {
			html += HTMLArea.getHTML(i, true);
		}
		if (outputRoot && !closed) {
			html += "</" + root.tagName.toLowerCase() + ">";
		}
		break;
	    case 3: // Node.TEXT_NODE
		html = encode(root.data);
		break;
	    case 8: // Node.COMMENT_NODE
		html = "<!--" + root.data + "-->";
		break;		// skip comments, for now.
	}
	return html;
};

// creates a rgb-style color from a number
HTMLArea._makeColor = function(v) {
	if (typeof v != "number") {
		// already in rgb (hopefully); IE doesn't get here.
		return v;
	}
	// IE sends number; convert to rgb.
	var r = v & 0xFF;
	var g = (v >> 8) & 0xFF;
	var b = (v >> 16) & 0xFF;
	return "rgb(" + r + "," + g + "," + b + ")";
};

// returns hexadecimal color representation from a number or a rgb-style color.
HTMLArea._colorToRgb = function(v) {
	// returns the hex representation of one byte (2 digits)
	function hex(d) {
		return (d < 16) ? ("0" + d.toString(16)) : d.toString(16);
	};

	if (typeof v == "number") {
		// we're talking to IE here
		var r = v & 0xFF;
		var g = (v >> 8) & 0xFF;
		var b = (v >> 16) & 0xFF;
		return "#" + hex(r) + hex(g) + hex(b);
	}

	if (v.substr(0, 3) == "rgb") {
		// in rgb(...) form -- Mozilla
		var re = /rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/;
		if (v.match(re)) {
			var r = parseInt(RegExp.$1);
			var g = parseInt(RegExp.$2);
			var b = parseInt(RegExp.$3);
			return "#" + hex(r) + hex(g) + hex(b);
		}
		// doesn't match RE?!  maybe uses percentages or float numbers
		// -- FIXME: not yet implemented.
		return null;
	}

	if (v[0] == "#") {
		// already hex rgb (hopefully :D )
		return v;
	}

	// if everything else fails ;)
	return null;
};

// modal dialogs for Mozilla (for IE we're using the showModalDialog() call).

// receives an URL to the popup dialog and a function that receives one value;
// this function will get called after the dialog is closed, with the return
// value of the dialog.
HTMLArea.prototype._popupDialog = function(url, action, init) {
	Dialog(this.popupURL(url), action, init);
};

// paths

HTMLArea.prototype.imgURL = function(file) {
	return this.config.editorURL + this.config.imgURL + file;
};

HTMLArea.prototype.popupURL = function(file) {
	return this.config.editorURL + this.config.popupURL + file;
};

// EOF
// Local variables: //
// c-basic-offset:8 //
// indent-tabs-mode:t //
// End: //

/************************* ******************************* ******************************/

// Though "Dialog" looks like an object, it isn't really an object.  Instead
// it's just namespace for protecting global symbols.

function Dialog(url, action, init) {
	if (typeof init == "undefined") {
		init = window;	// pass this window object by default
	}
	if (document.all) {	// here we hope that Mozilla will never support document.all
		var value =
			showModalDialog(url, init,
//			window.open(url, '_blank',
					"resizable: no; help: no; status: no; scroll: no");
		if (action) {
			action(value);
		}
	} else {
		return Dialog._geckoOpenModal(url, action, init);
	}
};

Dialog._parentEvent = function(ev) {
	if (Dialog._modal && !Dialog._modal.closed) {
		Dialog._modal.focus();
		// we get here in Mozilla only, anyway, so we can safely use
		// the DOM version.
		ev.preventDefault();
		ev.stopPropagation();
	}
};

// should be a function, the return handler of the currently opened dialog.
Dialog._return = null;

// constant, the currently opened dialog
Dialog._modal = null;

// the dialog will read it's args from this variable
Dialog._arguments = null;

Dialog._geckoOpenModal = function(url, action, init) {
	var dlg = window.open(url, "ha_dialog",
			      "toolbar=no,menubar=no,personalbar=no,width=400,height=240," +
			      "scrollbars=no,resizable=no");
	Dialog._modal = dlg;
	Dialog._arguments = init;

	// capture some window's events
	function capwin(w) {
		w.addEventListener("click", Dialog._parentEvent, true);
		w.addEventListener("mousedown", Dialog._parentEvent, true);
		w.addEventListener("focus", Dialog._parentEvent, true);
	};
	// release the captured events
	function relwin(w) {
		w.removeEventListener("focus", Dialog._parentEvent, true);
		w.removeEventListener("mousedown", Dialog._parentEvent, true);
		w.removeEventListener("click", Dialog._parentEvent, true);
	};
	capwin(window);
	// capture other frames
	for (var i = 0; i < window.frames.length; capwin(window.frames[i++]));
	// make up a function to be called when the Dialog ends.
	Dialog._return = function (val) {
		if (val && action) {
			action(val);
		}
		relwin(window);
		// capture other frames
		for (var i = 0; i < window.frames.length; relwin(window.frames[i++]));
		Dialog._modal = null;
	};
};

/* k-zed's own tooltip thingy ;) */

function findPosition(i) {
	if(i.offsetParent) {
		for(var posX=0, posY=0; i.offsetParent; i = i.offsetParent) {
			posX += i.offsetLeft;
			posY += i.offsetTop;
		}
		return [posX, posY];
	} else return [i.offsetLeft, i.offsetTop];
}


function popDisplay(id) {
	lE = document.getElementById(id + "Link");
	pE = document.getElementById(id);

	pE.style.left = 0;
	pE.style.display = '';

	po = findPosition(lE);

	if (po[1] + lE.offsetHeight - document.body.scrollTop + pE.offsetHeight >= document.body.clientHeight)
		y = po[1] - pE.offsetHeight;
	else
		y = po[1] + lE.offsetHeight;

	x = po[0] + (lE.offsetWidth - pE.offsetWidth) / 2;
	if (x < 4) x = 4; else if (x + pE.offsetWidth >= document.body.clientWidth) x = document.body.clientWidth - pE.offsetWidth - 20;

	pE.style.top = y;
	pE.style.left = x;
}

function popHide(id) {
	pE = document.getElementById(id);

	pE.style.display = 'none';
}

