// <![CDATA[

var AjaxFW = {

	HTTP_POST		: "POST",
	HTTP_GET		: "GET",
	RESPONSE_XML	: "text/xml",
	RESPONSE_TEXT	: "text/plain",
	RESPONSE_JSON	: "application/json",

	/**
	 * Creates an XMLHttpRequest object.
	 * 
	 * @return the created XMLHttpRequest object.
	 */
	getXMLHttpRequest: function() {
		return window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest();
	},
	
	/**
	 * Creates an AJAX-request.
	 * 
	 * @param callParam a JSON object with the call attributes (url, query, parameters, etc).
	 */
	call: function(callParam) {
		try {
			var http = this.getXMLHttpRequest();

			// Collect parameters.
			var url			= (callParam.url !== undefined ? callParam.url : "/");
			var asynchronous= (callParam.asynchronous !== undefined ? callParam.asynchronous : true);
			var parameters	= (callParam.parameters !== undefined ? callParam.parameters : {});
			var method		= (callParam.method !== undefined ? callParam.method : AjaxFW.HTTP_GET);
			var responseType= (callParam.responseType !== undefined ? callParam.responseType : AjaxFW.RESPONSE_XML);
			var contentType	= (callParam.contentType !== undefined ? callParam.contentType : "application/x-www-form-urlencoded");
			var encoding	= (callParam.encoding !== undefined ? callParam.encoding : "UTF-8");
			var onALoading	= (callParam.onLoading !== undefined ? callParam.onLoading : function(obj){});
			var onAComplete	= (callParam.onComplete !== undefined ? callParam.onComplete : function(obj){});
			var onAFailure	= (callParam.onFailure !== undefined ? callParam.onFailure : function(obj){});

			// Function that extracts the response content.
			var getResponseContent = function() {
				switch (responseType) {
					case AjaxFW.RESPONSE_XML: 
						return http.responseXML;
					case AjaxFW.RESPONSE_JSON:
						return eval("(" + http.responseText + ")");
					default:
						return http.responseText;
				}
			};
			
			// If asynchronous, create an onreadystatechange handler.
			if(asynchronous) {
				http.onreadystatechange = function() {	
					
					switch(http.readyState) {
						/* 0: UNINITIALIZED
						 * 1: LOADING
						 * 2: LOADED
						 * 3: INTERACTIVE
						 * 4: COMPLETE
						 */
						case 1:
							onALoading();
							break;
						case 4:
							if(http.status == 200) {
								onAComplete(getResponseContent());
							}
							else {		
								onAFailure();
							}
							break;
					}
				};
			}
				
			// Send request as HTTP GET.
			if(method === this.HTTP_GET) {
				http.open(this.HTTP_GET, (url + "?" + this.toQueryString(parameters, true) + "&r=" + parseInt((Math.random() * 99999999), 10)), asynchronous);
				http.send(null);
			}
			// Send request as HTTP POST. (POST is implemented in the browsers as a two-step process: sending the headers first, then sending data. So it's best to use GET, which only takes one TCP packet to send)
			else {
				http.open(this.HTTP_POST, url, asynchronous);
				http.setRequestHeader("Content-Type", contentType + (encoding ? "; charset=" + encoding : ""));
				http.send(this.toQueryString(parameters, false));
			}

			// If not asynchronous, return response content directly.
			if(!asynchronous) {
				return getResponseContent();
			}
		
		} catch(e) {alert("Error in AjaxFW.call()");}
	},
	
	/**
	 * Converts a JSON object into a HTTP query string.
	 * 
	 * @param obj the JSON object with parameters.
	 * @param escapeCharacters whether the characters will be escaped or not (for http-post requests, this should be false).
	 * @return the object as a query string.
	 */
	toQueryString: function(obj, escapeCharacters) {
		var queryString = "";

		// Sub function to create the query parameters.
		var generateParam = function(property, value) {
			if(escapeCharacters) {
				value = escape(value);
				property = escape(property);
			}
			if (!value) {
				return property + "&";
			} else {
				return property + "=" + value + "&";
			}
		};
	
		// Iterate over the passed object
		for(var property in obj) {
			if(typeof obj[property] != "function" ) {
				var value = obj[property];
				if (typeof value == "object" && value.constructor == Array) {
					for(var index=0; index<value.length; index++) {
						queryString += generateParam(property, value[index]);
					}
				} else {
					if(value !== undefined) {
						queryString += generateParam(property, value);
					}
				}
			}
		}

		// Return the object (removing the last ampersand)
		return queryString.substring(0, queryString.length - 1);
	}
};

var DOMFW = {

	/**
	 * Returns the first child (that is an element) with the specified name.
	 * 
	 * @param node the parent node to start from.
	 * @param name the name of the child node. 
	 * @return the child element (or null if no element was found).
	 */
	getFirstChildByName: function(node, name) {
		if(node === null || name === null) {
			return;
		}
		
		var elements = node.getElementsByTagName(name);
		if(elements !== null && elements.length > 0) {
			return elements[0];
		}
		
		return null;
	},
	
	/**
	 * Returns the value of the specified attribute.
	 * 
	 * @param node the node that contains the attribute.
	 * @param name the name of the attribute. 
	 * @return the value of the attribute (or null if no attribute was found).
	 */
	getAttribute: function(node, name) {
		if(node === null || name === null) {
			return null;
		}
		
		return node.getAttribute(name);
	},

	/**
	 * Returns the text content of a node.
	 * 
	 * @param node the node that holds the text.
	 * @return the node text content or an empty string if nothing was found.
	 */
	getText: function(node) {
		if(node === null) {
			return "";
		}

		var value;

		if(node.firstChild) {
			value = node.firstChild.nodeValue;
		}
		else {
			value = node.textContent;
		}
		
		return ((value === null || value === undefined) ? "" : TextFW.trim(value));
	}
};

var CookieFW = {

	/**
	 * Creates a cookie.
	 * 
	 * @param name the name of the cookie.
	 * @param value the cookie value.
	 * @param days the time to live in days for the cookie.
	 */
	set: function(name, value, days) {
		var expires = "";
		if (days) {
			var date = new Date();
			date.setTime(date.getTime()+(days*24*60*60*1000));
			expires = "; expires="+date.toGMTString();
		}
		document.cookie = name+"="+value+expires+"; path=/";
	},
	
	/**
	 * Returns the value of a cookie.
	 * 
	 * @param name the name of the cookie.
	 * @return the cookie value.
	 */
	get: function(name) {
		var nameEQ = name + "=";
		var cookies = document.cookie.split(";");
		for(var i=0; i<cookies.length; i++) {
			var c = cookies[i];
			while (c.charAt(0) == " ") {
				c = c.substring(1,c.length);
				if (c.indexOf(nameEQ) === 0) {
					// Remove "-characters and return value.
					return TextFW.replaceAll(c.substring(nameEQ.length,c.length), "\"", "");
				}
			}
		}
		return null;
	},
	
	/**
	 * Deletes a cookie.
	 * 
	 * @param name the name of the cookie to delete.
	 */
	remove: function(name) {
		this.set(name, "", -1);
	}
};

var ValidateFW = {

	hasIllegalCharsPattern:	"[/\\\\|:*?<>\"\']",
	hasEmailPattern:		"[\\w-]+(\\.[\\w-]+)*@([\\w-]+\\.)+[a-zA-Z]{2,7}",
	isDatePattern:			"^(?:(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(\\/|-|\\.)(?:0?2\\1(?:29))$)|(?:(?:1[6-9]|[2-9]\\d)?\\d{2})(\\/|-|\\.)(?:(?:(?:0?[13578]|1[02])\\2(?:31))|(?:(?:0?[1,3-9]|1[0-2])\\2(29|30))|(?:(?:0?[1-9])|(?:1[0-2]))\\2(?:0?[1-9]|1\\d|2[0-8]))$",
	isEmailPattern:			"^[\\w-]+(\\.[\\w-]+)*@([\\w-]+\\.)+[a-zA-Z]{2,7}$",
	isPasswordPattern:		"^[a-zA-Z0-9]+$",
	isHostPattern:			"^[a-zA-Z0-9]+([a-zA-Z0-9\\-\\.]+)?\\.([a-zA-Z]{2,7})$",
	isUrlPattern:			"^((news|(ht|f)tp(s?))\\://([\\w-\\.])+(/[\\w-./?%&=:,;#~]*)?)$",
	isNumberPattern:		"^(-?)[0-9]+$",

	hasIllegalChars: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("hasIllegalChars", str, actionURL);
		}
		return this.runRegExp(str, this.hasIllegalCharsPattern);
	},

	hasEmail: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("hasEmail", str, actionURL);
		}
		return this.runRegExp(str, this.hasEmailPattern);
	},

	isDate: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("isDate", str, actionURL);
		}
		return this.runRegExp(str, this.isDatePattern);
	},

	isEmail: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("isEmail", str, actionURL);
		}
		return this.runRegExp(str, this.isEmailPattern);
	},

	isPassword: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("isPassword", str, actionURL);
		}
		return this.runRegExp(str, this.isPasswordPattern);
	},

	isHostName: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("isHostName", str, actionURL);
		}
		return this.runRegExp(str, this.isHostPattern);
	},

	isUrl: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("isUrl", str, actionURL);
		}
		return this.runRegExp(str, this.isUrlPattern);
	},

	isNumber: function(str, actionURL) {
		if(actionURL) {
			return this.callServerValidate("isNumber", str, actionURL);
		}
		return this.runRegExp(str, this.isNumberPattern);
	},

	runRegExp: function(str, pattern) {
		return new RegExp(pattern).test(str);
	},
	
	callServerValidate: function(operation, string, actionURL) {
			
		var xml = AjaxFW.call ({
			url				: actionURL,
			asynchronous	: false,
			parameters		: {
				operationName	: operation,
				value			: string
			}
		});
		
		var rootElement = xml.documentElement;
		return (DOMFW.getText(DOMFW.getFirstChildByName(rootElement, "result")).toLowerCase() == "true");
	}
};

var TextFW = {

	/** 
	* Returns a new string resulting from removing all leading and trailing white spaces.
	* 
	* @param string the string to trim.
	* @return a new string without leading and trailing white spaces.
	*/
	trim: function(string) {
		return string.replace(/^\s+/, "").replace(/\s+$/, "");
	},
	
	/** 
	* Returns a new string resulting from replacing all matches of the pattern with the new string.
	* 
	* @param string the original string.
	* @param pattern the pattern to match.
	* @param newString the new string that should replace all matches of the pattern.
	* @return a new string with the replaced content.
	*/
	replaceAll: function(string, pattern, newString) {
		return string.replace(new RegExp(pattern, "g"), newString);
	},
	
	/** 
	* Replaces all occurrences of {<key>} in the template with a value.
	* The parameter array should contain entry sets like:
	* 	entry.key	= "someKey"
	* 	entry.value	= "someValue"
	*
	* @param template the template content.
	* @param parmeters an array of key/value objects.
	* @return the populated template content.
	*/
	populateTemplate: function(template, parameters) {

		if(template === null || parameters === null) {
			return template;
		}

		var content = unescape(template);
		for(var i in parameters) {
			content = TextFW.replaceAll(content, "{+?(" + parameters[i].key + ")}", parameters[i].value);
		}

		return content;
	}
};

// ]]> 
