//////////////////////////////////////////////////////////////
//															//
//	© 2005 - 2007 Vereyon									//
//  http://www.vereyon.nl									//
//	All rights reserved										//
//															//
//////////////////////////////////////////////////////////////

/**
 * Returns the type of the object oObject
 * @param {Object} oObject The object to get type type of
 */
function etypeof(oObject) {
	

	// Declare variables
	var strType = typeof(oObject);
	switch(strType) {
		default:
			return strType;
			break;
		case "Object":
		case "object":
			if(oObject.__type != undefined) {
				return oObject.__type;
			} else {
				return strType;
			}
			break;
	}
}

/**
 * Return the document element with the id strId
 * @param {string} param A string containing the id of the document element to retrieve, or the object to extend
 */
function $(param) {
	
	if(typeof(param) == "string") {
		param = document.getElementById(param);
	}
	
	Object.extend(param, {
		
		getAbsolutePosition: function() {
			
			// Declare variables
			var hDocumentElement = document.documentElement;
			var hLayoutParent = this;
			var position = { x: 0, y: 0 };
			
			while(hLayoutParent.tagName != "BODY") {
				position.x += hLayoutParent.offsetLeft - hLayoutParent.scrollLeft;
				position.y += hLayoutParent.offsetTop - hLayoutParent.scrollTop;
				hLayoutParent = hLayoutParent.offsetParent;
			}
			
			return position;
		},
		
		setSelectToValue: function(value) {
			
			// Declare variables
			var hOption;
			
			for(var i = 0; i < this.options.length; i++) {
				hOption = this.options[i];
				if(hOption.value == value) {
					this.selectedIndex = i;
					break;
				}
			}
		}
		
		});
	
	return param;
}

/**
 * Inhert to passed object
 * @param {Object} subtype The type to inhert supertype
 * @param {Object} supertype The type to inherit from
 */
Object.inherits = function Object$inherits(subtype, supertype) {
	subtype.prototype = new supertype;
};

/**
 * Extend this object with the passed extensions
 * @param {Object} extensions An array containing the extensions. The key as the porperty name, the value als the actual property.
 */
Object.extend = function Object$extend(subject, extensions) {
	for(var property in extensions) {
		subject[property] = extensions[property];
	}
	return subject;
};

/**
 * Binds the function with a fixed context
 * @param {Object} context the object to function as the [this] variable in the scope of the function
 */
Function.prototype.Bind = function Function$Bind(context) {
	var _function = this;
	var args = Array.createFrom(arguments);
	var context = args.shift();
	return function() {
		_function.apply(context, args.concat(Array.createFrom(arguments)));
	}
}

/**
 * Binds the function as a event listener to the object [object] for the event [event] with a fixed context
 * @param {Object} context The object to function as the [this] variable in the scope of the function.
 */
Function.prototype.BindEvent = function Function$BindEvent(context) {
	var _function = this;
	var args = Array.createFrom(arguments);
	var context = args.shift();
	return function(event) {
		_function.apply(context, [event || window.event].concat(args));
	}
}

Array.createFrom = function Array$createFrom(collection) {
	if (collection.toArray) {
		return collection.toArray();
	} else {
		var result = [];
		for (var i = 0; i < collection.length; i++)
			result[i] = collection[i];
		return result;
	}
}

Array.IndexOf = function Array$IndexOf(array, value) {
	for(var i = 0; i < this.length; i++) {
		if(this[i] == value) {
			return i;
		}
	}
	
	return -1;
}

Date.prototype.formatDate = function Date$formatDate() {
	
	aMonths = new Array(TEXT['January'], TEXT['February'], TEXT['March'], TEXT['April'], TEXT['May'], TEXT['June'], TEXT['July'], TEXT['August'], TEXT['September'], TEXT['October'], TEXT['November'], TEXT['December']);
	aDays = new Array(TEXT['Sunday'], TEXT['Monday'], TEXT['Tuesday'], TEXT['Wensday'], TEXT['Thursday'], TEXT['Friday'], TEXT['Saturday']);
	
	return aDays[this.getDay()] + " " + this.getDate() + " " + aMonths[this.getMonth()];
}

/**
 * Intializes a new instance of the Delegate object.
 */
function Delegate() {
	this.arrFunctions = [];
	this.arrContexts = [];
	this.arrArguments = [];
};

Delegate.prototype.__type = "Delegate";
/**
 * Invokes all the suscribed functions in the context and passes the passed arguments.
 * @param {Object} args Any number of arguments to be passed to the suscribed functions
 */
Delegate.prototype.Invoke = function Delegate$Invoke() {
	
	// Declare variables
	var hContext, hFunction, aArguments;
	
	// Iterate trough suscribed functions
	for(var i = 0; i < this.arrFunctions.length; i++) {
		hFunction = this.arrFunctions[i];
		hContext = this.arrContexts[i];
		aArguments = this.arrArguments[i];
		aArguments = aArguments.concat(Array.createFrom(arguments));
		
		// Call function if valid
		if(hFunction && hContext) {
			hFunction.apply(hContext, aArguments);
		}
	}
}

/**
 * Suscribes the passed function and context to this delegate
 * @param {Function} hFunction The function to suscribe to this delegate
 * @param {Object} hContext The context of the function to suscribe
 */
Delegate.prototype.Suscribe = function Delegate$Suscribe(hFunction, hContext) {

	// Validate types
	if(etypeof(hFunction) != "function" || !Object.prototype.isPrototypeOf(hContext)) {
		throw new ArgumentException("The hFunction argument must be of the type 'function' and the hContext argument must be of the type 'object'.");
	}
	
	aArguments = Array.createFrom(arguments);

	// Store the function and object pointer
	this.arrFunctions.push(aArguments.shift());
	this.arrContexts.push(aArguments.shift());
	this.arrArguments.push(aArguments);
}

/**
 * Unsuscribes the passed function and context from this delegate
 * @param {Function} hFunction The function to unsuscribe from this delegate
 * @param {Object} hContext The context of the function to unsuscribe
 */
Delegate.prototype.Unsuscribe = function Delegate$Unsuscribe(hFunction, hContext) {

	// Validate types
	if(etypeof(hFunction) != "function" || !Object.prototype.isPrototypeOf(hContext)) {
		throw new ArgumentException("The hFunction argument must be of the type 'function' and the hContext argument must be of the type 'object'.");
	}
	
	// Attempt to find the stored function and context
	for(i = 0; i < this.arrFunctions.length; i++) {
		if(this.arrFunctions[i] == hFunction && this.arrContexts[i] == hContext) {
		
			// Delete the values from arrays
			this.arrFunctions.splice(i, 1);
			this.arrContexts.splice(i, 1);
			this.arrArguments.splice(i, 1);
			break;
		}
	}
}

Error.prototype.__type = "Error";
Error.prototype._stackTrace = "";
Error.prototype.HandleByUser = function Error$HandleByUser() {
	
	core.ShowErrorDialog(this);
}

Error.stackTrace = function Error$stackTrace(startingPoint)
	{
		var stackTraceMessage = "Stack trace: \n";
		var nextCaller = startingPoint;
		while(nextCaller)
		{
			stackTraceMessage += Error.getSignature(nextCaller) + "\n";
			nextCaller = nextCaller.caller;
		}
		stackTraceMessage += "\n\n";
		
		return stackTraceMessage;
	}
	
Error.getSignature = function Error$getSignature(theFunction)
	{
		var signature = Error.getFunctionName(theFunction);
		signature += "(";
		for(var x=0; x<theFunction.arguments.length; x++)
		{
			// trim long arguments
			var nextArgument = theFunction.arguments[x];
			if(nextArgument.length > 30)
				nextArgument = nextArgument.substring(0, 30) + "...";
			
			// apend the next argument to the signature
			signature += "'" + nextArgument + "'"; 
			
			// comma seperator
			if(x < theFunction.arguments.length - 1)
				signature += ", ";
		}
		signature += ")";
		return signature;
	}
	
Error.getFunctionName = function Error$getFunctionName(theFunction)
	{
		// mozilla makes it easy. I love mozilla.
		if(theFunction.name)
		{
			return theFunction.name;
		}
		
		// try to parse the function name from the defintion
		var definition = theFunction.toString();
		var name = definition.substring(definition.indexOf('function') + 8,definition.indexOf('('));
		if(name)
			return name;

		// sometimes there won't be a function name 
		// like for dynamic functions
		return "anonymous";
	}

ArgumentError = function(message, file, line) {
	
}

String.prototype.trim = function() { 
	return this.replace(/^\s+|\s+$/g, ""); 
};

function getXmlHttpRequest() {

	// Declare variables
	var oXmlHttpRequest;
	
	if (window.XMLHttpRequest) {
	
		// Mozilla firefox & IE 7
		try {
	    	oXmlHttpRequest = new XMLHttpRequest();
	    } catch(ex) {
	    	oXmlHttpRequest = false;
	    }
	} else if (window.ActiveXObject) {
		
		// Microsoft IE <= 6
		try {
			oXmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(ex) {
			try {
				oXmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(ex) {
				oXmlHttpRequest = false;
			}
		}
	    
	}
	return oXmlHttpRequest;
}

var Xml = {};
Xml.Serialize = function Xml$Serialize(oXmlDocument) {
	
	// Declare variables
	var strXml;
	var oXmlSerializer;
	
	if (window.ActiveXObject) {
		
		// Microsoft IE
		strXml = oXmlDocument.xml;
	} else if(window.XMLSerializer) {
	
		// Mozilla firefox
		oXmlSerializer = new XMLSerializer();
		strXml = oXmlSerializer.serializeToString(oXmlDocument);
	}
	
	return strXml;
};
	
Xml.LoadXmlString = function Xml$LoadXmlString(strXml) {
		
	// Declare variables
	var oXmlDoc;
	
	oXmlDoc = new Xml.Document();
	
	
	return oXmlDoc;
};

Xml.Document = function Xml$Document(rootNodeName) {

	// Check types
	if(etypeof(rootNodeName) != "string") {
		throw new ArgumentException();
	}
	
	// Declare variables
	var oXmlDoc;
	
	// Attempt to get a xml document
	if (window.ActiveXObject) {
	
		strXml = "<" + rootNodeName + "/>";
		
		// Microsoft IE
		try {
			oXmlDoc = new ActiveXObject("Msxml2.DOMDocument.3.0");
			oXmlDoc.async = false;
			//pi = oXmlDoc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
			oXmlDoc.loadXML(strXml);
			//oXmlDoc.insertBefore(pi, oXmlDoc.firstChild);
		} catch(ex) {
			try
			{
				oXmlDoc = new ActiveXObject("Microsoft.XMLDOM");
				oXmlDoc.async = false;
				oXmlDoc.loadXML(strXml);
			} catch(ex) {
				oXmlDoc = false;
			}
		}
	} else if (document.implementation && document.implementation.createDocument) {
	
		// Mozilla firefox
		oXmlDoc = document.implementation.createDocument("", rootNodeName, null);
		//pi = oXmlDoc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"UTF-8\"");
		//oXmlDoc.insertBefore(pi, oXmlDoc.firstChild);
	} else {
		throw new Exception("Xml.Document is not supported on this computer");
	}
	
	/*
	// Extend the xml document
	Object.extend(oXmlDoc, {
		__type: "Xml.Document"
	} );
	*/
	
	return oXmlDoc;
};

var Net = {};
Net.XMLHttpRequest = function Net$XMLHttpRequest() {
	
	// Declare variables
	var oXmlHttpRequest;
	
	if (window.XMLHttpRequest) {
	
		// Mozilla firefox & IE 7
		try {
	    	oXmlHttpRequest = new XMLHttpRequest();
	    } catch(ex) {
	    	throw new Error("The XMLHttpRequest object is not available on this computer.");
	    }
	} else if (window.ActiveXObject) {
		
		// Microsoft IE <= 6
		try {
			oXmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(ex) {
			try {
				oXmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(ex) {
				throw new Error("The XMLHttpRequest object is not available on this computer.");
			}
		}
	}
	
	/*
	// Extend the xml htpp request
	Object.extend(oXmlHttpRequest, {
		__type: "Net.XMLHttpRequest"
	} );
	*/
	
	return oXmlHttpRequest;
};

Net.Request = function Net$Request(url, method, data, extended) {
	
	// Save settings
	this._url = url || "";
	this._method = method || "GET";
	this._data = data || null;
	this._extended = extended || false;
	this._async = true;
	this.ExtendedResult = null;
	
	// Error handling
	this.Error = false;
	this.Exceptions = [];
	
	// Events
	this.OnStateChanged = new Delegate();
	this.OnComplete = new Delegate();
};

Net.Request.prototype.MakeRequest = function Net$Request$MakeRequest() {
	
	// Get the xml http request
	this.hXMLHttpRequest = new Net.XMLHttpRequest();
	this.hXMLHttpRequest.open(this._method, this._url, this._async);
	this.hXMLHttpRequest.onreadystatechange = this._OnReadyStateChange.Bind(this);
	if(this._data !== null)
		this.hXMLHttpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	this.hXMLHttpRequest.send(this._data);
}

Net.Request.prototype._OnReadyStateChange = function Net$Request$_OnReadyStateChange() {
	
	this.OnStateChanged.Invoke();
	
	if(this.hXMLHttpRequest.readyState == 4) {
		this._ProcessResponse();
	}
}

Net.Request.prototype._ProcessResponse = function Net$Request$_ProcessResponse() {
	
	if(!this._extended) {
		
		// Notify the request is complete
		this.OnComplete.Invoke();
	} else {
		
		// Pre-process response
		if(this.hXMLHttpRequest.responseXML) {
			
			try {
				
				// Declare variables
				var hExceptions = this.hXMLHttpRequest.responseXML.getElementsByTagName("exception");
				var hResult = this.hXMLHttpRequest.responseXML.getElementsByTagName("result")[0];
				var hException, newException, resultType, requestResult;
				
				// Process remote exceptions (if any)
				if(hExceptions.length > 0) {
					this.Error = true;
					for(i = 0; i < hExceptions.length; i++) {
						hException = hExceptions[i];
						
						if(hException.hasChildNodes()) {
							newException = new Net.RemoteException(hException.firstChild.nodeValue)
							this.Exceptions.push(newException);
						}
					}
				}
				
				// Process the result
				resultType = hResult.getAttribute("type");
				switch(resultType) {
					case "int":
					
						// Return request result as an integer
						requestResult = parseInt(hResult.firstChild.nodeValue);
						break;
					case "bool":
					
						// Return request result as a boolean
						requestResult = hResult.firstChild.nodeValue;
						if(requestResult == "true") {
							requestResult = true;
						} else {
							requestResult = false;
						}
						break;
					default:
					case "string":
					
						// Return request result as a string
						requestResult = hResult.firstChild.nodeValue;
						break;
					case "object":
					
						// Return request result as an object
						eval("requestResult = " + hResult.firstChild.nodeValue);
						break;
					case "xml":
					
						// Return request result as a xml node (skip all text nodes on this branch)
						for(var z = 0; z < hResult.childNodes.length; z++) {
							if(hResult.childNodes[z].nodeType == 1)
								requestResult = hResult.childNodes[z];
						}
						
						break;
				}
				this.ExtendedResult = requestResult;
			}
			catch(ex)
			{
				this.Error = true;
				this.Exceptions.push(new Error("An error ocurred while processing the xml response from the server: " + ex.message));
			}
			
		} else {
			
			// Invalid response
			this.Error = true;
			this.Exceptions.push(new Error("The Net.Request object received an invalid response from the server (no xml data)."));
		}
		
		// Notify the request is complete
		this.OnComplete.Invoke();
	}
}

Net.Request.prototype.GetResponseText = function Net$Request$GetResponseText() {
	
	return this.hXMLHttpRequest.responseText;
}

Net.Request.prototype.Abort = function Net$Request$Abort() {
	
	this.hXMLHttpRequest.abort();
}

Net.RemoteException = function(message, innerException) {
	if(message !== undefined) {
		this.Message = message;
	}
	if(innerException !== undefined) {
		if(Exception.prototype.isPrototypeOf(innerException)) {
			this.InnerException = innerException;
		} else {
			throw new ArgumentException("The innerException must be of the type Exception");
		}
	}
}
Object.inherits(Net.RemoteException, Error);
Net.RemoteException.prototype.__type = "Net.RemoteError";


Net.Cookies = {};
Net.Cookies.CreateCookie = function Net$Cookies$CreateCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

Net.Cookies.ReadCookie = function Net$Cookies$ReadCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

Net.Cookies.EraseCookie = function Net$Cookies$EraseCookie(name) {
	createCookie(name,"",-1);
}

function ClearSelect(hSelect) {
	
	while(hSelect.options.length > 0) {
		hSelect.removeChild(hSelect.options[0]);
	}
}

function SelectAddOption(hSelect, strValue, strText, iIndex) {

	// Declare variables
	var newOption;
	
	newOption = document.createElement("OPTION");
	if(iIndex === undefined) {
		hSelect.options.add(newOption);
	} else {
		hSelect.options.add(newOption, iIndex);
	}
	newOption.value = strValue;
	newOption.appendChild(document.createTextNode(strText));
}

function RandomString(length) {
	var i;
	strString = "";
	arrChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHILJKLMNOPQRSTUVWXYZ".split("");
	for(i = 0; i < length; i++) {
		cId = arrChars[Math.round(Math.random() * (arrChars.length - 1))];
		strString += cId;
	}
	return strString;
}

/*
function Core() {

	this.Initialize = function() {
	
		// Declare variables
		var cId;
		var arrChars;
	
		this.bOpenDialog = false;
		this.hDialogWindow = null;
		this.arrDialogArguments = [];
		
		// Initialize variables
		this.OnWindowResize = new Delegate();
		this.OnWindowScroll = new Delegate();
		
		// Generate unique dialog name string
		this.strDialogName = "";
		arrChars = this.strChars.split("");
		for(i = 0; i < 64; i++) {
			cId = arrChars[Math.round(Math.random() * (arrChars.length - 1))];
			this.strDialogName += cId;
		}
		
		if(window.core) {
			throw new Exception("Core already present in window object!");
		}
		
		this.strParentWindowName = this.strDialogName + "parent";
		window.name = this.strParentWindowName;
		window.core = this;
		window.onfocus = this.OnWindowFocus;
		window.onunload = this.OnWindowClose;
		window.onresize = this._OnWindowResize.Bind(this);
		window.onscroll = this._OnWindowScroll.Bind(this);
	};
	
	this.ShowDialog = function(url, args, width, height) {
	
		// Declare variables
		var iScreenWidth, iScreenHeight, iTop, iLeft;
		
		// Close previous dialog if open
		if(this.bOpenDialog && this.hDialogWindow !== undefined) {
			this.hDialogWindow.close();
		}
		this.bOpenDialog = false;
	
		// Calculate exact dialog position
		try {
			iScreenWidth = screen.availWidth;
			iScreenHeight = screen.availHeight;
		} catch(ex) {
			iScreenWidth = 1024;
			iScreenHeight = 768;
		}
		
		iLeft = (iScreenWidth - width) / 2;
		iTop = (iScreenHeight - height) / 2;
		
		// Open the dialog window
		this.arrDialogArguments = args;
		this.hDialogWindow = window.open(url, target=this.strDialogName, "height = " + height + ", width = " + width + ", toolbar = 0, top = " + iTop + ", left = " + iLeft);
		this.hDialogWindow.core = this;
		this.bOpenDialog = true;
	};
	
	this.OnDialogClose = function() {
	
		this.core.bOpenDialog = false;
	};
	
	this.OnWindowFocus = function() {
		
		if(this.core.bOpenDialog && this.core.hDialogWindow !== undefined) {
			this.core.hDialogWindow.focus();
		}
	};
	
	this.OnWindowClose = function() {
		
		if(this.core.bOpenDialog && this.core.hDialogWindow !== undefined) {
			this.core.hDialogWindow.close();
		}
	};
	
	this.Initialize();
};
*/

function Core() {
	this.Initialize();
}

Core.prototype.Initialize = function Core$Initialize() {
	
	// Declare variables
	var cId;
	var arrChars;
	var strUid;
	
	// Initialize variables
	this.OnWindowResize = new Delegate();
	this.OnWindowScroll = new Delegate();
	
	this.hDhtmlEntry = document.body;
	
	// Generate unique dialog name string
	strUid = "";
	arrChars = this.strChars.split("");
	for(i = 0; i < 64; i++) {
		cId = arrChars[Math.round(Math.random() * (arrChars.length - 1))];
		strUid += cId;
	}
	
	if(window.core) {
		throw new Exception("Core already present in window object!");
	}
	
	this.strParentWindowName = strUid + "parent";
	window.name = this.strParentWindowName;
	window.core = this;
	window.onresize = this._OnWindowResize.Bind(this);
	window.onscroll = this._OnWindowScroll.Bind(this);
};

Core.prototype._OnWindowResize = function Core$_OnWindowResize(event) {
	this.OnWindowResize.Invoke(event);
	
	if(this.openDialog !== null)
		this.openDialog.OnResize_OnScroll();
	if(this.openErrorDialog !== null)
		this.openErrorDialog.OnResize_OnScroll();
}

Core.prototype._OnWindowScroll = function Core$_OnWindowScroll(event) {
	this.OnWindowScroll.Invoke(event);
	
	if(this.openDialog !== null)
		this.openDialog.OnResize_OnScroll();
	if(this.openErrorDialog !== null)
		this.openErrorDialog.OnResize_OnScroll();
}

Core.prototype._OnDialogClose = function Core$_OnDialogClose() {
	
	this.openDialog = null;
}

Core.prototype._OnErrorDialogClose = function Core$_OnErrorDialogClose() {
	
	this.openErrorDialog = null;
}

Core.prototype.ShowDialog = function Core$ShowDialog(strUrl, args, width, height) {
	
	if(this.openDialog !== null) {
		this.openDialog.Close();
	}
	
	this.openDialog = new UI.Dialog(this.hDhtmlEntry, TEXT['Dialog'], width, height);
	this.openDialog.OnClose.Suscribe(this._OnDialogClose, this);
	this.openDialog.LoadContents(strUrl);
}

Core.prototype.ShowErrorDialog = function Core$ShowErrorDialog(error) {
	
	if(this.openErrorDialog !== null) {
		this.openErrorDialog.Close();
	}
	
	this.openErrorDialog = new UI.ErrorDialog(this.hDhtmlEntry, error);
	this.openErrorDialog.OnClose.Suscribe(this._OnErrorDialogClose, this);
}

Core.prototype.__type = "Core";
Core.prototype.strChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHILJKLMNOPQRSTUVWXYZ";

Core.prototype.OnWindowResize = null;
Core.prototype.OnWindowScroll = null;

Core.prototype.openDialog = null;
Core.prototype.openErrorDialog = null;
Core.prototype.strOpendDialogUrl = null;
Core.prototype.strParentWindowName = null;
Core.prototype.hDhtmlEntry = null;

function TestResult() { 
	this.dateTime = new Date();
}
TestResult.prototype.__type = "TestResult";
TestResult.prototype.iDuration = 0;
TestResult.prototype.bShowRemarks = true;
TestResult.prototype.repeatMethod = null;
TestResult.prototype.questionDirection = null;
TestResult.prototype.questionSequence = null;
TestResult.prototype.testStyle = null;
TestResult.prototype.answerCheckType = null;
TestResult.prototype.iQuestionCount = 0;
TestResult.prototype.iErrorCount = 0;
TestResult.prototype.dateTime = null;

var UI = {};

UI.ToolBarButton = function UI$ToolBarButton(hToolBar) {

	this.Initialize = function UI$ToolBarButton$Initialize(hToolBar) {
	
		this.hToolBar = hToolBar;
		
		// Create toolbar div
		this.hDiv = document.createElement("DIV");
		this.hDiv.className = "toolbarDiv";
		this.hDiv.title = this.strToolTip;
		this.hDiv.owningClass = this;
		this.hDiv.onclick = this.OnClick;
		this.hDiv.onmouseout = this.OnMouseOut;
		this.hDiv.onmouseover = this.OnMouseOver;
		this.hToolBar.appendChild(this.hDiv);
		
		// Create image
		this.hImg = document.createElement("IMG");
		this.hImg.width = 16;
		this.hImg.height = 16;
		this.hImg.alt = "";
		this.hImg.title = this.strToolTip;
		this.hDiv.appendChild(this.hImg);
		
		// Create the delegate
		this.onClick = new Delegate();
	}
	
	this.OnClick = function UI$ToolBarButton$OnClick(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
	
		// Check if callback is valid
		//if(srcClass.onClickCallback && srcClass.enabled) {
		//	srcClass.onClickCallback();
		//}
		if(srcClass.enabled) {
			srcClass.onClick.Invoke(oEvent);
		}
	}
	
	this.OnMouseOut = function UI$ToolBarButton$OnMouseOut(e) {
	
		this.className = "toolbarDiv";
	}
	
	this.OnMouseOver = function UI$ToolBarButton$OnMouseOver(e) {
	
		// Declare variables
		var srcClass, oEvent;
		
		srcClass = this.owningClass;
		
		if(window.event) {
		
			// Windows IE and DOM level 2
			// Bug: using window.event seems to slowdown event handling in IE. Perhaps IE takes a lot of time setting the window.event object.
			oEvent = window.event;
		} else {
		
			// Firefox
			oEvent = e;
		}
		
		if(srcClass.enabled) {
			this.className = "toolbarDivHover";
		}
	}
	
	this.SetImage = function UI$ToolBarButton$SetImage(enableSrc, disabledSrc) {
	
		this.enabledImg = enableSrc;
		this.disabledImg = disabledSrc;
		
		if(this.enabled) {
			this.hImg.src = this.enabledImg;
		} else {
			this.hImg.src = this.disabledImg;
		}
	}
	
	this.Enable = function UI$ToolBarButton$Enable() {
		
		this.enabled = true;
		this.hImg.src = this.enabledImg;
	}
	
	this.Disable = function UI$ToolBarButton$Disable() {
		
		this.enabled = false;
		this.hImg.src = this.disabledImg;
	}
	
	this.SetToolTip = function UI$ToolBarButton$SetToolTip(text) {
		
		this.strToolTip = text;
		this.hDiv.title = this.strToolTip;
		this.hImg.title = this.strToolTip;
	}
	
	this.SetText = function UI$ToolBarButton$SetText(text) {
	
		// Declare variables
	
		this.strText = text;
		
		// Delete old P
		if(this.hLabel)
			this.hDiv.removeChild(this.hLabel);
		
		// Create new P
		this.hLabel = document.createElement("LABEL");
		this.hLabel.appendChild(document.createTextNode(text));
		this.hDiv.appendChild(this.hLabel);
	}
	
	this.Initialize(hToolBar);
}

UI.ToolBarButton.prototype.__type = "ToolBarButton";
UI.ToolBarButton.prototype.enabled = false;
UI.ToolBarButton.prototype.enabledImg = "";
UI.ToolBarButton.prototype.disabledImg = "";
UI.ToolBarButton.prototype.hImg = null;
UI.ToolBarButton.prototype.hDiv = null;
UI.ToolBarButton.prototype.hLabel = null;
UI.ToolBarButton.prototype.strToolTip = "";
UI.ToolBarButton.prototype.strText = "";
UI.ToolBarButton.prototype.hToolBar = null;
UI.ToolBarButton.prototype.oEvent = null;
UI.ToolBarButton.prototype.onClick = null;

UI.FileBrowser = function UI$FileBrowser(hParentDiv, width, height) {
	
	this.Initialize = function UI$FileBrowser$Initialize(hParentDiv, width, height) {
	
		// Declare variables
		var newRow, newP;
		
		// Store handle
		this.hParentDiv = hParentDiv;
		
		this.iWidth = width || 450;
		this.iHeight = height || 400;
		
		this.arrCategoryExculsions = new Array();
		this.arrFileExculsions = new Array();
	
		// Create container table
		this.hContentTable = document.createElement("TABLE");
		this.hContentTable.cellSpacing = 0;
		this.hContentTable.cellPadding = 0;
		this.hContentTable.className = "fileBrowserContainer";
		this.hContentTable.style.width = this.iWidth + "px";
		this.hContentTable.style.height = this.iHeight + "px";
		this.hParentDiv.appendChild(this.hContentTable);
		
		// Create the toolbar cell
		newRow = this.hContentTable.insertRow(-1);
		this.hToolbarCell = newRow.insertCell(-1);
		this.hToolbarCell.className = "fileBrowserToolbar";
		
		// Create the location div
		this.hLocationDiv = document.createElement("DIV");
		this.hLocationDiv.className = "fileBrowserLocationDiv";
		this.hToolbarCell.appendChild(this.hLocationDiv);
		
		// Initialize toolbar
		this.IntializeToolbar();
		
		// Create the content cell
		newRow = this.hContentTable.insertRow(-1);
		this.hContentCell = newRow.insertCell(-1);
		this.hContentCell.style.height = this.iHeight - 30 + "px";
		
		// Create the fileview div
		this.fileList = new UI.FileList(this.hContentCell, this.iWidth, this.iHeight - 30);
		this.fileList.OnItemClick.Suscribe(this._OnFilelistClick, this);
		
		// Create the loading div
		this.hLoadingDiv = document.createElement("DIV");
		this.hLoadingDiv.className = "fileBrowserLoadingDiv";
		this.hContentCell.appendChild(this.hLoadingDiv);
		
		newP = document.createElement("P");
		newP.appendChild(document.createTextNode(TEXT['PleaseWait']));
		newP.appendChild(document.createElement("BR"));
		newP.appendChild(document.createTextNode(TEXT['Loading']));
		this.hLoadingDiv.appendChild(newP);
		
		// Event delegates
		this.OnWordlistClick = new Delegate();
		
		// Set initial category
		this.arrCategoryLog = new Array();
		this.SetCurrentCategory("", TEXT['FileBrowser.RootCategories']);
		this.arrCurrentCategoryWordlists = new Array();
		
		// Switch to loading mode
		this.SetMode("loading");
		
		this.goBackButton.Enable();
		this.goFowardButton.Enable();
	};
	
	this.IntializeToolbar = function UI$FileBrowser$IntializeToolbar() {
	
		this.goBackButton = new UI.ToolBarButton(this.hToolbarCell);
		this.goBackButton.SetImage("images/icon-goback2.png", "images/icon-goback2-grey.png");
		this.goBackButton.SetToolTip(TEXT['FileBrowser.GoBack']);
		this.goBackButton.onClickCallback = this.OnOpenButtonClick;
		this.goBackButton.onClickCallbackClass = this;
		
		this.goFowardButton = new UI.ToolBarButton(this.hToolbarCell);
		this.goFowardButton.SetImage("images/icon-gofoward2.png", "images/icon-gofoward2-grey.png");
		this.goFowardButton.SetToolTip(TEXT['FileBrowser.GoNext']);
		this.goFowardButton.onClickCallback = this.OnOpenButtonClick;
		this.goFowardButton.onClickCallbackClass = this;
	};
	
	this.SetMode = function UI$FileBrowser$SetMode(mode) {
	
		switch(mode) {
			case "loading":
			
				// Show the loading div
				this.fileList.Hide();
				
				this.hLoadingDiv.style.visibility = "visible";
				this.hLoadingDiv.style.display = "block";
				break;
			case "fileview":
			
				// Show the fileview div
				this.fileList.Show();
				
				this.hLoadingDiv.style.visibility = "hidden";
				this.hLoadingDiv.style.display = "none";
				break;
		}
	}
	
	this.Initialize(hParentDiv, width, height);
}

UI.FileBrowser.prototype.GetCategoryContents = function UI$FileBrowser$GetCategoryContents() {
	
	// Declare variables
	var requestUrl;
	
	this.fileList.Clear();
	this.SetMode("loading");
	
	// Build request url
	requestUrl = "xml.php?page=category&category=" + this.iCurrentCategory;
	if(this.bShowOnlyWriteableCategories)
		requestUrl += "&writeable";
	
	this.Request = new Net.Request(requestUrl, "GET", null, true);
	this.Request.OnComplete.Suscribe(this._OnGetCategoryContents, this);
	this.Request.MakeRequest();
}

UI.FileBrowser.prototype._OnGetCategoryContents = function UI$FileBrowser$_OnGetCategoryContents() {
	
	// Delcare variables
	var hXml, hNode;
	var iParentId, iId;
	var strParentName, strName;
	var newListItem;
	
	if(this.Request.ExtendedResult) {
		
		hXml = this.Request.ExtendedResult;
		
		// Create the "up" link
		if(hXml.nodeName == "category") {
			iParentId = hXml.getAttribute("parentId") || "";
			strParentName = hXml.getAttribute("parentName");
			
			newListItem = new UI.FileListItem(iParentId, "parent", strParentName, "");
			this.fileList.Add(newListItem);
		}
		
		// Process child nodes
		for(i = 0; i < hXml.childNodes.length; i++) {
			hNode = hXml.childNodes[i];
			
			switch(hNode.nodeName) {
				case "category":
				
					// Process a category node
					if(!this.bShowCategories)
						break;
						
					strName = hNode.getAttribute("name");
					iId = hNode.getAttribute("id");
					
					if(this._IsExcluded("category", iId))
						break;
					
					newListItem = new UI.FileListItem(iId, "category", strName);
					this.fileList.Add(newListItem);
					break;
				case "wordlist":
				
					// Process a file node
					if(!this.bShowFiles)
						break;
						
					strName = hNode.getAttribute("name");
					iId = hNode.getAttribute("id");
					
					if(this._IsExcluded("wordlist", iId))
						break;
						
					strPrimaryLanguage = hNode.getAttribute("primaryLanguage");
					strSecondaryLanguage = hNode.getAttribute("secondaryLanguage");
					newListItem = new UI.FileListItem(iId, "wordlist", strName, "", strPrimaryLanguage, strSecondaryLanguage);
					this.fileList.Add(newListItem);
					break;
			}
		}
	}
	
	this.SetMode("fileview");
}

UI.FileBrowser.prototype.Navigate = function UI$FileBrowser$Navigate(categoryId, strName) {
	
	this.SetCurrentCategory(categoryId, strName);
	this.GetCategoryContents();
}

UI.FileBrowser.prototype._OnFilelistClick = function UI$FileBrowser$_OnFilelistClick(file) {
	
	// Fire the OnWordlistClick event
	switch(file.type) {
		case "category":
		case "parent":
			this.Navigate(file.id, file.name);
			break;
		case "wordlist":
			this.OnWordlistClick.Invoke(file);
			break;
	}
}

UI.FileBrowser.prototype.SetCurrentCategory = function UI$FileBrowser$_IsExcluded(categoryId, name) {
	
	var newP, newImg;
	
	while(this.hLocationDiv.hasChildNodes())
		this.hLocationDiv.removeChild(this.hLocationDiv.firstChild);
	
	newImg = document.createElement("IMG");
	newImg.src = "images/icon-folder-16.png";
	newImg.style.marginRight = "6px";
	newImg.style.position = "relative";
	newImg.style.top = "3px";
	newP = document.createElement("P");
	newP.appendChild(newImg);
	newP.appendChild(document.createTextNode(name));
	newP.style.position = "relative";
	newP.style.top = "-3px";
	this.hLocationDiv.appendChild(newP);
	
	this.iCurrentCategory = categoryId;
	this.strCurrentCategory = name;
	
	this.arrCategoryLog.push(this.iCurrentCategory);
	if(this.arrCategoryLog.length > 10) {
		this.arrCategoryLog.splice(0, 1);
	} else {
		this.iCategoryLogPointer++;
	}
}

UI.FileBrowser.prototype._IsExcluded = function UI$FileBrowser$_IsExcluded(type, id) {
	
	switch(type) {
		case "wordlist":
			if(Array.IndexOf(this.arrFileExculsions, id) > -1) {
				return true;
			}
			break;
		case "category":
			if(Array.IndexOf(this.arrCategoryExculsions , id) > -1) {
				return true;
			}
			break;
	}
	
	return false;
}

UI.FileBrowser.prototype.__type = "UI.FileBrowser";
UI.FileBrowser.prototype.xmlUrl = "xml.php";
UI.FileBrowser.prototype.ajaxRequest = null;
UI.FileBrowser.prototype.bShowFiles = true;
UI.FileBrowser.prototype.bShowCategories = true;
UI.FileBrowser.prototype.bShowOnlyWriteableCategories = false;
UI.FileBrowser.prototype.bShowToolbar = true;
UI.FileBrowser.prototype.iSelectFile = 0;
UI.FileBrowser.prototype.iCurrentCategory = "";
UI.FileBrowser.prototype.strCurrentCategory = "";
UI.FileBrowser.prototype.arrCategoryLog = null;
UI.FileBrowser.prototype.iCategoryLogPointer = -1;	
UI.FileBrowser.prototype.fileList = null;
UI.FileBrowser.prototype.iWidth = 450;
UI.FileBrowser.prototype.iHeight = 400;
UI.FileBrowser.prototype.bInitializing = true;
UI.FileBrowser.prototype.arrCategoryExculsions = null;
UI.FileBrowser.prototype.arrFileExculsions = null;

UI.FileBrowser.prototype.hParentDiv = null;
UI.FileBrowser.prototype.hContentTable = null;
UI.FileBrowser.prototype.hToolbarCell = null;
UI.FileBrowser.prototype.hLocationDiv = null;
UI.FileBrowser.prototype.hLoadingDiv = null;
UI.FileBrowser.prototype.hContentCell = null;

UI.FileBrowser.prototype.goBackButton = null;
UI.FileBrowser.prototype.goFowardButton = null;

/**
 * Initializes a new instance of the UI.FileListItem object.
 * @param {Object} id
 * @param {Object} type
 * @param {Object} name
 * @param {Object} description
 * @param {Object} primaryLanguage
 * @param {Object} secondaryLanguage
 */
UI.FileListItem = function UI$FileListItem(id, type, name, description, primaryLanguage, secondaryLanguage) {
	this.id = id || "";
	this.type = type || "file";
	this.name = name || "";
	this.description = description || "";
	this.primaryLanguage = primaryLanguage || "";
	this.secondaryLanguage = secondaryLanguage || "";
}

UI.FileListItem.prototype.__type = "UI.FileListItem";
UI.FileListItem.prototype.id = null;
UI.FileListItem.prototype.primaryLanguage = "";
UI.FileListItem.prototype.secondaryLanguage = "";
UI.FileListItem.prototype.name = "";
UI.FileListItem.prototype.description = "";
UI.FileListItem.prototype.type = "";

/**
 * Initializes a new instance of the UI.FileList object
 * @param {Object} hParentDiv
 */
UI.FileList = function UI$FileList(hParentDiv, width, height) {
	
	this.iWidth = width || 450;
	this.iHeight = height || 300;
	
	this.Initialize(hParentDiv);
}

UI.FileList.prototype.Initialize = function UI$FileList$Initialize(hParentDiv) {
	
	// Declare variables
	var newTable, newRow, newCell;
	
	// Store handle
	this.hParentDiv = hParentDiv;
	
	this.arrItems = new Array();
	this.OnItemClick = new Delegate();
	this.OnChanged = new Delegate();
	
	// Create the container div
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "fileListContainerDiv";
	this.hContainerDiv.style.width = this.iWidth + "px";
	this.hContainerDiv.style.height = this.iHeight + "px";
	this.hParentDiv.appendChild(this.hContainerDiv);
	
	// Create header table
	newTable = document.createElement("TABLE");
	newTable.className = "fileBrowserFileHeaderTable";
	newTable.cellSpacing = "0";
	newTable.cellPadding = "0";
	this.hContainerDiv.appendChild(newTable);
	
	// Create header table contents
	newRow = newTable.insertRow(-1);
	newCell = newRow.insertCell(-1);
	newCell.className = "fileBrowserFileHeaderTableCell";
	newCell.style.width = (((this.iWidth - 20) / 5) * 3) + "px";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['FileBrowser.FileName']));
	newCell.appendChild(newP);
	newCell = newRow.insertCell(-1);
	newCell.className = "fileBrowserFileHeaderTableCell";
	newCell.style.width = ((this.iWidth - 20) / 5) + "px";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['FileBrowser.PrimaryLanguage']));
	newCell.appendChild(newP);
	newCell = newRow.insertCell(-1);
	newCell.className = "fileBrowserFileHeaderTableCell";
	newCell.style.width = ((this.iWidth - 20) / 5) + "px";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['FileBrowser.SecondaryLanguage']));
	newCell.appendChild(newP);
	
	// Spacer
	newCell = newRow.insertCell(-1);
	newCell.className = "fileBrowserFileHeaderTableCell";
	newCell.style.width = "20px";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(' '));
	newCell.appendChild(newP);
	
	// Create actual file div
	newDiv = document.createElement("DIV");
	newDiv.className = "fileBrowserFileTableDiv";
	newDiv.style.height = (this.iHeight - 20) + "px";
	this.hContainerDiv.appendChild(newDiv);
	
	// Create file table
	this.hFileTable = document.createElement("TABLE");
	this.hFileTable.className = "commonTable wordlistTable";
	//this.hFileTable.style.width = this.iWidth - 18 + "px";
	this.hFileTable.cellSpacing = "0";
	this.hFileTable.cellPadding = "0";
	newDiv.appendChild(this.hFileTable);
}

UI.FileList.prototype.Add = function UI$FileList$Add(file) {
	
	// Declare variables
	var newRow, newCell, newA, newImg;
	var rowCount;
	var strRowStyle;
	
	// Check for duplicates
	if(!this.bAllowDuplicates) {
		if(this.IndexOf(file) > -1)
			return;
	}
	
	// Get current row count and determine row style
	rowCount = this.hFileTable.rows.length;
	if(rowCount % 2 == 0) {
		strRowStyle = "evenRow";
	} else {
		strRowStyle = "oddRow";
	}
	
	// Store object
	this.arrItems.push(file);
	
	switch(file.type) {
		case "wordlist":
			icon = "images/icon-vocfile-16.jpg";
			break;
		case "category":
			icon = "images/icon-folder-16.png";
			break;
		case "parent":
			icon = "images/icon-parentfolder-16.png";
			break;
	}
	
	newRow = this.hFileTable.insertRow(-1);
	newCell = newRow.insertCell(-1);
	newCell.className = strRowStyle;
	newCell.style.width = ((this.iWidth - 20) / 5 * 3) + "px";
	newA = document.createElement("A");
	newA.className = "folderDivItem";
	newA.href = "javascript:void(0);";
	newA.onclick = this._OnFileClick.Bind(this, file);
	
	newCell.appendChild(newA);
	newImg = document.createElement("IMG");
	newImg.src = icon;
	newA.appendChild(newImg);
	newA.appendChild(document.createTextNode(file.name));
	newCell.appendChild(newA);
	
	newCell = newRow.insertCell(-1);
	newCell.className = strRowStyle;
	newCell.style.width = ((this.iWidth - 20) / 5) + "px";
	newCell.appendChild(document.createTextNode(file.primaryLanguage));
	
	newCell = newRow.insertCell(-1);
	newCell.className = strRowStyle;
	newCell.style.width = ((this.iWidth - 20) / 5) + "px";
	newCell.appendChild(document.createTextNode(file.secondaryLanguage));
	
	this.OnChanged.Invoke();
}

UI.FileList.prototype.Remove = function UI$FileList$Remove(file) {
	
	// Declare variables
	var iIndex;
	var hRow, hCell;
	
	iIndex = this.IndexOf(file);
	
	if(iIndex == -1)
		throw new Error("The UI.FileListItem to remove is not present in this UI.FileList.");
		
	// Delete the row in the file table and the file in the item collection
	this.hFileTable.deleteRow(iIndex);
	this.arrItems.splice(iIndex, 1);
	
	for(var i = iIndex; i < this.hFileTable.rows.length; i++) {
		hRow = this.hFileTable.rows[i];
		for(j = 0; j < hRow.cells.length; j++) {
			hCell = hRow.cells[j];
			if(hCell.className == "wordTableEvenCell") {
				hCell.className = "wordTableOddCell";
			} else {
				hCell.className = "wordTableEvenCell";
			}
		}
	}
	
	this.OnChanged.Invoke();
}

UI.FileList.prototype._OnFileClick = function UI$FileList$_OnFileClick(file) {
	
	this.OnItemClick.Invoke(file);
}

UI.FileList.prototype.Clear = function UI$FileList$Clear() {
	
	while(this.hFileTable.rows.length > 0)
		this.hFileTable.deleteRow(0);
	
	this.arrItems = new Array();
	
	this.OnChanged.Invoke();
}

UI.FileList.prototype.Show = function UI$FileList$Show() {
	
	this.hContainerDiv.style.display = "block";
	this.hContainerDiv.style.visibility = "visible";
}

UI.FileList.prototype.Hide = function UI$FileList$Hide() {
	
	this.hContainerDiv.style.display = "none";
	this.hContainerDiv.style.visibility = "hidden";
}

UI.FileList.prototype.SetAllowDuplicates = function UI$FileList$SetAllowDuplicates(bAllow) {
	
	this.bAllowDuplicates = bAllow;
}

UI.FileList.prototype.IndexOf = function UI$FileList$IndexOf(file) {
	
	for(var i = 0; i < this.arrItems.length; i++) {
		if(this.arrItems[i].type == file.type && this.arrItems[i].id == file.id)
			return i;
	}
	
	return -1;
}

UI.FileList.prototype.Serialize = function UI$FileList$Serialize() {
	
	// Declare variables
	var output = "";
	var file;
	
	for(var i = 0; i < this.arrItems.length; i++) {
		file = this.arrItems[i];
		
		if(i > 0)
			output += ",";
		output += file.type + "," + file.id;
	}
	
	return output;
}

UI.FileList.prototype.__type = "UI.FileList";

UI.FileList.prototype.arrItems = null;
UI.FileList.prototype.OnItemClick = null;
UI.FileList.prototype.OnChanged = null;
UI.FileList.prototype.iWidth = 450;
UI.FileList.prototype.iHeight = 300;
UI.FileList.prototype.bAllowDuplicates = true;

UI.FileList.prototype.hContainerDiv = null;
UI.FileList.prototype.hParentDiv = null;
UI.FileList.prototype.hFileTable = null;

UI.FilePicker = function(hParentDiv, width, height) {
	
	this.Initialize(hParentDiv, width, height);
}

UI.FilePicker.prototype.Initialize = function(hParentDiv, width, height) {
	
	// Declare variables
	var newRow, newCell, newH2;
	
	// Store handles
	this.hParentDiv = hParentDiv;
	
	this.iWidth = width || 910;
	this.iHeight = height || 400;
	
	// Create the container table
	this.hContainerTable = document.createElement("TABLE");
	this.hContainerTable.cellSpacing = "0";
	this.hContainerTable.cellPadding = "0";
	this.hContainerTable.className = "filePickerContainer";
	this.hParentDiv.appendChild(this.hContainerTable);
	
	newRow = this.hContainerTable.insertRow(-1);
	this.hFileBrowserCell = newRow.insertCell(-1);
	this.hFileBrowserCell.rowSpan = 2;
	
	newCell = newRow.insertCell(-1);
	newCell.rowSpan = 2;
	newCell.style.width = "10px";
	
	this.hFileListTopCell = newRow.insertCell(-1);
	this.hFileListTopCell.className = "fileBrowserToolbar";
	newH2 = document.createElement("H2");
	newH2.appendChild(document.createTextNode(TEXT['FilePicker.SelectedWordlists']));
	this.hFileListTopCell.appendChild(newH2);
	
	newRow = this.hContainerTable.insertRow(-1);
	this.hFileListCell = newRow.insertCell(-1);
	
	// Create the filebrowser
	this.fileBrowser = new UI.FileBrowser(this.hFileBrowserCell, (this.iWidth - 10) / 2, this.iHeight);
	this.fileBrowser.OnWordlistClick.Suscribe(this._OnFileBrowserWordlistClick, this);
	this.fileBrowser.GetCategoryContents();
	
	// Create the file list
	this.fileList = new UI.FileList(this.hFileListCell, (this.iWidth - 10) / 2, this.iHeight - 30);
	this.fileList.OnItemClick.Suscribe(this._OnFileListItemClick, this);
	this.fileList.SetAllowDuplicates(false);
}

UI.FilePicker.prototype._OnFileBrowserWordlistClick = function(file) {
	
	// Declare variables
	var firstFile;
	
	// Check if the file to add is a wordlist and if so, if the wordlist has 
	// the same languages as the other wordlist in the FileList
	if(this.bForceEqualLanguages && this.fileList.arrItems.length > 0 && file.type == "wordlist") {
		firstFile = this.fileList.arrItems[0];
		if((file.primaryLanguage.toLowerCase() == firstFile.primaryLanguage.toLowerCase() && file.secondaryLanguage.toLowerCase() == firstFile.secondaryLanguage.toLowerCase()) ||
			(file.secondaryLanguage.toLowerCase() == firstFile.primaryLanguage.toLowerCase() && file.primaryLanguage.toLowerCase() == firstFile.secondaryLanguage.toLowerCase())) {
			
			this.fileList.Add(file);
		} else {
			alert(TEXT['FilePicker.LanguagesDontMatch']);
		}
	} else {
		this.fileList.Add(file);
	}
}

UI.FilePicker.prototype._OnFileListItemClick = function(file) {
	
	this.fileList.Remove(file);
}

UI.FilePicker.prototype.SerializeSelection = function() {
	
	return this.fileList.Serialize();
}

UI.FilePicker.prototype.__type = "UI.FilePicker";

UI.FilePicker.prototype.fileBrowser = null;
UI.FilePicker.prototype.fileList = null;
UI.FilePicker.prototype.iWidth = 910;
UI.FilePicker.prototype.iHeight = 450;
UI.FilePicker.prototype.bForceEqualLanguages = false;

UI.FilePicker.prototype.hParentDiv = null;
UI.FilePicker.prototype.hContainerTable = null;
UI.FilePicker.prototype.hFileBrowserCell = null;
UI.FilePicker.prototype.hFileListTopCell = null;
UI.FilePicker.prototype.hFileListCell = null;

/**
 * Initializes a new instance of the UI.PlannerItem class
 * @param {Object} text (Optional) A string containing description of the planned item
 * @param {Object} itemId (Optional) The id of the planned item (Defaults to -1 (new))
 * @param {Object} backgroundColor (Optional) The background color of the item as a CSS valid value (Defaults to #ffffff)
 * @param {Object} borderColor (Optional) The border color of the item as a CSS valid value (Defaults to #000000)
 */
UI.PlannerItem = function(text, planningId, itemId, backgroundColor, borderColor, itemType, bFinished) {
	
	// Set default values
	if(itemId === undefined)
		itemId = -1;
	if(backgroundColor === undefined)
		backgroundColor = "white";
	if(borderColor === undefined)
		borderColor = "black";
	
	// Set default values
	this.hParentPlannerDay = null;
	
	// Store values
	this.strText = text;
	this.iPlanningId = planningId;
	this.iItemId = itemId;
	this.itemType = itemType;
	this.bFinished = bFinished;
	
	// Create the main div
	this.hDiv = document.createElement("DIV");
	this.hDiv.className = "plannerItemDiv";
	this.hDiv.style.backgroundColor = backgroundColor;
	this.hDiv.style.borderColor = borderColor;
	this.hDiv.onclick = this.OnClick.Bind(this);
	
	// Create the checked image if appropriate
	if(this.bFinished) {
		this.hCheckedImg = document.createElement("IMG");
		this.hCheckedImg.className = "contentImgLeft";
		this.hCheckedImg.src = "images/icon-checked-16.png";
		this.hDiv.appendChild(this.hCheckedImg);
	}
	
	// Create text representation
	this.hP = document.createElement("P");
	this.hP.appendChild(document.createTextNode(text));
	this.hDiv.appendChild(this.hP);
}

UI.PlannerItem.prototype.__type = "UI.PlannerItem"
UI.PlannerItem.prototype.hDiv = null;
UI.PlannerItem.prototype.hParentPlannerDay = null;
UI.PlannerItem.prototype.itemType = null;
UI.PlannerItem.prototype.iItemId = null;
UI.PlannerItem.prototype.iPlanningId = null;
UI.PlannerItem.prototype.bFinished = false;

UI.PlannerItem.prototype.OnClick = function(e) {
	
	//window.open("index.php?page=planner&sub=execute&planning=" + this.iPlanningId + "&planningdateid=" + this.iItemId + "&type=" + this.itemType, target='_self');
	switch(this.itemType) {
		case "learnnew":
			core.ShowDialog("dialog.php?page=executelearnnew&planning=" + this.iPlanningId + "&planningdateid=" + this.iItemId, null, 400, 250);
			break;
		case "progressiontest":
			core.ShowDialog("dialog.php?page=executeprogressiontest&planning=" + this.iPlanningId + "&planningdateid=" + this.iItemId, null, 400, 250);
			break;
	}
}

/**
 * Initializes a new instance of the UI.PlannerDay class.
 * @param {Object} hElement (Optional) The DOM Element to append the UI.PlannerDay to.
 */
UI.PlannerDay = function(hElement, bShowButton) {
	
	this.bShowNewPlanningButton = bShowButton || false;
	
	// Declare variables
	var newP, newImg, newA;
	
	this.hDiv = document.createElement("DIV");
	this.hDiv.className = "plannerDayDiv";
	
	this.hNullDiv = document.createElement("DIV");
	newP = document.createElement("P");
	newP.className = "center";
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createTextNode(TEXT['PlanningDay.Empty']));
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createElement("BR"));
	this.hNullDiv.appendChild(newP);
	this.hDiv.appendChild(this.hNullDiv);
	
	this.hNewPlanningDiv = document.createElement("DIV");
	newP = document.createElement("P");
	newP.className = "center";
	newA = document.createElement("A");
	newA.href = "index.php?page=planner&sub=newplanning1";
	newA.appendChild(document.createElement("BR"));
	newImg = document.createElement("IMG");
	newImg.src = "images/icon-create-planning.png";
	newA.appendChild(newImg);
	newA.appendChild(document.createElement("BR"));
	newA.appendChild(document.createTextNode(TEXT['PlanningDay.NewPlanningButton']));
	newA.appendChild(document.createElement("BR"));
	newA.appendChild(document.createElement("BR"));
	newP.appendChild(newA);
	this.hNewPlanningDiv.appendChild(newP);
	this.hDiv.appendChild(this.hNewPlanningDiv);
	
	this.arrItems = new Array();
	
	if(hElement === undefined) {
		this.hParentElement = null;
	} else {
		this.SetParentElement(hElement)
	}
	
	this.Invalidate();
}

UI.PlannerDay.prototype.__type = "UI.PlannerDay"
UI.PlannerDay.prototype.hDiv = null;
UI.PlannerDay.prototype.hNullDiv = null;
UI.PlannerDay.prototype.hNewPlanningDiv = null;
UI.PlannerDay.prototype.bShowNewPlanningButton = false;

/**
 * Adds the passed PlannerItem to this PlannerDay
 * @param {Object} item The PlannerItem to add to this PlannerDay
 */
UI.PlannerDay.prototype.AddItem = function(item) {
	
	// Validate types
	if(etypeof(item) != "UI.PlannerItem") {
		throw new ArgumentError("The item argument must be of the type UI.PlannerItem");
	}
	
	// Add the item to the item collection
	this.arrItems.push(item);
	
	// Setup visual presentation in the html DOM
	this.hDiv.insertBefore(item.hDiv, this.hNewPlanningDiv);
	
	item.hParentPlannerDay = this;
	
	this.Invalidate();
}

UI.PlannerDay.prototype.SetParentElement = function(hElement) {
	
	// Unregister the UI.PlannerDay div at the current parent element
	if(this.hParentElement != null) {
		this.hParentElement.removeChild(this.hDiv);
	}
	
	this.hParentElement = hElement;
	this.hParentElement.appendChild(this.hDiv);
}

UI.PlannerDay.prototype.Invalidate = function() {
	
	if(this.arrItems.length > 0) {
		this.hNullDiv.style.display = "none";
	} else {
		this.hNullDiv.style.display = "block";
	}
	
	if(this.bShowNewPlanningButton) {
		this.hNewPlanningDiv.style.display = "block";
	} else {
		this.hNewPlanningDiv.style.display = "none";
	}
}

UI.PlanningAgenda = function(hParentElement) {
	
	this.Initialize(hParentElement);
}

UI.PlanningAgenda.prototype.Initialize = function(hParentElement) {
	
	// Store handle
	this.hParentElement = hParentElement;
	
	// Bind loading div
	this.hLoadingDiv = document.getElementById("LoadingDiv");
	
	// Bind content parent div
	this.hEditorContentParent = document.getElementById("contentDivParent");
	
	// Bind status bar
	this.hStatusBar = document.getElementById("StatusBar");
	this.hTitleBar = document.getElementById("TitleBar");
	this.hToolBar = document.getElementById("ToolBar");
	this.SetStatusBarDefaultMessage(TEXT['Loading']);
	
	// Attempt to finish initialization
	this.FinalizeInitialization();
}

UI.PlanningAgenda.prototype.SetStatusBarDefaultMessage = function(strMessage) {
		
	this.strStatusBarDefaultMessage = strMessage;
	this.UpdateStatusBar();
}

UI.PlanningAgenda.prototype.UpdateStatusBar = function() {
	
	// Clear the statusbar
	while(this.hStatusBar.childNodes.length > 0)
		this.hStatusBar.removeChild(this.hStatusBar.firstChild);
		
	if(this.hStatusBarTimer == null || !this.hStatusBarTimer || this.hStatusBarTimer == undefined) {
	
		// Set the default message
		this.hStatusBar.appendChild(document.createTextNode(this.strStatusBarDefaultMessage));
	} else {
	
		// Set the current message
		this.hStatusBar.appendChild(document.createTextNode(this.strStatusBarCurrentMessage));
	}
}

UI.PlanningAgenda.prototype.SetStatusBarMessage = function(strMessage, iMilliseconds) {
	
	// Clear the timer
	if(this.hStatusBarTimer != null)
		clearTimeout(this.hStatusBarTimer);
	
	if(iMilliseconds == -1 || iMilliseconds == undefined) {
	
		// Display the new message as the default message
		this.strStatusBarDefaultMessage = strMessage;
		
	} else {
	
		// Display the new message as a temporary message
		this.hStatusBarTimer = setTimeout(this.OnStatusBarTimerTimeout, iMilliseconds);
		this.strStatusBarCurrentMessage = strMessage;
	}
	
	this.UpdateStatusBar();
}

UI.PlanningAgenda.prototype.OnStatusBarTimerTimeout = function() {

	this.editor.hStatusBarTimer = null;
	this.editor.UpdateStatusBar();
}

UI.PlanningAgenda.prototype.FinalizeInitialization = function() {
		
	// Check if intitializing
	if(!this.bInitializing) {
	
		// Check if all procedures have been finished
		if(!this.bLoadingData) {
			this.SetMode(this.targetMode);
			
			this.RefreshWordTableHeaders();
			this.RefreshTestSettings();
			this.Invalidate();
			this.InvalidateTestDiv();
		}
	}
}

UI.PlanningAgenda.prototype.SetMode = function (mode) {
	
	// Check if editmode should change
	if(this.mode == mode)
		return;

	switch(mode) {
		case "agenda":
		
			// Switch to edit mode
			this.mode = mode;
			
			this.ShowDiv(mode);
				
			break;
	}
}

UI.PlanningAgenda.prototype.ShowDiv = function(div) {

	this.hTestDiv.style.visibility = "hidden";
	this.hTestDiv.style.display = "none";
	this.hAgendaDiv.style.visibility = "hidden";
	this.hAgendaDiv.style.display = "none";
	
	switch(div) {
		case "agenda":
			this.hAgendaDiv.style.visibility = "visible";
			this.hAgendaDiv.style.display = "block";
			break;
		case "loading":
			this.hLoadingDiv.style.visibility = "visible";
			this.hLoadingDiv.style.display = "block";
			break;
	}
}

UI.PlanningAgenda.prototype.__type = "UI.PlanningAgenda";

UI.PlanningAgenda.prototype.hStatusBarTimer = null;
UI.PlanningAgenda.prototype.strStatusBarDefaultMessage = "";
UI.PlanningAgenda.prototype.bInitializing = false;
UI.PlanningAgenda.prototype.bLoadingData = false;
UI.PlanningAgenda.prototype.mode = "loading";
UI.PlanningAgenda.prototype.targetMode = "loading";

UI.PlanningAgenda.prototype.hParentElement = null;
UI.PlanningAgenda.prototype.hLoadingDiv = null;
UI.PlanningAgenda.prototype.hEditorContentParent = null;
UI.PlanningAgenda.prototype.hStatusBar = null;
UI.PlanningAgenda.prototype.hTitleBar = null;
UI.PlanningAgenda.prototype.hToolBar = null;
UI.PlanningAgenda.prototype.hAgendaDiv = null;

UI.PlanningEditor = function(hParentElement, startDate, endData, wordCount) {
	this.Initialize(hParentElement, startDate, endData, wordCount);
}

UI.PlanningEditor.prototype.Initialize = function(hParentElement, startDate, endData, wordCount) {
	
	// Declare variables
	var i;
	
	// Store handle
	this.hParentElement = hParentElement;
	
	this.startDate = startDate;
	this.endDate = endDate;
	this.wordCount = wordCount;
	
	// Create layout table
	newTable = document.createElement("TABLE");
	newTable.cellSpacing = "0";
	newTable.cellPadding = "0";
	newTable.className = "containerTable";
	this.hParentElement.appendChild(newTable);
	
	newRow = newTable.insertRow(-1);
	hTitleCell = newRow.insertCell(-1);
	hTitleCell.className = "headerCell";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['PlanningEditor.Title']));
	hTitleCell.appendChild(newP);
	
	newRow = newTable.insertRow(-1);
	this.hContentCell = newRow.insertCell(-1);
	this.hContentCell.className = "contentCell planningEditorContentCell";
	
	this.hContentCellDiv = document.createElement("DIV");
	this.hContentCellDiv.className = "planningEditorContentCell";
	this.hContentCell.appendChild(this.hContentCellDiv);
	
	this.hDayTable = document.createElement("TABLE");
	this.hDayTable.cellSpacing = "0";
	this.hDayTable.cellPadding = "0";
	this.hContentCellDiv.appendChild(this.hDayTable);
	newDayTableRow = this.hDayTable.insertRow(-1);
	
	timeSpan = this.endDate.getTime() - this.startDate.getTime();
	timeSpanDays = Math.round(timeSpan / (1000 * 60 * 60 * 24));
	iCurrentDate = this.startDate.getTime();
	
	this.arrDays = new Array();
	for(i = 0; i < timeSpanDays; i++) {
		
		currentDate = new Date();
		newCell = newDayTableRow.insertCell(-1);
		newDay = new UI.PlanningEditorDay(newCell);
		currentDate.setTime(iCurrentDate);
		newDay.SetDate(currentDate);
		newDay.OnChanged.Suscribe(this.OnDayChanged, this);
		iCurrentDate += (1000 * 60 * 60 * 24);
		this.arrDays.push(newDay);
		
		// No progression test on first day
		if(i == 0)
			newDay.SetDoTest(false);
	}
	
	// Update the planning
	this.UpdatePlanning();
}

UI.PlanningEditor.prototype.OnDayChanged = function() {
	
	this.UpdatePlanning();
}

UI.PlanningEditor.prototype.UpdatePlanning = function() {
	
	// Declare variables
	var iTotalWeight, i, iRemainingWords, iWords, iRemainingWeight;
	var hDay;
	
	// Get the total weight
	iTotalWeight = 0;
	for(i = 0; i < this.arrDays.length; i++) {
		hDay = this.arrDays[i];
		if(!hDay.bKeepFree)
			iTotalWeight += hDay.iWeight;
	}
	
	// Spread the words according to the day weights
	iRemainingWords = this.wordCount;
	iRemainingWeight = iTotalWeight;
	for(i = 0; i < this.arrDays.length; i++) {
		hDay = this.arrDays[i];
		if(!hDay.bKeepFree && hDay.iWeight > 0) {
			iWords = Math.round((hDay.iWeight / iRemainingWeight) * iRemainingWords);
			iRemainingWords -= iWords;
			iRemainingWeight -= hDay.iWeight;
			hDay.SetNewWordCount(iWords);
		} else {
			hDay.SetNewWordCount(0);
		}
	}
}

UI.PlanningEditor.prototype.IsValid = function(bAlert) {
	
	// Declare variables
	var hDay;
	var bValid = true;
	var bAllDaysFree = true;
	
	// Check if planning is null planning
	if(this.arrDays.length == 0 || this.wordCount == 0) {
		alert(TEXT['PlanningEditorDay.PlanningInvalidNullPlanning']);
		return false;
	}
	
	// Check if not all days are kept free
	for(var i = 0; i < this.arrDays.length; i++) {
		hDay = this.arrDays[i];
		if(hDay.iWeight > 0)
			bAllDaysFree = false;
	}
	if(bAllDaysFree) {
		alert(TEXT['PlanningEditorDay.PlanningInvalidAllDaysFree']);
		return false;
	}
		
	return true;
}

UI.PlanningEditor.prototype.SerializePlanning = function() {
	
	// Declare variables
	var strOutput = "";
	var hDay;
	
	// Iterate trough planning days
	for(var i = 0; i < this.arrDays.length; i++) {
		hDay = this.arrDays[i];
		
		// Serialize day
		if(i != 0)
			strOutput += ",";
		strOutput += hDay.date.getTime() + ",";
		strOutput += hDay.bKeepFree + ",";
		strOutput += hDay.bProgressionTest + ",";
		strOutput += hDay.iWeight;
	}
	
	return strOutput;
}

UI.PlanningEditor.prototype.__type = "UI.PlanningEditor";

UI.PlanningEditor.prototype.startDate = null;
UI.PlanningEditor.prototype.endDate = null;
UI.PlanningEditor.prototype.wordCount = 0;
UI.PlanningEditor.prototype.arrDays = null;

UI.PlanningEditor.prototype.hParentElement = null;
UI.PlanningEditor.prototype.hTitleCell = null;
UI.PlanningEditor.prototype.hContentCell = null;
UI.PlanningEditor.prototype.hContentCellDiv = null;
UI.PlanningEditor.prototype.hDayTable = null;

UI.PlanningEditorDay = function(hParentElement) {
	
	this.Initialize(hParentElement);
}

UI.PlanningEditorDay.prototype.Initialize = function(hParentElement) {
	
	// Declare variables
	var strId;
	
	// Store handle
	this.hParentElement = hParentElement;
	
	this.arrMonths = new Array(TEXT['January'], TEXT['February'], TEXT['March'], TEXT['April'], TEXT['May'], TEXT['June'], TEXT['July'], TEXT['August'], TEXT['September'], TEXT['October'], TEXT['November'], TEXT['December']);
	this.arrDays = new Array(TEXT['Sunday'], TEXT['Monday'], TEXT['Tuesday'], TEXT['Wensday'], TEXT['Thursday'], TEXT['Friday'], TEXT['Saturday']);
	
	// Create the container div
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "containerDiv planningEditorDayDiv";
	this.hParentElement.appendChild(this.hContainerDiv);
	
	// Create the day title
	this.hDayTitleDiv = document.createElement("DIV");
	this.hDayTitleDiv.className = "planningEditorDayTitleDiv";
	this.SetTitle(TEXT['PlanningEditorDay.DefaultTitle'])
	this.hContainerDiv.appendChild(this.hDayTitleDiv);
	
	// Create the learn new words div
	this.hNewWordsDiv = document.createElement("DIV");
	this.hNewWordsDiv.className = "planningEditorDayBlock";
	this.hContainerDiv.appendChild(this.hNewWordsDiv);
	
	// Create the do progression test checkbox
	strId = "MakeProgressionTestCheckbox" + RandomString(16);
	this.hProgressionTestCheckbox = document.createElement("INPUT");
	this.hProgressionTestCheckbox.id = strId;
	this.hProgressionTestCheckbox.type = "checkbox";
	this.hProgressionTestCheckbox.checked = true;
	this.hProgressionTestCheckbox.defaultChecked = true;
	this.hProgressionTestCheckbox.onclick = this.OnProgressionTestBoxClick.Bind(this);
	this.hContainerDiv.appendChild(this.hProgressionTestCheckbox);
	newLabel = document.createElement("LABEL");
	newLabel.htmlFor = strId;
	newLabel.appendChild(document.createTextNode(TEXT['PlanningEditorDay.MakeProgressionTest']));
	this.hContainerDiv.appendChild(newLabel);
	
	newBr = document.createElement("BR");
	this.hContainerDiv.appendChild(newBr);
	
	// Create the keepfree checkbox
	strId = "KeepFreeCheckbox" + RandomString(16);
	this.hKeepFreeCheckbox = document.createElement("INPUT");
	this.hKeepFreeCheckbox.id = strId;
	this.hKeepFreeCheckbox.type = "checkbox";
	this.hKeepFreeCheckbox.onclick = this.OnClick.Bind(this);
	this.hContainerDiv.appendChild(this.hKeepFreeCheckbox);
	newLabel = document.createElement("LABEL");
	newLabel.htmlFor = strId;
	newLabel.appendChild(document.createTextNode(TEXT['PlanningEditorDay.KeepDayFree']));
	this.hContainerDiv.appendChild(newLabel);
	
	newBr = document.createElement("BR");
	this.hContainerDiv.appendChild(newBr);
	
	newBr = document.createElement("BR");
	this.hContainerDiv.appendChild(newBr);
	
	// Create the increase load button
	this.hIncreaseLoadButton = document.createElement("INPUT");
	this.hIncreaseLoadButton.type = "button";
	this.hIncreaseLoadButton.value = TEXT['PlanningEditorDay.IncreaseLoad'];
	this.hIncreaseLoadButton.className = "planningEditorDayButton";
	this.hIncreaseLoadButton.onclick = this.IncreaseWeight.Bind(this);
	this.hContainerDiv.appendChild(this.hIncreaseLoadButton);
	
	// Create the decrease load button
	this.hDecreaseLoadButton = document.createElement("INPUT");
	this.hDecreaseLoadButton.type = "button";
	this.hDecreaseLoadButton.value = TEXT['PlanningEditorDay.DecreaseLoad'];
	this.hDecreaseLoadButton.className = "planningEditorDayButton";
	this.hDecreaseLoadButton.onclick = this.DecreaseWeight.Bind(this);
	this.hContainerDiv.appendChild(this.hDecreaseLoadButton);
	
	this.SetNewWordCount(0);
	
	this.OnChanged = new Delegate();
}

UI.PlanningEditorDay.prototype.SetTitle = function(text) {
	
	while(this.hDayTitleDiv.hasChildNodes())
		this.hDayTitleDiv.removeChild(this.hDayTitleDiv.firstChild);
	
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(text));
	this.hDayTitleDiv.appendChild(newP);
}

UI.PlanningEditorDay.prototype.SetDate = function(date) {
	
	// Declare variables
	var strTitle;
	
	this.date = date;
	
	// Format date
	strTitle = this.arrDays[this.date.getDay()];
	strTitle += " " + this.date.getDate();
	strTitle += " " + this.arrMonths[this.date.getMonth()];
	this.SetTitle(strTitle);
}

UI.PlanningEditorDay.prototype.OnClick = function() {
	
	this.bKeepFree = this.hKeepFreeCheckbox.checked;
	if(this.bKeepFree) {
		this.hProgressionTestCheckbox.disabled = true;
		this.hIncreaseLoadButton.disabled = true;
		this.hDecreaseLoadButton.disabled = true;
	} else {
		this.hProgressionTestCheckbox.disabled = false;
		this.hIncreaseLoadButton.disabled = false;
		this.hDecreaseLoadButton.disabled = false;
	}
	
	// Fire the onchange delegate
	this.OnChanged.Invoke();
}

UI.PlanningEditorDay.prototype.OnProgressionTestBoxClick = function() {
	
	this.SetDoTest(this.hProgressionTestCheckbox.checked);
}

UI.PlanningEditorDay.prototype.SetKeepFree = function(bKeepFree) {
	
	this.bKeepFree = bKeepFree;
	this.hKeepFreeCheckbox.checked = bKeepFree;
	if(this.bKeepFree) {
		this.hProgressionTestCheckbox.disabled = true;
		this.hIncreaseLoadButton.disabled = true;
		this.hDecreaseLoadButton.disabled = true;
	} else {
		this.hProgressionTestCheckbox.disabled = false;
		this.hIncreaseLoadButton.disabled = false;
		this.hDecreaseLoadButton.disabled = false;
	}
	
	// Fire the onchange delegate
	this.OnChanged.Invoke();
}

UI.PlanningEditorDay.prototype.SetDoTest = function(bProgressionTest) {
	
	this.bProgressionTest = bProgressionTest;
	this.hProgressionTestCheckbox.checked = bProgressionTest;
	
	// Fire the onchange delegate
	this.OnChanged.Invoke();
}

UI.PlanningEditorDay.prototype.IncreaseWeight = function() {
	
	// Increase weight
	this.iWeight += 0.5;
	
	// Fire the onchange delegate
	this.OnChanged.Invoke();
}

UI.PlanningEditorDay.prototype.DecreaseWeight = function() {
	
	// Decrease the weight, weight may not be negative
	this.iWeight -= 0.5;
	
	if(this.iWeight < 0)
		this.iWeight = 0;
		
	// Fire the onchange delegate
	this.OnChanged.Invoke();
}

UI.PlanningEditorDay.prototype.SetNewWordCount = function(count) {
	
	this.iNewWords = count;
	
	while(this.hNewWordsDiv.hasChildNodes())
		this.hNewWordsDiv.removeChild(this.hNewWordsDiv.firstChild);
	
	newP = document.createElement("P");
	if(this.iNewWords == 0) {
		newP.appendChild(document.createTextNode(TEXT['PlanningEditorDay.LearnNoNewWords']));
	} else if(this.iNewWords == 0) {
		newP.appendChild(document.createTextNode(TEXT['PlanningEditorDay.Learn1NewWord']));
	} else {
		newP.appendChild(document.createTextNode(TEXT['PlanningEditorDay.LearnXNewWords'].replace("{0}", this.iNewWords)));
	}
	
	this.hNewWordsDiv.appendChild(newP);
}

UI.PlanningEditorDay.prototype.__type = "UI.PlanningEditorDay";

UI.PlanningEditorDay.prototype.iWeight = 1;
UI.PlanningEditorDay.prototype.iNewWords = 0;
UI.PlanningEditorDay.prototype.bProgressionTest = true;
UI.PlanningEditorDay.prototype.bKeepFree = false;
UI.PlanningEditorDay.prototype.date = null;
UI.PlanningEditorDay.prototype.OnChanged = null;
UI.PlanningEditorDay.prototype.arrDays = null;
UI.PlanningEditorDay.prototype.arrMonths = null;

UI.PlanningEditorDay.prototype.hParentElement = null;
UI.PlanningEditorDay.prototype.hContainerDiv = null;
UI.PlanningEditorDay.prototype.hDayTitleDiv = null;
UI.PlanningEditorDay.prototype.hKeepFreeCheckbox = null;
UI.PlanningEditorDay.prototype.hNewWordsDiv = null;
UI.PlanningEditorDay.prototype.hProgressionTestCheckbox = null;
UI.PlanningEditorDay.prototype.hIncreaseLoadButton = null;
UI.PlanningEditorDay.prototype.hDecreaseLoadButton = null;

UI.FormFieldTip = function(text, formField) {
	
	this.hFormField = $(formField);
	if(document.addEventListener) {
		this.hFormField.addEventListener("focus", this.OnFocus, false);
		this.hFormField.addEventListener("blur", this.OnBlur, false);
	} else if(document.attachEvent) {
		// Internet explorer 6 ofcourse doesn't support DOM Level 2 (stupid), so in order to maintain backward compatability, offer event bindings for IE6
		this.hFormField.onfocus = this.OnFocus;
		this.hFormField.onblur = this.OnBlur;
	}
	this.hFormField.formFieldTip = this;
	
	this.hDiv = document.createElement("DIV");
	this.hDiv.className = "formFieldTipDiv";
	document.getElementById("dhtmlEntry").appendChild(this.hDiv);
	this.hDiv.style.display = "none";
	
	this.hP = document.createElement("P")
	this.hP.appendChild(document.createTextNode(text))
	this.hDiv.appendChild(this.hP);
}

UI.FormFieldTip.prototype.OnFocus = function(e) {
	
	var extended = $(this);
	var position = extended.getAbsolutePosition();
	this.formFieldTip.hDiv.style.display = "block";
	this.formFieldTip.hDiv.style.left = (position.x + this.clientWidth + 10) + "px";
	this.formFieldTip.hDiv.style.top = (position.y - 10) + "px";
}

UI.FormFieldTip.prototype.OnBlur = function(e) {
	
	this.formFieldTip.hDiv.style.display = "none";
}


UI.PlanningProgressDiv = function(hParentElement, progress) {
	
	this.Initialize(hParentElement, progress);
}

UI.PlanningProgressDiv.prototype.Initialize = function(hParentElement, progress) {
	
	// Declare variables
	var color = "rgb(";
	
	// Store handle
	this.hParentElement = hParentElement;
	
	this.iProgress = progress || 1;
	
	// Calculate filler color
	if(this.iProgress < 50) {
		color += "255," + Math.round(this.iProgress / 50 * 255) + ",0)"; 
	} else {
		color += Math.round((100 - this.iProgress) / 50 * 255) + ",255,0)";
	}
	
	// Create the main progress bar
	this.hMainProgressBar = document.createElement("DIV");
	this.hMainProgressBar.className = "planningTableProgressDiv";
	this.hParentElement.appendChild(this.hMainProgressBar);
	
	// Fill the progress bar
	this.hProgressBarFiller = document.createElement("DIV");
	this.hProgressBarFiller.className = "planningTableProgressDivFilled";
	this.hProgressBarFiller.style.width = this.iProgress + "px";
	this.hProgressBarFiller.style.backgroundColor = color;
	this.hMainProgressBar.appendChild(this.hProgressBarFiller);
	
	// Create the percentage notation label
	this.hP = document.createElement("P");
	this.hP.appendChild(document.createTextNode(" " + this.iProgress + "%"));
	this.hParentElement.appendChild(this.hP);
}

UI.PlanningProgressDiv.prototype.SetProgress = function(progress) {
	
	// Declare variables
	var color = "rgb(";
	
	this.iProgress = progress;
	
	// Calculate filler color
	if(this.iProgress < 50) {
		color += "255," + Math.round(this.iProgress / 50 * 255) + ",0)"; 
	} else {
		color += Math.round((100 - this.iProgress) / 50 * 255) + ",255,0)";
	}
	
	// Set the progress bar
	this.hProgressBarFiller.style.width = this.iProgress + "px";
	this.hProgressBarFiller.style.backgroundColor = color;
	
	// Set the percentage notation label
	while(this.hP.hasChildNodes())
		this.hP.removeChild(this.hP.firstChild);
	this.hP.appendChild(document.createTextNode(" " + this.iProgress + "%"));
}

UI.PlanningProgressDiv.prototype.Dispose = function() {
	
	this.hParentElement.removeChild(this.hMainProgressBar);
	this.hParentElement.removeChild(this.hP);
}

UI.PlanningProgressDiv.prototype.__type = "";
UI.PlanningProgressDiv.prototype.iProgress = 0;

UI.PlanningProgressDiv.prototype.hParentElement = null;
UI.PlanningProgressDiv.prototype.hMainProgressBar = null;
UI.PlanningProgressDiv.prototype.hProgressBarFiller = null;
UI.PlanningProgressDiv.prototype.hP = null;



UI.DatePicker = function(hParentNode) {
	this.Initialize(hParentNode);
}

UI.DatePicker.prototype.Initialize = function(hParentNode) {
	
	// Parent node
	this.hParentNode = hParentNode;
	
	// Create the container node
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "datePickerContainer";
	this.hParentNode.appendChild(this.hContainerDiv);

	// System date
	this.SystemDate = new Date();
	this.DatePickerDate = new Date();
	
	// Load datePicker month and year from the current system date
	this.Year = this.SystemDate.getFullYear();
	this.Month = this.SystemDate.getMonth();
	
	// Array containing all the day button handles
	this.dayButtonHandles = new Array();
	
	// A handle to the titlebar text
	this.hTitleBarText = null;
	
	// Data
	this.strMonths = new Array(TEXT['January'], TEXT['February'], TEXT['March'], TEXT['April'], TEXT['May'], TEXT['June'], TEXT['July'], TEXT['August'], TEXT['September'], TEXT['October'], TEXT['November'], TEXT['December']);
	this.MonthDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	this.strDays = new Array(TEXT['Sunday'], TEXT['Monday'], TEXT['Tuesday'], TEXT['Wensday'], TEXT['Thursday'], TEXT['Friday'], TEXT['Saturday']);
	
	// Create the datepicker
	this.CreateDatePicker();
	this.RefreshTitleBar();
}

UI.DatePicker.prototype.NextMonth = function() {

	// Move one month foward
	if(this.Month == 11) {
		this.Month = 0;
		this.Year++;
	} else {
		this.Month++;
	}
	
	// Update the datePicker date object
	this.DatePickerDate.setMonth(this.Month);
	this.DatePickerDate.setYear(this.Year);
	this.CheckForLeapYear();
	
	// Refresh the titlebar
	this.RefreshTitleBar();
	this.PopulateDayButtons();
}

UI.DatePicker.prototype.PrevMonth = function() {

	// Move one month backward
	if(this.Month == 0) {
		this.Month = 11;
		this.Year--;
	} else {
		this.Month--;
	}
	
	// Update the datePicker date object
	this.DatePickerDate.setMonth(this.Month);
	this.DatePickerDate.setYear(this.Year);
	this.CheckForLeapYear();
	
	// Refresh the titlebar
	this.RefreshTitleBar();
	this.PopulateDayButtons();
}

UI.DatePicker.prototype.NextYear = function() {

	// Move one year foward
	this.Year++;
	
	// Update the datePicker date object
	this.DatePickerDate.setYear(this.Year);
	this.CheckForLeapYear();
	
	// Refresh the titlebar
	this.RefreshTitleBar();
	this.PopulateDayButtons();
}

UI.DatePicker.prototype.PrevYear = function() {

	// Move one year backward
	this.Year--;
	
	// Update the datePicker date object
	this.DatePickerDate.setYear(this.Year);
	this.CheckForLeapYear();
	
	// Refresh the titlebar
	this.RefreshTitleBar();
	this.PopulateDayButtons();
}

UI.DatePicker.prototype.CreateLabel = function(strText) {
	
	// Declare variables
	var newDiv, newP
	
	// Create the label div
	newDiv = document.createElement("DIV");
	newDiv.className = "datePickerLabelDiv";
	
	// Insert the text
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(strText));
	newDiv.appendChild(newP);
	
	return newDiv;
}

UI.DatePicker.prototype.CreateDayButton = function(strText, strToolTip) {
	
	// Declare variables
	var newDiv, newP;
	
	// Create the button div
	newDiv = document.createElement("DIV");
	newDiv.className = "datePickerDayButtonDiv";
	newDiv.onmouseover = this.DayButtonMouseOver;
	newDiv.onmouseout = this.DayButtonMouseOut;
	newDiv.onclick = this.OnDayButtonClick.Bind(this, newDiv);
	newDiv.title = strToolTip;
	newDiv.toggled = false;
	
	// Insert the text
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(strText));
	newDiv.appendChild(newP);
	
	return newDiv;
}

UI.DatePicker.prototype.DayButtonMouseOver = function() {

	// Set the hover style
	if(this.active == true && !this.toggled) {
		this.className = "datePickerDayButtonDivHover";
	}
}

UI.DatePicker.prototype.DayButtonMouseOut = function() {

	// Set the non-hover style
	if(this.active == true && !this.toggled) {
		this.className = "datePickerDayButtonDiv";
	}
}

UI.DatePicker.prototype.OnDayButtonClick = function(hButton) {
	
	// Update the datepicker's date
	this.DatePickerDate.setDate(hButton.iDay);
	
	// Untoggle previous toggled button
	if(this.hToggledButton !== null) {
		this.hToggledButton.bChecked = false;
		this.hToggledButton.Invalidate();
	}
	
	// Toggle the clicked button
	if(!hButton.bChecked) {
		hButton.bChecked = true;
		hButton.Invalidate();
		this.hToggledButton = hButton;
	} else {
		hButton.bChecked = false;
		hButton.Invalidate();
		this.hToggledButton = null;
	}
}

UI.DatePicker.prototype.CreateTitleBar = function() {

	// Declare variables
	var newDiv, newP;
	
	// Create previous month button
	newDiv = this.CreateDayButton("«", TEXT['DatePicker.PreviousMonth']);
	newDiv.action = "prevMonth";
	newDiv.datePicker = this;
	newDiv.active = true;
	newDiv.onclick = this.TitleBarButtonClick.Bind(this, "prevMonth");
	this.hContainerDiv.appendChild(newDiv);
	
	// Create the titlebar itself
	newDiv = document.createElement("DIV");
	newDiv.className = "datePickerTitleBar";
	
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(" "));
	newDiv.appendChild(newP);
	this.hContainerDiv.appendChild(newDiv);
	
	// Store handle to the titlebar text
	this.hTitleBarText = newP;
	
	// Create next month button
	newDiv = this.CreateDayButton("»", TEXT['DatePicker.NextMonth']);
	newDiv.action = "nextMonth";
	newDiv.datePicker = this;
	newDiv.active = true;
	newDiv.onclick = this.TitleBarButtonClick.Bind(this, "nextMonth");
	this.hContainerDiv.appendChild(newDiv);
}

UI.DatePicker.prototype.TitleBarButtonClick = function(action) {
	
	// Determine the action to be taken
	switch(action) {
		case "prevMonth":
			
			// Move one month backward
			this.PrevMonth();
			break;
		case "nextMonth":
		
			// Move one month foward
			this.NextMonth();
			break;
	}
}

UI.DatePicker.prototype.RefreshTitleBar = function() {

	// Declare variables
	var strText;
	
	// Create the date string
	strText = this.GetDateMonth();
	strText += " ";
	strText += this.DatePickerDate.getFullYear();
	
	// Set the titlebar text to the current month and year
	this.hTitleBarText.replaceChild(document.createTextNode(strText), this.hTitleBarText.firstChild);
}

UI.DatePicker.prototype.GetDateMonth = function() {

	// Return the current month
	return this.strMonths[this.DatePickerDate.getMonth()];
}

UI.DatePicker.prototype.CheckForLeapYear = function() {

	// Check for leap year
	if((this.Year / 4) == Math.round(this.Year / 4)) {
	
		// Current year is a leap year --> february has 29 days
		this.MonthDays[1] = 29;
	} else {
	
		// Current year is not a leap year --> february has 28 days
		this.MonthDays[1] = 28;
	}
}

UI.DatePicker.prototype.PopulateDayButtons = function() {

	// Declare variables
	var FuncDate = new Date();
	var hButton;
	var iWeeks = 0;
	var iDay;
	var x, d;
	
	// Set the function date object
	FuncDate.setMonth(this.Month);
	FuncDate.setYear(this.Year);
	
	this.hToggledButton = null;
	
	// Clear all day buttons
	for(x = 0; x < this.dayButtonHandles.length; x++) {
		
		hButton = this.dayButtonHandles[x];
		hButton.bVisible = false;
		hButton.bEnabled = false;
		hButton.bChecked = false;
		hButton.Invalidate();
	}
	
	// Iterate trough days
	for(d = 1; d <= this.MonthDays[this.Month]; d++) {
	
		// Set the day of the month and retrieve the day of the week
		FuncDate.setDate(d);
		iDay = FuncDate.getDay()
		
		// Get a handle to the corresponding day button
		hButton = this.dayButtonHandles[(iWeeks * 7) + (iDay)];
		
		// Set the day button text
		hButton.SetText(FuncDate.getDate());
		hButton.bEnabled = true;
		
		// If button date is before today, disable the button
		if(this.Year < this.SystemDate.getFullYear()) {
			hButton.bEnabled = false;
		} else if(this.Year == this.SystemDate.getFullYear()) {
			if(this.Month < this.SystemDate.getMonth()) {
				hButton.bEnabled = false;
			} else if(this.Month == this.SystemDate.getMonth()) {
				if(d < this.SystemDate.getDate()) {
					hButton.bEnabled = false;
				}
			}
		}
		
		// Check if date is selected date --> check button
		if(this.Year == this.DatePickerDate.getFullYear() && this.Month == this.DatePickerDate.getMonth() && d == this.DatePickerDate.getDate()) {
			hButton.bChecked = true;
			this.hToggledButton = hButton;
		}
		
		hButton.bVisible = true;
		hButton.strToolTip = this.strDays[iDay] + " " + FuncDate.getDate() + " " + this.strMonths[FuncDate.getMonth()] + " " + FuncDate.getFullYear();
		hButton.iDay = d;
		hButton.Invalidate();
		
		// If this is the last day of the week, increment week counter
		if(iDay == 6)
			iWeeks++;
	}
}

UI.DatePicker.prototype.CreateDatePicker = function() {

	// Declare variables
	var strText;
	var newDiv, newP, newButton;
	
	// Create the titlebar and buttons
	this.CreateTitleBar();
	
	// Create the day labels
	for(d = 0; d < 7; d++) {
		
		// Translate label text
		strText = this.strDays[d].substr(0, 2);
		
		// Create the label
		newDiv = this.CreateLabel(strText);
		
		// Add the label to the parent node
		this.hContainerDiv.appendChild(newDiv);
	}
	
	// Create all the day buttons (7x5 matrix)
	for(b = 1; b < 43; b++) {
	
		// Create the button
		newButton = new UI.DatePickerDayButton();
		newButton.OnClick.Suscribe(this.OnDayButtonClick, this);
		
		// Add the label to the parent node and store it in the [dayButtonHandles] array
		this.hContainerDiv.appendChild(newButton.hDiv);
		this.dayButtonHandles.push(newButton);
	}
	
	// Populate the daybuttons
	this.PopulateDayButtons();
}

UI.DatePicker.prototype.ToMysqlDate = function() {
	return this.DatePickerDate.getFullYear() + "-" + this.DatePickerDate.getMonth() + "-" + this.DatePickerDate.getDate();
}

UI.DatePicker.prototype.__type = "UI.DatePicker";

UI.DatePicker.prototype.DatePickerDate = null;

UI.DatePicker.prototype.hParentNode = null;
UI.DatePicker.prototype.hContainerDiv = null;
UI.DatePicker.prototype.hToggledButton = null;

UI.DatePickerDayButton = function() {
	this.Initialize();
	
}

UI.DatePickerDayButton.prototype.Initialize = function() {
	
	this.OnClick = new Delegate();
	this.OnMouseOver = new Delegate();
	this.OnMouseOut = new Delegate();
	
	this.hDiv = document.createElement("DIV");
	this.hDiv.className = "datePickerDayButtonDiv";
	
	// Bind event handlers
	this.hDiv.onmouseover = this._OnMouseOver.BindEvent(this);
	this.hDiv.onmouseout = this._OnMouseOut.BindEvent(this);
	this.hDiv.onclick = this._OnClick.BindEvent(this);
}

UI.DatePickerDayButton.prototype._OnMouseOver = function(e) {
	
	if(this.bEnabled && this.bVisible && !this.bChecked) {
		this.hDiv.className = "datePickerDayButtonDivHover";
		this.OnMouseOver.Invoke(this);
	}
}

UI.DatePickerDayButton.prototype._OnMouseOut = function(e) {
	
	if(this.bEnabled && this.bVisible) {
		if(!this.bChecked)
			this.hDiv.className = "datePickerDayButtonDiv";
		this.OnMouseOut.Invoke(this);
	}	
}

UI.DatePickerDayButton.prototype._OnClick = function(e) {
	
	if(this.bEnabled && this.bVisible)
		this.OnClick.Invoke(this);
}

UI.DatePickerDayButton.prototype.SetText = function(text) {
	
	var newP;
	
	// Clear the div
	while(this.hDiv.hasChildNodes())
		this.hDiv.removeChild(this.hDiv.firstChild);
		
	// Insert the text
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(text));
	this.hDiv.appendChild(newP);
	
	// Store
	this.strText = text;
}

UI.DatePickerDayButton.prototype.Invalidate = function() {
	
	if(!this.bVisible) {
		this.hDiv.style.visibility = "hidden";
	} else {
		this.hDiv.style.visibility = "visible";
	}
	if(!this.bEnabled) {
		this.hDiv.className = "datePickerDayButtonDivDisabled";
	} else {
		if(this.bChecked) {
			this.hDiv.className = "datePickerDayButtonDivToggled";
		} else {
			this.hDiv.className = "datePickerDayButtonDiv";
		}
	}
	
	if(this.strToolTip !== null)
		this.hDiv.title = this.strToolTip;
}

UI.DatePickerDayButton.prototype.hDiv = null;
UI.DatePickerDayButton.prototype.bVisible = true;
UI.DatePickerDayButton.prototype.bEnabled = true;
UI.DatePickerDayButton.prototype.bChecked = false;
UI.DatePickerDayButton.prototype.hDataPicker = null;
UI.DatePickerDayButton.prototype.strText = null;
UI.DatePickerDayButton.prototype.strToolTip = null;
UI.DatePickerDayButton.prototype.iDay = null;
UI.DatePickerDayButton.prototype.OnClick = null;
UI.DatePickerDayButton.prototype.OnMouseOver = null;
UI.DatePickerDayButton.prototype.OnMouseOut = null;

UI.ColorPicker = function(hParentElement) {
	this.Initialize(hParentElement);
}
	
UI.ColorPicker.prototype.Initialize = function(hParentElement) {
	
	// Declare variables
	
	this.hParentElement = hParentElement;
	
	// Create the container div
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "containerDiv colorPickerContainer";
	this.hParentElement.appendChild(this.hContainerDiv);
	
	// Create bitmap
	this.hBitmap = document.createElement("DIV");
	this.hBitmap.className = "colorPickerBitmap";
	this.hBitmap.onmousedown = this.OnMouseDown.Bind(this);
	this.hBitmap.onmouseup = this.OnMouseUp.Bind(this);
	this.hBitmap.onmousemove = this.OnMouseMove.Bind(this);
	this.hBitmap.onmouseenter = this.OnMouseDown.Bind(this);
	this.hBitmap.onmouseleave = this.OnMouseDown.Bind(this);
	this.hContainerDiv.appendChild(this.hBitmap);
	
	// Create the cursor
	this.hCursor = document.createElement("DIV");
	this.hCursor.className = "colorPickerCursor";
	this.hBitmap.appendChild(this.hCursor);
	
	// Create the sample div
	this.hSampleDiv = document.createElement("DIV");
	this.hSampleDiv.className = "colorPickerSampleDiv";
	this.hContainerDiv.appendChild(this.hSampleDiv);
}

UI.ColorPicker.prototype.OnMouseDown = function(e) {
	this.bDragging = true;
}

UI.ColorPicker.prototype.OnMouseUp = function(e) {
	this.bDragging = false;
}

UI.ColorPicker.prototype.OnMouseMove = function(e) {
	
	// Declare variables
	var x, y;
	var extended;
	var pos;
	
	if(this.bDragging) {
		if(e === undefined) var e = window.event;
		
		extended = $(this.hBitmap);
		pos = extended.getAbsolutePosition();
		x = e.clientX - pos.x;
		y = e.clientY - pos.y;
		
		this.hCursor.style.left = x + window.scrollX + "px";
		this.hCursor.style.top = y + window.scrollY + "px";
	}
}

UI.ColorPicker.prototype.__type = "UI.ColorPicker";
UI.ColorPicker.prototype.bDragging = false;

UI.ColorPicker.prototype.hParentElement = null;
UI.ColorPicker.prototype.hContainerDiv = null;
UI.ColorPicker.prototype.hCursor = null;
UI.ColorPicker.prototype.hBitmap = null;
UI.ColorPicker.prototype.hSampleDiv = null;

/**
 * 
 * @param {Object} hParentElement
 * @param {Object} title
 * @param {Object} width
 * @param {Object} height
 */
UI.Dialog = function UI$Dialog(hParentElement, title, width, height) {
	this.Initialize(hParentElement, title, width, height);
}

UI.Dialog.prototype.Initialize = function UI$Dialog$Initialize(hParentElement, title, width, height) {
	
	// Import
	title = title || "";
	this.iWidth = width || 400;
	this.iHeight = height || 400;
	
	// Store handle
	this.hParentElement = hParentElement;
	
	this.OnClose = new Delegate();
	
	// Declare variables
	var left, top;
	var newP;
	var element;
	
	// Create container
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "commongDialogContainer";
	this.hContainerDiv.style.width = this.iWidth + "px";
	this.hParentElement.appendChild(this.hContainerDiv);
	
	// Create loading message
	newP = document.createElement("P");
	newP.className = "center";
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createTextNode(TEXT['Dialog.Loading']));
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createElement("BR"));
	newP.appendChild(document.createElement("BR"));
	this.hContainerDiv.appendChild(newP);
	
	// Center the dialog
	this.OnResize_OnScroll();
	
}

UI.Dialog.prototype.OnResize_OnScroll = function UI$Dialog$OnResize_OnScroll() {
	
	// Delcare variables
	var iScrollLeft, iScrollTop, iWidth, iHeight, iLeft, iTop;
	
	// Get the scroll offset
	if(self.pageYOffset) {
		iScrollLeft = self.pageXOffset;
		iScrollTop = self.pageYOffset;
	} else if(document.documentElement && document.documentElement.scrollTop) {
		iScrollLeft = document.documentElement.scrollLeft;
		iScrollTop = document.documentElement.scrollTop;
	} else if(document.body) {
		iScrollLeft = document.body.scrollLeft;
		iScrollTop = document.body.scrollTop;
	}
	
	// Update dialog size
	//this.iWidth = this.hContainerDiv.clientWidth;
	//this.iHeight = this.hContainerDiv.clientHeight;
	
	// Get the page size
	iWidth = document.documentElement.clientWidth || document.body.clientWidth;
	iHeight = document.documentElement.clientHeight || document.body.clientHeight;
	
	// Calc container div position
	iLeft = Math.round((iWidth - this.iWidth) / 2 + iScrollLeft);
	iTop = Math.round((iHeight - this.iHeight) / 2 + iScrollTop);
	
	if(iTop < 0)
		iTop = 0;
	
	this.hContainerDiv.style.left = iLeft + "px";
	this.hContainerDiv.style.top = iTop + "px";
}

UI.Dialog.prototype.Close = function UI$Dialog$Close() {
	
	this.hParentElement.removeChild(this.hContainerDiv);
	this.OnClose.Invoke();
}

UI.Dialog.prototype.LoadContents = function UI$Dialog$LoadContents(url) {
	
	this.strUrl = url;
	this.WebRequest = new Net.Request(url, "GET", null, true);
	this.WebRequest.OnComplete.Suscribe(this.OnLoadContentsComplete, this);
	this.WebRequest.MakeRequest();
}

UI.Dialog.prototype.OnLoadContentsComplete = function UI$Dialog$OnLoadContentsComplete() {
	
	// Declare variables
	var hResponseNode;
	var strHtml = null, strScript = null;
	var _this;
	
	// Parse response
	if(this.WebRequest.ExtendedResult) {
		for(var x = 0; x < this.WebRequest.ExtendedResult.childNodes.length; x++) {
			
			hResponseNode = this.WebRequest.ExtendedResult.childNodes[x];
			switch(hResponseNode.nodeName) {
				case "html":
					if(hResponseNode.hasChildNodes()) {
						strHtml = hResponseNode.firstChild.nodeValue
					}
					break;
				case "script":
					if(hResponseNode.hasChildNodes()) {
						this.strScript = hResponseNode.firstChild.nodeValue
					}
					break;
			}
		}
		
		if(strHtml !== null) {
			
			// Clear the container div
			while(this.hContainerDiv.hasChildNodes())
				this.hContainerDiv.removeChild(this.hContainerDiv.firstChild);
			
			// Create container
			if(this.hContentDiv)
				this.hContainerDiv.removeChild(this.hContentDiv);
			this.hContentDiv = document.createElement("DIV");
			this.hContentDiv.id = "dialogContentDiv";
			
			element = new YAHOO.util.Element("dialogContentDiv");
			element.addListener("contentReady", this._OnDialogContentReady, null, this);
			
			// Set the dialog html
			this.hContentDiv.innerHTML = strHtml;
			this.hContainerDiv.appendChild(this.hContentDiv);
			
			/*
			// Evaluate the passed script if appropriate
			// Make sure the script is executed in global scope (window.execScript in IE,
			// window.eval in FF). If not possible, just use eval.
			if(strScript !== null) {
				try {
					if(window.execScript) {
						window.execScript(strScript);
					} else {
						window.eval ? window.eval(strScript) : eval(strScript);
					}
				} catch(error) {
					throw new Error("An error curred while attempting to evaluate the dialog script.\n\nError message: " + error.message + "\n\nJavascript being evaluated: " + strScript);
				}
			}
			*/
			
		}
	} else {
		
		// Extended result is invalid, throw error
		dialogError = new UI.DialogError(this.WebRequest.hXMLHttpRequest.responseText, this.strUrl);
		core.ShowErrorDialog(dialogError);
	}
}

UI.Dialog.prototype._OnDialogContentReady = function UI$Dialog$_OnDialogContentReady() {
	
	if(this.strScript !== null) {
				
		// Thanks to http://dean.edwards.name/weblog/2006/11/sandbox/
		// Check whether window.eval executes code in the global scope.
		window.eval("var __INCLUDE_TEST_1__ = true;");
		if (typeof window.__INCLUDE_TEST_1__ != "undefined") {
			delete window.__INCLUDE_TEST_1__;
			window.eval(this.strScript);
		} else if (typeof window.execScript != "undefined")	{// IE only
			window.execScript(this.strScript);
		} else {
			
			// Test effectiveness of creating a new SCRIPT element and adding it to the document.
			this._insertScriptTag = function (_jsCode) {
				var _script = document.createElement("script");
				_script.type = "text/javascript";
				_script.defer = false;
				_script.text = _jsCode;
				var _headNodeSet = document.getElementsByTagName("head");
				if (_headNodeSet.length) {
					_script = _headNodeSet.item(0).appendChild(_script);
				} else {
					var _head = document.createElement("head");
					_head = document.documentElement.appendChild(_head);
					_script = _head.appendChild(_script);
				}
				return _script;
			}
			
			var _testScript = this._insertScriptTag("var __INCLUDE_TEST_2__ = true;");
			
			if (typeof window.__INCLUDE_TEST_2__ == "boolean") {
				_testScript.parentNode.removeChild(_testScript);
				this._insertScriptTag(this.strScript);
			} else {
			
				// Check whether window.setTimeout works in real time.
				window.setTimeout("var __INCLUDE_TEST_3__ = true;", 0);
				if (typeof window.__INCLUDE_TEST_3__ != "undefined") {
					delete window.__INCLUDE_TEST_3__;
					window.setTimeout(this.strScript, 0);
				}
			}
		}
		
		this.strScript = null;
	}
}

UI.Dialog.prototype.__type = "UI.Dialog";

UI.Dialog.prototype.iWidth;
UI.Dialog.prototype.iHeight;
UI.Dialog.prototype.OnClose = null;

UI.Dialog.prototype.WebRequest = null;
UI.Dialog.prototype.strUrl = null;
UI.Dialog.prototype.strScript = null;

UI.Dialog.prototype.hParentElement = null;
UI.Dialog.prototype.hContainerDiv = null;
UI.Dialog.prototype.hContentDiv = null;

UI.DialogError = function(strRawResponse, strUrl) {
	this.message = strRawResponse;
	this.fileName = strUrl;
}
UI.DialogError.prototype.name = "UI.DialogError";
UI.DialogError.prototype.message = "";
UI.DialogError.prototype.fileName = "";


/**
 * 
 * @param {Object} hParentElement
 * @param {Object} title
 * @param {Object} width
 * @param {Object} height
 */
UI.ErrorDialog = function(hParentElement, error) {
	this.Initialize(hParentElement, error);
}

UI.ErrorDialog.prototype.Initialize = function(hParentElement, error) {
	
	// Import
	this.iWidth = 700;
	this.iHeight = 400;
	this.oError = error;
	
	// Store handle
	this.hParentElement = hParentElement;
	
	this.OnClose = new Delegate();
	
	// Declare variables
	var left, top;
	var newP, newDiv, newTable, newRow, newCell;
	
	// Create container
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "commongDialogContainer";
	this.hContainerDiv.style.width = this.iWidth + "px";
	this.hParentElement.appendChild(this.hContainerDiv);
	
	// Create titlebar
	this.hTitleBarDiv = document.createElement("div");
	this.hTitleBarDiv.className = "commonErrorDialogTitle";
	this.hContainerDiv.appendChild(this.hTitleBarDiv);
	
	newDiv = document.createElement("div");
	newDiv.className = "commonDialogCloseButton";
	newDiv.onclick = this.Close.BindEvent(this);
	this.hTitleBarDiv.appendChild(newDiv);
		
	newP = document.createElement("p");
	newP.appendChild(document.createTextNode(TEXT['ErrorDialog']));
	this.hTitleBarDiv.appendChild(newP);
	
	// Create Ccontent
	this.hContentDiv = document.createElement("div");
	this.hContentDiv.className = "commonDialogContent"
	this.hContainerDiv.appendChild(this.hContentDiv);
	
	// Create primary notice
	newP = document.createElement("p");
	newP.appendChild(document.createTextNode(TEXT['ErrorDialog.Notice1']));
	this.hContentDiv.appendChild(newP);
	this.hContentDiv.appendChild(document.createElement("br"));
	
	newP = document.createElement("p");
	newP.appendChild(document.createTextNode(TEXT['ErrorDialog.Information']));
	this.hContentDiv.appendChild(newP);
	
	// Error information
	newTable = document.createElement("table");
	newTable.cellPadding = 0;
	newTable.cellSpacing = 0;
	this.hContentDiv.appendChild(newTable);
	
	if(this.oError.name) {
		newRow = newTable.insertRow(-1);
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newStrong = document.createElement("strong");
		newStrong.appendChild(document.createTextNode(TEXT['ErrorDialog.ErrorName']));
		newP.appendChild(newStrong);
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newP.appendChild(document.createTextNode(this.oError.name));
		newCell.appendChild(newP);
	}
	
	if(this.oError.message) {
		
		// Truncate
		if(this.oError.message.length > 256) {
			strMessage = this.oError.message.substring(0, 256) + " ... [More]";
		} else {
			strMessage = this.oError.message;
		}

		newRow = newTable.insertRow(-1);
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newStrong = document.createElement("strong");
		newStrong.appendChild(document.createTextNode(TEXT['ErrorDialog.ErrorMessage']));
		newP.appendChild(newStrong);
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newP.appendChild(document.createTextNode(strMessage));
		newCell.appendChild(newP);
	}
	
	if(this.oError.fileName) {
		newRow = newTable.insertRow(-1);
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newStrong = document.createElement("strong");
		newStrong.appendChild(document.createTextNode(TEXT['ErrorDialog.FileName']));
		newP.appendChild(newStrong);
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newP.appendChild(document.createTextNode(this.oError.fileName));
		newCell.appendChild(newP);
	}
	
	if(this.oError.lineNumber) {
		newRow = newTable.insertRow(-1);
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newStrong = document.createElement("strong");
		newStrong.appendChild(document.createTextNode(TEXT['ErrorDialog.LineNumber']));
		newP.appendChild(newStrong);
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		newP.appendChild(document.createTextNode(this.oError.lineNumber));
		newCell.appendChild(newP);
	}
	
	if(this.oError.stack) {
		newRow = newTable.insertRow(-1);
		newCell = newRow.insertCell(-1);
		newCell.vAlign = "top";
		newP = document.createElement("p");
		newStrong = document.createElement("strong");
		newStrong.appendChild(document.createTextNode(TEXT['ErrorDialog.StackTrace']));
		newP.appendChild(newStrong);
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		this.FormatStack(this.oError.stack, newP);
		newCell.appendChild(newP);
	}
	
	if(this.oError._stackTrace) {
		newRow = newTable.insertRow(-1);
		newCell = newRow.insertCell(-1);
		newCell.vAlign = "top";
		newP = document.createElement("p");
		newStrong = document.createElement("strong");
		newStrong.appendChild(document.createTextNode("JS Generated stack trace"));
		newP.appendChild(newStrong);
		newCell.appendChild(newP);
		
		newCell = newRow.insertCell(-1);
		newP = document.createElement("p");
		this.FormatStack(this.oError._stackTrace, newP);
		newCell.appendChild(newP);
	}
	
	try {
		if(window.location) {
			newRow = newTable.insertRow(-1);
			newCell = newRow.insertCell(-1);
			newCell.vAlign = "top";
			newP = document.createElement("p");
			newStrong = document.createElement("strong");
			newStrong.appendChild(document.createTextNode(TEXT['ErrorDialog.Page']));
			newP.appendChild(newStrong);
			newCell.appendChild(newP);
			
			newCell = newRow.insertCell(-1);
			newP = document.createElement("p");
			newP.appendChild(document.createTextNode(window.location));
			newCell.appendChild(newP);
		}
	} catch(ex) {};
	
	// Create footer
	newDiv = document.createElement("div");
	newDiv.className = "commonErrorDialogFooter";
	this.hContainerDiv.appendChild(newDiv);
	
	// Submit bugreport button
	newInput = document.createElement("input");
	newInput.type = "button";
	newInput.value = TEXT['ErrorDialog.BugreportButton'];
	newInput.className = "mediumButton";
	newInput.onclick = this.SubmitBugreport.BindEvent(this);
	newDiv.appendChild(newInput);
	
	// Ignore error button
	newInput = document.createElement("input");
	newInput.type = "button";
	newInput.value = TEXT['ErrorDialog.IgnoreButton'];
	newInput.className = "smallButton";
	newInput.onclick = this.Close.BindEvent(this);
	newDiv.appendChild(newInput);
		
	// Center the dialog
	this.OnResize_OnScroll();
	newInput.focus();
}

UI.ErrorDialog.prototype.FormatStack = function(stack, pElement) {
	
	// Declare variables
	var arrLines, strLine, newBr;
	
	// Split stack
	arrLines = stack.split("\n");
	for(var x = 0; x < arrLines.length; x++) {
		strLine = arrLines[x].trim();
		
		// Insert line break
		if(x > 0) {
			newBr = document.createElement("br");
			pElement.appendChild(newBr);
		}
		pElement.appendChild(document.createTextNode(strLine));
	}
}

UI.ErrorDialog.prototype.OnResize_OnScroll = function() {
	
	// Delcare variables
	var iScrollLeft, iScrollTop, iWidth, iHeight, iLeft, iTop;
	
	// Get the scroll offset
	if(self.pageYOffset) {
		iScrollLeft = self.pageXOffset;
		iScrollTop = self.pageYOffset;
	} else if(document.documentElement && document.documentElement.scrollTop) {
		iScrollLeft = document.documentElement.scrollLeft;
		iScrollTop = document.documentElement.scrollTop;
	} else if(document.body) {
		iScrollLeft = document.body.scrollLeft;
		iScrollTop = document.body.scrollTop;
	}
	
	// Get the page size
	iWidth = document.documentElement.clientWidth || document.body.clientWidth;
	iHeight = document.documentElement.clientHeight || document.body.clientHeight;
	
	// Calc container div position
	iLeft = Math.round((iWidth - this.iWidth) / 2 + iScrollLeft);
	iTop = Math.round((iHeight - this.iHeight) / 2 + iScrollTop);
	
	if(iTop < 0)
		iTop = 0;
	
	this.hContainerDiv.style.left = iLeft + "px";
	this.hContainerDiv.style.top = iTop + "px";
}

UI.ErrorDialog.prototype.Close = function() {
	
	this.hParentElement.removeChild(this.hContainerDiv);
	this.OnClose.Invoke();
}

UI.ErrorDialog.prototype.SubmitBugreport = function() {
	
	// Declare variables
	var newForm, newInput;
	
	// Create form
	newForm = document.createElement("form");
	newForm.action = "index.php?page=bugreport&sub=jsbugreport";
	newForm.method = "post";
	newForm.target = "_blank";
	this.hContainerDiv.appendChild(newForm);
	
	// Create input
	newInput = document.createElement("input");
	newInput.type = "hidden";
	newInput.name = "errorData";
	newInput.value = this.GetTechnicalData();
	newForm.appendChild(newInput);
	
	// Submit the form
	newForm.submit();
}

UI.ErrorDialog.prototype.GetTechnicalData = function() {
	
	// Delcare variables
	var strErrorData;
	
	// Format error data
	strErrorData = "Error Data:\n";
	if(this.oError.fileName)
		strErrorData += "File Name: " + this.oError.fileName + "\n";
	if(this.oError.lineNumber)
		strErrorData += "Line Number: " + this.oError.lineNumber + "\n";
	if(this.oError.message)
		strErrorData += "Message: " + this.oError.message + "\n";
	if(this.oError.name)
		strErrorData += "Error Name: " + this.oError.name + "\n";
	if(this.oError.stack)
		strErrorData += "Native stack trace: " + this.oError.stack + "\n";
	if(this.oError._stackTrace)
		strErrorData += "JS stack trace: " + this.oError._stackTrace + "\n";
	try {
		if(window.location)
			strErrorData += "URL: " + window.location + "\n";	
	} catch(ex) {};
		
	// Format browser data
	strErrorData += "\nBrowser Data:\n";
	if(window.navigator)
		strErrorData += this.FormatArray(window.navigator);
	
	return strErrorData;
}

UI.ErrorDialog.prototype.FormatArray = function(array) {
	
	// Delcare variables
	var key, value;
	var strData = "";
	
	for(key in array) {
		value = array[key];
		if(typeof(value) != "function") {
			strData += key + ": " + value + "\n";
		}
	}
	
	return strData;
}

UI.ErrorDialog.prototype.__type = "UI.ErrorDialog";

UI.ErrorDialog.prototype.iWidth;
UI.ErrorDialog.prototype.iHeight;
UI.ErrorDialog.prototype.oError;
UI.ErrorDialog.prototype.OnClose = null;

UI.ErrorDialog.prototype.hParentElement = null;
UI.ErrorDialog.prototype.hContainerDiv = null;
UI.ErrorDialog.prototype.hTitleBarDiv = null;
UI.ErrorDialog.prototype.hContentDiv = null;


UI.LanguagePicker = function(hParentElement, strCurrentLanguage) {
	this.Initialize(hParentElement, strCurrentLanguage);
}
	
UI.LanguagePicker.prototype.Initialize = function(hParentElement, strCurrentLanguage) {
	
	// Declare variables
	var newDiv, newImg, newP;
	var hLanguage;

	this.hParentElement = hParentElement;
	
	// Solve current language
	this.oCurrentLanguage = Localization.LanguageMap[strCurrentLanguage.toLowerCase()];
	if(!this.oCurrentLanguage)
		 this.oCurrentLanguage = Localization.Languages.English;
	
	// Create container
	this.hContainerDiv = document.createElement("DIV");
	this.hContainerDiv.className = "languagePickerFlag";
	this.hContainerDiv.style.backgroundImage = "url('images/" + this.oCurrentLanguage.flag + "')";
	this.hContainerDiv.onmouseover = this.ContainerOnMouseOver.BindEvent(this);
	this.hContainerDiv.onmouseout = this.ContainerOnMouseOut.BindEvent(this);
	this.hContainerDiv.onclick = this.ContainerOnClick.BindEvent(this);
	this.hParentElement.appendChild(this.hContainerDiv);
	
	// Create popup
	this.hPopupDiv = document.createElement("DIV");
	this.hPopupDiv.className = "popupDiv";
	this.hPopupDiv.style.width = "150px";
	this.hPopupDiv.style.display = "none";
	document.getElementById("dhtmlEntry").appendChild(this.hPopupDiv);
	
	// Populate popup
	for(var i in Localization.Languages) {
		hLanguage = Localization.Languages[i];
		
		newDiv = document.createElement("DIV");
		newDiv.className = "languagePickerOption";
		newDiv.onmouseover = this.OptionOnMouseOver.BindEvent(this, newDiv);
		newDiv.onmouseout = this.OptionOnMouseOut.BindEvent(this, newDiv);
		newDiv.onclick = this.OptionOnClick.BindEvent(this, hLanguage);
		newImg = document.createElement("IMG");
		newImg.src = "images/" + hLanguage.flag;
		newP = document.createElement("P");
		newP.appendChild(newImg);
		newP.appendChild(document.createTextNode(hLanguage.name));
		newDiv.appendChild(newP);
		this.hPopupDiv.appendChild(newDiv);
	}
}

UI.LanguagePicker.prototype.ContainerOnMouseOver = function(e) {
	
	this.hContainerDiv.className = "languagePickerFlagHover";
}

UI.LanguagePicker.prototype.ContainerOnMouseOut = function(e) {
	
	this.hContainerDiv.className = "languagePickerFlag";
}

UI.LanguagePicker.prototype.ContainerOnClick = function(e) {
	if(this.hPopupDiv.style.display == "none") {
		this.ShowPopup();
	} else {
		this.HidePopup();
	}
}

UI.LanguagePicker.prototype.OptionOnMouseOver = function(e, div) {
	div.className = "languagePickerOptionHover";
}

UI.LanguagePicker.prototype.OptionOnMouseOut = function(e, div) {
	div.className = "languagePickerOption";
}

UI.LanguagePicker.prototype.OptionOnClick = function(e, language) {
	if(language != this.oCurrentLanguage) {
		Net.Cookies.CreateCookie("language", language.code, 365);
		window.location = "http://" + language.code + "." + baseDomain + window.location.pathname + window.location.search;
	}
	this.HidePopup();
	
}

UI.LanguagePicker.prototype.ShowPopup = function() {
	
	// Delcare variables
	var hFlag;
	var pPosition;
	
	// Make visible
	this.hPopupDiv.style.display = "block";
		
	// Calculate position
	hFlag = $(this.hContainerDiv);
	pPosition = hFlag.getAbsolutePosition();
	pPosition.x += 42;
	pPosition.x -= this.hPopupDiv.clientWidth;
	pPosition.x -= 2;
	
	this.hPopupDiv.style.top = pPosition.y + "px";
	this.hPopupDiv.style.left = pPosition.x + "px";
	
	this.hContainerDiv.style.zIndex = 11;
	this.hPopupDiv.style.zIndex = 11;
}

UI.LanguagePicker.prototype.HidePopup = function() {
	
	this.hPopupDiv.style.display = "none";
	this.hContainerDiv.style.zIndex = 1;
}

UI.LanguagePicker.prototype.__type = "UI.LanguagePicker";
UI.LanguagePicker.prototype.oCurrentLanguage = null;

UI.LanguagePicker.prototype.hParentElement = null;
UI.LanguagePicker.prototype.hContainerDiv = null;
UI.LanguagePicker.prototype.hPopupDiv = null;



UI.ProgressBar = function(hParentElement, progress, maxProgress, width, height) {
	
	this.Initialize(hParentElement, progress, maxProgress, width, height);
}

UI.ProgressBar.prototype.Initialize = function(hParentElement, progress, maxProgress, width, height) {
	
	// Declare variables
	
	// Store handle and variables
	this.hParentElement = hParentElement;
	
	this.iMaxProgress = maxProgress || 100;
	this.iWidth = width || 100;
	this.iHeight = height || 10;
	
	// Create the main progress bar
	this.hMainProgressBar = document.createElement("DIV");
	this.hMainProgressBar.className = "progressBar";
	this.hMainProgressBar.style.width = this.iWidth + "px";
	this.hMainProgressBar.style.height = this.iHeight + "px";
	this.hParentElement.appendChild(this.hMainProgressBar);
	
	// Fill the progress bar
	this.hProgressBarFiller = document.createElement("DIV");
	this.hProgressBarFiller.className = "progressBarFiller";
	this.hProgressBarFiller.style.height = this.iHeight + "px";
	this.hMainProgressBar.appendChild(this.hProgressBarFiller);
	
	// Set initial progress
	this.SetProgress(progress);
}

UI.ProgressBar.prototype.SetProgress = function(progress) {
	
	// Declare variables
	var iWidth;
	
	if(progress > this.iMaxProgress)
		progress = this.iMaxProgress;
	this.iProgress = progress;
	
	// Calc width
	iWidth = Math.round(this.iWidth * (this.iProgress / this.iMaxProgress));
	
	// Set the progress bar
	this.hProgressBarFiller.style.width = iWidth + "px";
}

UI.ProgressBar.prototype.Dispose = function() {
	
	this.hParentElement.removeChild(this.hMainProgressBar);
}

UI.ProgressBar.prototype.__type = "UI.ProgressBar";
UI.ProgressBar.prototype.iProgress = 0;
UI.ProgressBar.prototype.iMaxProgress = 0;
UI.ProgressBar.prototype.iWidth = 0;
UI.ProgressBar.prototype.iHeight = 0;

UI.ProgressBar.prototype.hParentElement = null;
UI.ProgressBar.prototype.hMainProgressBar = null;
UI.ProgressBar.prototype.hProgressBarFiller = null;


var Localization = {};
Localization.Languages = {};
Localization.Languages.Dutch = { name: "Nederlands", flag: "flag-nl.png", code: "nl" };
Localization.Languages.English = { name: "English", flag: "flag-en.png", code: "en" };

Localization.LanguageMap = {
	dutch: Localization.Languages.Dutch,
	nl: Localization.Languages.Dutch,
	english: Localization.Languages.English,
	en: Localization.Languages.English
}
/*
var Localization = {};
Localization.Languages = {};
Localization.Languages.Dutch = { name: "Nederlands", flag: "flag-dutch.png", code: "nl" };

Localization.LanguageMap = {
	dutch: Localization.Languages.Dutch,
	nl: Localization.Languages.Dutch
}*/

var Speech = {};
Speech.Voices = {};
Speech.Voices.Dutch = { maleClsid: "{A0DDCA41-A92C-11d1-B17B-0020AFED142E}", femaleClsid: "{A0DDCA40-A92C-11d1-B17B-0020AFED142E}", langid: 0x0413, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.British = { maleClsid: "{227A0E41-A92A-11d1-B17B-0020AFED142E}", femaleClsid: "{227A0E40-A92A-11d1-B17B-0020AFED142E}", langid: 0x0809, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.American = { maleClsid: "{CA141FD0-AC7F-11D1-97A3-006008273000}", femaleClsid: "{CA141FD0-AC7F-11D1-97A3-006008273008}", langid: 0x0409, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.French = { maleClsid: "{0879A4E1-A92C-11d1-B17B-0020AFED142E}", femaleClsid: "{0879A4E0-A92C-11d1-B17B-0020AFED142E}", langid: 0x040C, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.German = { maleClsid: "{3A1FB761-A92B-11d1-B17B-0020AFED142E}", femaleClsid: "{3A1FB760-A92B-11d1-B17B-0020AFED142E}", langid: 0x0407, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.Spanish = { maleClsid: "{2CE326E1-A935-11d1-B17B-0020AFED142E}", femaleClsid: "{2CE326E0-A935-11d1-B17B-0020AFED142E}", langid: 0x0C0A, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.Italian = { maleClsid: "{7EF71701-A92D-11d1-B17B-0020AFED142E}", femaleClsid: "{7EF71700-A92D-11d1-B17B-0020AFED142E}", langid: 0x0410, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 150 };
Speech.Voices.Japaneese = { maleClsid: "{A778E061-A936-11d1-B17B-0020AFED142E}", femaleClsid: "{A778E060-A936-11d1-B17B-0020AFED142E}", langid: 0x0411, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.Russian = { maleClsid: "{06377F81-D48E-11d1-B17B-0020AFED142E}", femaleClsid: "{06377F80-D48E-11d1-B17B-0020AFED142E}", langid: 0x0419, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };
Speech.Voices.Portugese = { maleClsid: "{8AA08CA1-A1AE-11d3-9BC5-00A0C967A2D1}", femaleClsid: "{8AA08CA0-A1AE-11d3-9BC5-00A0C967A2D1}", langid: 0x0416, srid: "{161FA781-A52C-11d0-8D7C-00A0C9034A7E}", baseSpeed: 130 };

Speech.LanguageMap = {
	english: Speech.Voices.British,
	engels: Speech.Voices.British,
	american: Speech.Voices.American,
	amerikaans: Speech.Voices.American,
	dutch: Speech.Voices.Dutch,
	nederlands: Speech.Voices.Dutch,
	french: Speech.Voices.French,
	frans: Speech.Voices.French,
	german: Speech.Voices.German,
	duits: Speech.Voices.German,
	spanish: Speech.Voices.Spanish,
	spaans: Speech.Voices.Spanish,
	italian: Speech.Voices.Italian,
	italiaans: Speech.Voices.Italian,
	japaneese: Speech.Voices.Japaneese,
	japans: Speech.Voices.Japaneese,
	russian: Speech.Voices.Russian,
	russisch: Speech.Voices.Russian,
	portugese: Speech.Voices.Portugese,
	portugees: Speech.Voices.Portugese
};

/**
 * Retrieves a Speech.Voices according to the passed language string
 * @param {Object} language A string containing the language
 */
Speech.GetVoice = function(language) {
	
	var strLanguage;
	
	strLanguage = language.toLowerCase().trim();
	
	for(var key in Speech.LanguageMap) {
		if(strLanguage.indexOf(key) != -1)
			return Speech.LanguageMap[key];
	}
	
	return null;
}

Speech.SpeechControl = function() {
	this.Initialize();
}

Speech.SpeechControl.prototype.Initialize = function() {
	
	// Declare variables
	var newObject, newDiv;
	var hDhtmlEntry;
	
	this.OnLoad = new Delegate();
	
	// Get handles
	hDhtmlEntry = document.getElementById("dhtmlEntry");
	
	// Creat hidden div
	newDiv = document.createElement("DIV");
	newDiv.className = "hidden";
	hDhtmlEntry.appendChild(newDiv);
	
	// Create objects
	try {
		this.hAgentControl = document.createElement("OBJECT");
		this.hAgentControl.onreadystatechange = this.OnAgentControlReadyStateChange.BindEvent(this);
		this.hAgentControl.classid = "clsid:D45FD31B-5C6E-11D1-9EC1-00C04FD7081F";
		this.hAgentControl.codebase = "#VERSION=2,0,0,0";
		newDiv.appendChild(this.hAgentControl);
	}
	catch(ex) {};
	
	try {
		this.hTruVoice = document.createElement("OBJECT");
		this.hTruVoice.onreadystatechange = this.OnTruVoiceReadyStateChange.BindEvent(this);
		this.hTruVoice.classid = "clsid:B8F2846E-CE36-11D0-AC83-00C04FD97575";
		this.hTruVoice.codebase = "#VERSION=6,0,0,0";
		newDiv.appendChild(this.hTruVoice);
	}
	catch(ex) {};
	
}

Speech.SpeechControl.prototype.FinishInitialization = function() {
	
	// Check if both AgentControl and TruVoice objects have been loaded
	if(this.bAgentControlInitialized && this.bTruVoiceInitialized) {
		
		// Check if agentcontrol is available
		try {
			if(this.hAgentControl) {
				
				// Attempt to load the Vocabulum Speech Widget
				this.hAgentControl.Connected = true;
				this.oLoadRequest = this.hAgentControl.Characters.Load("Vocabulum", "Vocabulum.acs");
				if(this.oLoadRequest.Status != 0) {
					this.oLoadRequest = this.hAgentControl.Characters.Load("Vocabulum", BASE_URL + "/speech/Vocabulum.acf");
					if(this.oLoadRequest.Status != 0)
						throw new Error("Unable to load the Vocabulum Speech Widget.");
				}
				
				// Get character handle
				this.oCharacter = this.hAgentControl.Characters.Character("Vocabulum");
				this.SetVoice(Speech.Voices.British);
				
				// Show the character
				this.oCharacter.Get("state", "showing, speaking");
				this.oCharacter.Show();
				this.oCharacter.MoveTo(screen.width - 138, screen.height - 104);
			}
		} catch(ex) {
			this.bSpeechOutput = false;
			this.bSpeechRecognition = false;
		}
		
		this.OnLoad.Invoke();
	}
}

Speech.SpeechControl.prototype.OnAgentControlReadyStateChange = function(e) {
	if(this.hAgentControl.readyState == 4)
		this.bAgentControlInitialized = true;
	this.FinishInitialization();
}

Speech.SpeechControl.prototype.OnTruVoiceReadyStateChange = function(e) {
	if(this.hTruVoice.readyState == 4)
		this.bTruVoiceInitialized = true;
	this.FinishInitialization();
}

Speech.SpeechControl.prototype.Speak = function(text) {
	if(this.bSpeechOutput) {
		if(!this.bShowBalloon)
			text = "\\Map=\"" + text + "\"=\"\"\\";
		text = "\\Spd=" + (this.oSelectedVoice.baseSpeed + this.iSpeedModifier) + "\\" + text;
		this.oCharacter.Speak(text);
	}
}

Speech.SpeechControl.prototype.Show = function() {
	this.oCharacter.Show();
}

Speech.SpeechControl.prototype.Hide = function() {
	this.oCharacter.Hide();
}

Speech.SpeechControl.prototype.SetVoice = function(voice, gender, speedModifier) {
	
	this.cGender = gender || this.cGender;
	this.iSpeedModifier = speedModifier || 0;
	
	// Set the language
	this.oSelectedVoice = voice;
	this.oCharacter.LanguageID = voice.langid;
	switch(this.cGender) {
		case 'male':
			try { this.oCharacter.TTSModeID = voice.maleClsid; this.bSpeechOutput = true; } catch(ex) { this.bSpeechOutput = false; }
			try { this.oCharacter.SRModeID = voice.srid; this.bSpeechRecognition = true; } catch(ex) { this.bSpeechRecognition = false; }
			break;
		case 'female':
			try { this.oCharacter.TTSModeID = voice.femaleClsid; this.bSpeechOutput = true; } catch(ex) { this.bSpeechOutput = false; }
			try { this.oCharacter.SRModeID = voice.srid; this.bSpeechRecognition = true; } catch(ex) { this.bSpeechRecognition = false; }
			break;
	}
	
	return true;
}

Speech.SpeechControl.prototype.bAgentControlInitialized = false;
Speech.SpeechControl.prototype.bShowBalloon = true;
Speech.SpeechControl.prototype.bTruVoiceInitialized = false;
Speech.SpeechControl.prototype.bSpeechOutput = false;
Speech.SpeechControl.prototype.bSpeechRecognition = false;
Speech.SpeechControl.prototype.cGender = 'male'; 
Speech.SpeechControl.prototype.oCharacter = null;
Speech.SpeechControl.prototype.oLoadRequest = null;
Speech.SpeechControl.prototype.hAgentControl = null;
Speech.SpeechControl.prototype.hTruVoice = null;
Speech.SpeechControl.prototype.OnLoad = null;
Speech.SpeechControl.prototype.oSelectedVoice = null;
Speech.SpeechControl.prototype.iSpeedModifier = 0;

UI.WrtsImporter = function UI$WrtsImporter(hParentElement, iHelpItemId) {
	this.Initialize(hParentElement, iHelpItemId);
}

UI.WrtsImporter.prototype.Initialize = function UI$WrtsImporter$Initialize(hParentElement, iHelpItemId) {
	
	// Save handle
	this.hParentElement = hParentElement;
	this.iHelpItemId = iHelpItemId;
	
	// Declare variables
	var newCell, newRow, newP;
	
	// Create contianer
	this.hContainerTable = document.createElement("TABLE");
	this.hContainerTable.className = "containerTable";
	this.hContainerTable.cellSpacing = "0";
	this.hContainerTable.cellPadding = "0";
	this.hParentElement.appendChild(this.hContainerTable);
	
	// Create header
	newRow = this.hContainerTable.insertRow(-1);
	newCell = newRow.insertCell(-1);
	newCell.className = "headerCell";
	newCell.colSpan = 3;
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['WrtsImporter.Caption']))
	newCell.appendChild(newP);
	
	// Create control cells
	newRow = this.hContainerTable.insertRow(-1);
	newCell = newRow.insertCell(-1);
	newCell.className = "wrtsWordlistImporterControlCell";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['WrtsImporter.EmailLabel']))
	newP.appendChild(document.createElement("BR"));
	this.hUserInput = document.createElement("INPUT");
	this.hUserInput.type = "text";
	this.hUserInput.className = "mediumInput";
	newP.appendChild(this.hUserInput);
	newCell.appendChild(newP);
	
	newCell = newRow.insertCell(-1);
	newCell.className = "wrtsWordlistImporterControlCell";
	newP = document.createElement("P");
	newP.appendChild(document.createTextNode(TEXT['WrtsImporter.PasswordLabel']))
	newP.appendChild(document.createElement("BR"));
	this.hPasswordInput = document.createElement("INPUT");
	this.hPasswordInput.type = "password";
	this.hPasswordInput.className = "mediumInput";
	newP.appendChild(this.hPasswordInput);
	newCell.appendChild(newP);
	
	newCell = newRow.insertCell(-1);
	newCell.className = "wrtsWordlistImporterControlCell";
	this.hImportButton = document.createElement("INPUT");
	this.hImportButton.type = "button";
	this.hImportButton.className = "mediumButton";
	this.hImportButton.value = TEXT['WrtsImporter.ImportButton'];
	this.hImportButton.onclick = this.OnImportButtonClick.BindEvent(this);
	newCell.appendChild(this.hImportButton);
	
	// Create progress cells
	newRow = this.hContainerTable.insertRow(-1);
	newCell = newRow.insertCell(-1);
	newCell.className = "wrtsWordlistImporterProgressCell";
	newCell.colSpan = 3;
	this.hStatusLabel = document.createElement("P");
	newCell.appendChild(this.hStatusLabel);
	
	newRow = this.hContainerTable.insertRow(-1);
	newCell = newRow.insertCell(-1);
	newCell.className = "wrtsWordlistImporterProgressCell";
	newCell.colSpan = 3;
	this.oProgressBar = new UI.ProgressBar(newCell, 0, 100, 860, 10);
	
	this.SetStatus(TEXT['WrtsImporter.Ready']);
}

UI.WrtsImporter.prototype.SetStatus = function UI$WrtsImporter$SetStatus(text) {
	
	while(this.hStatusLabel.hasChildNodes())
		this.hStatusLabel.removeChild(this.hStatusLabel.firstChild);
	this.hStatusLabel.appendChild(document.createTextNode(text));
}

UI.WrtsImporter.prototype.OnImportButtonClick = function UI$WrtsImporter$OnImportButtonClick(e) {
	
	if(this.bImporting) {
		this.bStopping = true;
	} else {
		
		// Set control variables
		this.bImporting = true;
		this.bStopping = false;
		this.oWrtsRootFolder = new Wrts.WrtsFolder();
		this.iTotalObjects = 0;
		this.iObjectsDone = 0;
		
		// Set button and status text
		this.hImportButton.value = TEXT['WrtsImporter.ImportButtonAlternative'];
		this.SetStatus(TEXT['WrtsImporter.ImportStatus1']);
		this.oProgressBar.SetProgress(0);
		
		// Start importing sequence
		this.strWrtsUser = this.hUserInput.value;
		this.hUserInput.disabled = true;
		this.strWrtsPassword = this.hPasswordInput.value;
		this.hPasswordInput.disabled = true;
		this.EnumerateWrtsWordlists();
	}
}

UI.WrtsImporter.prototype.ImportCancelled = function UI$WrtsImporter$ImportCancelled() {
	
	this.bImporting = false;
	this.hUserInput.disabled = false;
	this.hPasswordInput.disabled = false;
	this.hImportButton.value = TEXT['WrtsImporter.ImportButton'];
}

UI.WrtsImporter.prototype.ImportFinished = function UI$WrtsImporter$ImportFinished() {
	
	this.bImporting = false;
	this.hUserInput.disabled = false;
	this.hPasswordInput.disabled = false;
	this.hImportButton.value = TEXT['WrtsImporter.ImportButton'];
	alert(TEXT['WrtsImporter.ImportFinished']);
}

UI.WrtsImporter.prototype.EnumerateWrtsWordlists = function UI$WrtsImporter$EnumerateWrtsWordlists() {
	
	// Declare varialbes
	var strUrl;
	
	// Make request
	strUrl = "xml.php?page=enumeratewrtslists&user=" + this.strWrtsUser + "&password=" + this.strWrtsPassword; 
	this.oWrtsRequest = new Net.Request(strUrl, "GET", null, true);
	this.oWrtsRequest.OnComplete.Suscribe(this.OnEnumerateWrtsWordlistsData, this);
	this.oWrtsRequest.MakeRequest();
}

UI.WrtsImporter.prototype.OnEnumerateWrtsWordlistsData = function UI$WrtsImporter$OnEnumerateWrtsWordlistsData() {
	
	// Declare variables
	var hResponseNode;
	var hResponseSubNode, hGroupSubNode;
	var newWrtsFolder;
	
	// Update status
	this.SetStatus(TEXT['WrtsImporter.ImportStatus2']);
	this.oProgressBar.SetProgress(2);
	
	// Check if import is being stopped
	if(this.bStopping) {
		this.ImportCancelled();
		return;
	}
	
	// Check if response is valid
	if(!this.oWrtsRequest.ExtendedResult) {
		this.SetStatus(TEXT['WrtsImporter.ImportError1']);
		this.ImportCancelled();
		return;
	}
	
	hResponseNode = this.oWrtsRequest.ExtendedResult;
	if(hResponseNode.nodeName == "response") {
		if(hResponseNode.getAttribute("success") == "false") {
			alert(TEXT['WrtsImporter.InvalidUsernamePassword']);
			this.ImportCancelled();
			return;
		}
	} else if(hResponseNode.nodeName == "list-index") {
		
		// Iterate trough wordlist and folders
		for(var x = 0; x < hResponseNode.childNodes.length; x++) {
			hResponseSubNode = hResponseNode.childNodes[x];
			
			// Skip non element nodes
			if(hResponseSubNode.nodeType != 1)
				continue;
				
			switch(hResponseSubNode.nodeName) {
				case "list":
				
					// Parse the list information and add to root folder
					this.oWrtsRootFolder.arrWordLists.push(this.ParseWrtsListWordList(hResponseSubNode));
					this.iTotalObjects++;
					break;
				case "group":
				
					// Creat new subgroup
					newWrtsFolder = new Wrts.WrtsFolder();
					this.oWrtsRootFolder.arrFolders.push(newWrtsFolder);
					this.iTotalObjects++;
					
					// Parse group sub nodes
					for(y = 0; y < hResponseSubNode.childNodes.length; y++) {
						hGroupSubNode = hResponseSubNode.childNodes[y];
						
						// Skip non element nodes
						if(hGroupSubNode.nodeType != 1)
							continue;
						
						switch(hGroupSubNode.nodeName) {
							case "title":
								if(hGroupSubNode.hasChildNodes())
									newWrtsFolder.strName = hGroupSubNode.firstChild.nodeValue;
								break;
							case "list":
							
								// Parse the list information and add to root folder
								newWrtsFolder.arrWordLists.push(this.ParseWrtsListWordList(hGroupSubNode));
								this.iTotalObjects++;
								break;
						}
					}
					break;
			}
		}
	}
	
	// Prepare class variables for object storage
	this.iCurrentFolderIndex = 0;
	this.iCurrentWordListIndex = 0;
	this.oProgressBar.SetProgress(5);
	this.StoreWrtsObjects();
}

UI.WrtsImporter.prototype.ParseWrtsListWordList = function UI$WrtsImporter$ParseWrtsListWordList(hNode) {
	
	// Delcare variables
	var newWrtsWordList;
	var hListSubNode;
	
	newWrtsWordList = new Wrts.WrtsWordList();
	
	// Iterate trough child nodes
	for(var x = 0; x < hNode.childNodes.length; x++) {
		hListSubNode = hNode.childNodes[x];
		
		// Skip non element nodes
		if(hListSubNode.nodeType != 1)
			continue;
		
		switch(hListSubNode.nodeName) {
			case "id":
				if(hListSubNode.hasChildNodes())
					newWrtsWordList.iId = parseInt(hListSubNode.firstChild.nodeValue);
				break;
			case "title":
				if(hListSubNode.hasChildNodes())
					newWrtsWordList.strName = hListSubNode.firstChild.nodeValue;
				break;
		}
	}
	
	return newWrtsWordList;
}

UI.WrtsImporter.prototype.StoreWrtsObjects = function UI$WrtsImporter$StoreWrtsObjects() {
	
	// Declare variables
	var hWordList, hFolder;
	var strUrl;
	
	// Check if import is being stopped
	if(this.bStopping) {
		this.ImportCancelled();
		return;
	}
	
	// Update progress bar
	this.oProgressBar.SetProgress(5 + 95 * (this.iObjectsDone / this.iTotalObjects));
	
	// Examine previous result
	if(this.iCurrentFolderIndex > 0 && this.iCurrentFolderIndex <= this.oWrtsRootFolder.arrFolders.length) {
		
		// Check if an error ocurred
		if(this.oVocRequest.ExtendedResult == -1) {
			this.SetStatus(TEXT['WrtsImporter.ImportError2']);
			this.ImportCancelled();
			return;
		}
		
		// Update wrts folder category mapping
		hFolder = this.oWrtsRootFolder.arrFolders[this.iCurrentFolderIndex - 1];
		hFolder.iCategoryId = this.oVocRequest.ExtendedResult;
		this.iObjectsDone++;
	}
	
	// Create folder structure
	if(this.iCurrentFolderIndex < this.oWrtsRootFolder.arrFolders.length) {
		hFolder = this.oWrtsRootFolder.arrFolders[this.iCurrentFolderIndex];
		this.iCurrentFolderIndex++;
		
		this.SetStatus(TEXT['WrtsImporter.ImportCreateCategory'] + hFolder.strName);
		this.oVocRequest = new Net.Request("xml.php?page=createcategory&category=" + this.iUserMyWordListsCategoryId, "post", "name=" + escape(hFolder.strName), true);
		this.oVocRequest.OnComplete.Suscribe(this.StoreWrtsObjects, this);
		this.oVocRequest.MakeRequest();
		
		// Break out (wait for async call to resume the operation)
		return;
	}
	
	// Put all the word lists in a single array for serial processing.
	if(this.iCurrentWordListIndex == 0) {
		
		this.arrWrtsWordLists = new Array();
		for(var x = 0; x < this.oWrtsRootFolder.arrWordLists.length; x++) {
			hWordList = this.oWrtsRootFolder.arrWordLists[x];
			hWordList.iParentCategoryId = this.iUserMyWordListsCategoryId;
			this.arrWrtsWordLists.push(hWordList);
		}
		for(var x = 0; x < this.oWrtsRootFolder.arrFolders.length; x++) {
			hFolder = this.oWrtsRootFolder.arrFolders[x];
			for(var y = 0; y < hFolder.arrWordLists.length; y++) 
			{
				hWordList = hFolder.arrWordLists[y];
				hWordList.iParentCategoryId = hFolder.iCategoryId;
				this.arrWrtsWordLists.push(hWordList);
			}
		}
	}
	
	// Examine previous result
	if(this.iCurrentWordListIndex > 0 && this.iCurrentWordListIndex <= this.arrWrtsWordLists.length) {
		
		// Check if an error ocurred
		if(!this.oVocRequest.ExtendedResult) {
			this.SetStatus(TEXT['WrtsImporter.ImportError3']);
			this.ImportCancelled();
			return;
		}
		
		this.iObjectsDone++;
	}
	
	// Store next wordlist
	if(this.iCurrentWordListIndex < this.arrWrtsWordLists.length) {
		hWordList = this.arrWrtsWordLists[this.iCurrentWordListIndex];
		this.iCurrentWordListIndex++;
		
		this.SetStatus(TEXT['WrtsImporter.ImportStoreWordlist'] + hWordList.strName);
		strUrl = "xml.php?page=importwrtslist&category=" + hWordList.iParentCategoryId + "&user=" + this.strWrtsUser + "&password=" + this.strWrtsPassword + "&wordlist=" + hWordList.iId;
		this.oVocRequest = new Net.Request(strUrl, "get", null, true);
		this.oVocRequest.OnComplete.Suscribe(this.StoreWrtsObjects, this);
		this.oVocRequest.MakeRequest();
		
		// Break out (wait for async call to resume the operation)
		return;
	}
	
	this.SetStatus(TEXT['WrtsImporter.ImportFinished']);
	this.oProgressBar.SetProgress(100);
	this.ImportFinished();
}

UI.WrtsImporter.prototype.__type = "UI.WrtsImporter";
UI.WrtsImporter.prototype.bImporting = false;
UI.WrtsImporter.prototype.bStopping = false;
UI.WrtsImporter.prototype.iTotalObjects = 0;
UI.WrtsImporter.prototype.iObjectsDone = 0;
UI.WrtsImporter.prototype.iCurrentFolderIndex = 0;
UI.WrtsImporter.prototype.iCurrentWordListIndex = 0;
UI.WrtsImporter.prototype.iUserMyWordListsCategoryId = null;
UI.WrtsImporter.prototype.iHelpItemId = null;

UI.WrtsImporter.prototype.strWrtsUser = null;
UI.WrtsImporter.prototype.strWrtsPassword = null;

UI.WrtsImporter.prototype.oWrtsRequest = null;
UI.WrtsImporter.prototype.oVocRequest = null;

UI.WrtsImporter.prototype.oWrtsRootFolder = null;
UI.WrtsImporter.prototype.arrWrtsWordLists = null;

UI.WrtsImporter.prototype.hParentElement = null;
UI.WrtsImporter.prototype.hContainerTable = null;
UI.WrtsImporter.prototype.hUserInput = null;
UI.WrtsImporter.prototype.hPasswordInput = null;
UI.WrtsImporter.prototype.hImportButton = null;
UI.WrtsImporter.prototype.hStatusLabel = null;
UI.WrtsImporter.prototype.oProgressBar = null;

var Wrts = {};
Wrts.WrtsWordList = function Wrts$WrtsWordList() {
}
Wrts.WrtsWordList.prototype.iId = null;
Wrts.WrtsWordList.prototype.strName = null;
Wrts.WrtsWordList.prototype.iParentCategoryId = null;

Wrts.WrtsFolder = function Wrts$WrtsFolder() {
	
	// Initialize variables
	this.arrFolders = new Array();
	this.arrWordLists = new Array();
}
Wrts.WrtsFolder.prototype.strName = null;
Wrts.WrtsFolder.prototype.iCategoryId = null;
Wrts.WrtsFolder.prototype.arrFolders = null;
Wrts.WrtsFolder.prototype.arrWordLists = null;

UI.ClearForm = function UI$ClearForm(hElement) {
	this.Initialize(hElement);
}
UI.ClearForm.prototype.Initialize = function(hElement) {
	
	// Store variables
	this.hForm = hElement;
	
	// Initialize variables
	this.aFields = new Array();
	this.aValidateFunctions = new Array();
	this.aOnFocusFunctions = new Array();
	this.aOnBlurFunctions = new Array();
	this.aOnMouseOverFunctions = new Array();
	this.aOnMouseOutFunctions = new Array();
	this.aValidateRequests = new Array();
}
UI.ClearForm.prototype.AddField = function(id) {
	
	// Declare variables
	var hElement;
	
	// Get element
	hElement = document.getElementById(id);
	this.aFields[id] = hElement;
	
	// Hookup events
	hElement.onfocus = this.OnInputFocus.Bind(this, id);
	hElement.onblur = this.OnInputBlur.Bind(this, id);
	hElement.onchange = this.OnInputChanged.Bind(this, id);
	hElement.onmouseover = this.OnInputMouseOver.Bind(this, id);
	hElement.onmouseout = this.OnInputMouseOut.Bind(this, id);
}

UI.ClearForm.prototype.RegisterFunction = function(fieldId, type, fn) {
	switch(type) {
		case "onfocus":
			this.aOnFocusFunctions[fieldId] = fn;
			break;
		case "onmouseover":
			this.aOnMouseOverFunctions[fieldId] = fn;
			break;
		case "onblur":
			this.aOnBlurFunctions[fieldId] = fn;
			break;
		case "onmouseout":
			this.aOnMouseOutFunctions[fieldId] = fn;
			break;
		case "validate":
			this.aValidateFunctions[fieldId] = fn;
			break;
	}
}

UI.ClearForm.prototype.OnInputFocus = function(id) {
	if(this.aOnFocusFunctions[id])
		this.aOnFocusFunctions[id].call(this, id);
}

UI.ClearForm.prototype.OnInputMouseOver = function(id) {
	if(this.aOnMouseOverFunctions[id])
		this.aOnMouseOverFunctions[id].call(this, id);
}

UI.ClearForm.prototype.OnInputBlur = function(id) {
	if(this.aOnBlurFunctions[id])
		this.aOnBlurFunctions[id].call(this, id);
	else 
		return;
		
	if(this.aValidateFunctions[id])
		this.aValidateFunctions[id].call(this, id);
}

UI.ClearForm.prototype.OnInputMouseOut = function(id) {
	if(this.aOnMouseOverFunctions[id])
		this.aOnMouseOverFunctions[id].call(this, id);
	else
		return;
		
	if(this.aValidateFunctions[id])
		this.aValidateFunctions[id].call(this, id);
}

UI.ClearForm.prototype.OnInputChanged = function(id) {
	//this.aValidateFunctions[id].call(this, id);
}

UI.ClearForm.prototype.XmlValidate = function(id, url) {
	
	// Declare variables
	var oRequest, hElement;
	
	hElement = this.aFields[id];
	
	oRequest = new Net.Request(url, "post", "validate=" + escape(hElement.value), true);
	oRequest.OnComplete.Suscribe(this.OnXmlValidate, this, id);
	oRequest.MakeRequest();
	
	this.aValidateRequests[id] = oRequest;
}

UI.ClearForm.prototype.OnXmlValidate = function(id) {
	
	// Declare variables
	var oRequest, hElement;
	
	hElement = document.getElementById(id + ".tip");
	oRequest = this.aValidateRequests[id];
		
	if(!oRequest.ExtendedResult) {
		hElement.innerHTML = TEXT['ClearForm.ValidationError'];
		return false;
	}
	
	switch(oRequest.ExtendedResult.result) {
		case false:
			hElement.innerHTML = "<p class=\"icon iconError\">" + oRequest.ExtendedResult.message + "</p>";
			break;
		case true:
			hElement.innerHTML = "<p class=\"icon iconAccept\">" + oRequest.ExtendedResult.message + "</p>";
			break;
	}
}

UI.ClearForm.prototype.hForm = null;

UI.ClearForm.prototype.aFields = null;
UI.ClearForm.prototype.aValidateFunctions = null;
UI.ClearForm.prototype.aOnFocusFunctions = null;
UI.ClearForm.prototype.aOnBlurFunctions = null;
UI.ClearForm.prototype.aOnMouseOverFunctions = null;
UI.ClearForm.prototype.aOnMouseOutFunctions = null;
UI.ClearForm.prototype.aValidateRequests = null;

var Sys = {};
Sys.Proto = {};
Sys.Proto.Document = function Sys$Proto$Document() {
	this.Initialize();
}
Sys.Proto.Document.prototype.Initialize = function Sys$Proto$Document$Initialize() {
	
	// Initialize class variables
	this.OnClick = new Delegate();
	this.OnMouseDown = new Delegate();
	this.OnMouseUp = new Delegate();
	
	this.DhtmlEntry = document.body;
	
	// Bind event handlers
	if(document.addEventListener) {
		
		document.addEventListener("click", this.Document_OnClick.BindEvent(this), false);
		document.addEventListener("mouseup", this.Document_OnMouseUp.BindEvent(this), false);
		document.addEventListener("mousedown", this.Document_OnMouseDown.BindEvent(this), false);
	} else if(document.attachEvent) {
		
		document.attachEvent("onclick", this.Document_OnClick.BindEvent(this));
		document.attachEvent("onmouseup", this.Document_OnMouseUp.BindEvent(this));
		document.attachEvent("onmousedown", this.Document_OnMouseDown.BindEvent(this));
	}
	
	// Make sure unhandled exceptions are handled
	window.onerror = this.Document_UnhandledError;
}

Sys.Proto.Document.prototype.Document_OnClick = function Sys$Proto$Document$Document_OnClick(e) {
	this.OnClick.Invoke(e);
}

Sys.Proto.Document.prototype.Document_OnMouseUp = function Sys$Proto$Document$Document_OnMouseUp(e) {
	this.OnMouseUp.Invoke(e);
}

Sys.Proto.Document.prototype.Document_OnMouseDown = function Sys$Proto$Document$Document_OnMouseDown(e) {
	this.OnMouseDown.Invoke(e);
}

Sys.Proto.Document.prototype.Document_UnhandledError = function Sys$Proto$Document$Document_UnhandledError(message, file, line) {
	
	// Create exception object
	var error = new Error(message);
	
	// Ignore adsense script errors
	if(file)
		if(file.indexOf("google") > -1)
			return;
	
	// Ignore 'syntax error on line 2'
	if(line == 2)
		return;
		
	error.fileName = file;
	error.lineNumber = line;
	//try {
		error.HandleByUser();
	//} catch(ex) {};
}

Sys.Proto.Document.prototype.__type = "Sys.Document";
Sys.Proto.Document.prototype.OnClick = null;
Sys.Proto.Document.prototype.OnMouseUp = null;
Sys.Proto.Document.prototype.OnMouseDown = null;
Sys.Proto.Document.prototype.DhtmlEntry = null;

Sys.Proto.Settings = function() {
	
	this.arrOriginalValues = new Array();
	this.arrKeys = new Array();
}

Sys.Proto.Settings.prototype.Add = function(key, value) {
	
	// Declare variables
	var bFound = false;
	
	// Create the key
	this.CreateSetting(key, value, this);
	
	// Check for duplicates
	for(var i = 0; i < this.arrKeys.length; i++) {
		if(this.arrKeys[i] == key)
			bFound = true;
	}
	if(!bFound)
		this.arrKeys.push(key);
}

Sys.Proto.Settings.prototype.AddAsOriginal = function(key, value) {
	
	// Create the key
	this.Add(key, value);
	this.arrOriginalValues[key] = value;
}

Sys.Proto.Settings.prototype.CreateSetting = function(key, value, object) {
	
	// Declare variables
	var keyPieces;
	var newBranch;
	
	// Create branch on subject
	keyPieces = key.split(".");
	if(keyPieces.length == 1) {
		object[keyPieces.shift()] = value;
	} else if(keyPieces.length > 1) {
		
		// Check if branch exists
		if(!object[keyPieces[0]])
			object[keyPieces[0]] = new Object();
		newBranch = object[keyPieces.shift()];
		
		// Recursion
		this.CreateSetting(keyPieces.join("."), value, newBranch);
	}
}

Sys.Proto.Settings.prototype.Remove = function(key) {
	
	// Destroy the key
	this.DestroySetting(key, this);
	
	for(var i = 0; i < this.arrKeys.length; i++) {
		if(this.arrKeys[i] == key)
			this.arrKeys.splice(i, 1);
	}
}

Sys.Proto.Settings.prototype.DestroySetting = function(key, object) {
	
	// Declare variables
	var keyPieces;
	var hBranch;
	
	keyPieces = key.split(".");
	if(keyPieces.length > 1) {
		if(object[keyPieces[0]]) {
			hBranch = object[keyPieces.shift()];
			
			// Recursion
			this.DestroySetting(keyPieces.join("."), hBranch);
		}
	} else if(keyPieces.length == 1) {
		
		// Destroy the branch
		if(object[keyPieces[0]])
			delete object[keyPieces[0]];
	}
}

Sys.Proto.Settings.prototype.GetValue = function(key, object) {
	
	// Delcare variables
	object = object || this;
	var keyPieces;
	var hBranch;
	
	keyPieces = key.split(".");
	if(keyPieces.length > 1) {
		if(object[keyPieces[0]] != "undefined") {
			hBranch = object[keyPieces.shift()];
			
			// Recursion
			return this.GetValue(keyPieces.join("."), hBranch);
		}
	} else if (keyPieces.length == 1) {
		
		// Return branch value if it exists
		if(object[keyPieces[0]] != "undefined")
			return object[keyPieces[0]];
	}
}

Sys.Proto.Settings.prototype.Save = function() {
	
	// Declare variables
	var arrChangedKeys;
	var keyValue, key;
	var strData;
	
	// Lookup all changed settings
	arrChangedKeys = new Array();
	for(var i = 0; i < this.arrKeys.length; i++) {
		
		// Compare values
		key = this.arrKeys[i];
		keyValue = this.GetValue(key);
		if(keyValue != this.arrOriginalValues[key]) {
			arrChangedKeys.push(key);
		}
	}
	
	// Don't make request if no settings have been changed
	if(arrChangedKeys.length == 0)
		return;
	
	// Serialize changed settings
	strData = "";
	for(var i = 0; i < arrChangedKeys.length; i++) {
		key = arrChangedKeys[i];
		if(i > 0)
			strData += "&";
		strData += unescape(key) + "=" + unescape(this.GetValue(key));
	}
	
	// Report changes to server
	this.netRequest = new Net.Request("xml.php?page=settings", "post", strData, true);
	this.netRequest.OnComplete.Suscribe(this.OnSave, this);
	this.netRequest.MakeRequest();
}

Sys.Proto.Settings.prototype.OnSave = function() {
	
	// Declare variables
	var hNode, hAttribute;
	var hSettingsNode;
	var strScript;
	
	if(this.netRequest.ExtendedResult) {
		hSettingsNode = this.netRequest.ExtendedResult;
		if(hSettingsNode.nodeName == "settings" && hSettingsNode.hasChildNodes()) {
			strScript = hSettingsNode.firstChild.nodeValue;
			
			// Execute script
			if(strScript !== null) {
				if(window.execScript) {
					window.execScript(strScript);
				} else {
					window.eval ? window.eval(strScript) : eval(strScript);
				}
			}
		}
	}
}



Sys.Proto.Settings.prototype.__type = "Sys.Settings";
Sys.Proto.Settings.prototype.arrOriginalValues = null;
Sys.Proto.Settings.prototype.arrKeys = null;
Sys.Proto.Settings.prototype.netRequest = null;

// Initialize the Sys.Document singleton
Sys.Document = new Sys.Proto.Document();
Sys.Settings = new Sys.Proto.Settings();


