function jajax(debug) {
	this.debug = debug;
	this.res = '';

	this.dynamicallyLoadedJSfiles = [];
	this.dynamicallyLoadedCSSfiles = [];

	// initialize the member function references
	// for the class prototype
	if (typeof(_jajax_prototype_called) == 'undefined'){

		jajax_prototype_called = true;
		jajax.prototype.c = this.c;
		jajax.prototype.s = this.s;
		jajax.prototype.serialize = this.serialize;
	}

	this.addScript = function(scriptURL, allowDuplication) {
		if (typeof allowDuplication == 'undefined') {
			allowDuplication = false;
		}

		if (allowDuplication || ($.inArray(scriptURL, this.dynamicallyLoadedJSfiles) == -1 && $('script[src$="'+scriptURL+'"]').length == 0)) {
			$.getScript(scriptURL, function() {
				if (j.debug && typeof console != 'undefined') {
					console.log("script loaded: "+scriptURL);
				}
				j.dynamicallyLoadedJSfiles.push(scriptURL);
			});
		} else if (this.debug && typeof console != 'undefined') {
			console.log("not loading script: "+scriptURL);
		}
	}

	this.addCSS = function(cssURL, media, allowDuplication) {
		if (typeof allowDuplication == 'undefined') {
			allowDuplication = false;
		}

		if (typeof media == 'undefined') {
			media = 'screen';
		}

		if (allowDuplication || ($.inArray(cssURL, this.dynamicallyLoadedCSSfiles) == -1 && $('link[href$="'+cssURL+'"]').length == 0)) {
			this.dynamicallyLoadedCSSfiles.push(cssURL);
			$('<link />').appendTo('head').attr({
				rel:  "stylesheet",
				type: "text/css",
				media: media,
				href: cssURL
			});

			if (this.debug && typeof console != 'undefined') {
				console.log("adding CSS ("+media+"): "+cssURL);
			}
		} else if (this.debug && typeof console != 'undefined') {
			console.log("not adding CSS ("+media+"): "+cssURL)
		}
	}

	this.real = function() {
		var func = arguments[0];
		arguments = arguments[1];

		var mthis = this;
		var args = new Array();
		var lp = location.pathname.replace(/\/\//g, '/');
		var url = lp+location.search;
		for (var i = 0; i < arguments.length; i++) {
			args[i] = arguments[i];
		}
		js_ret_data = null;

		if (func == 's') {
			js_sync_ret_value = null;
		}

		if (func == 'x') {
			var separator = '?';
			if (url.indexOf('?') != -1) {
				separator = '&';
			}
		}

		$.ajax( {
			async: (func == 's' ? false : true),
			type: 'POST',
			url: url + (func == 'x' ? separator + 'x3x_base64_encoded=1' : ''),
			data: { 'jajaxdata': $.toJSON(args) },
			dataType: (func == 'c' ? 'script' : null),
			success:
				function(t) {
					if(js_ret_data) {
						try{
							mthis.res = jQuery.parseJSON(js_ret_data);
							js_ret_data = null;
						}
						catch(e) {
							if(debug) {
								if(typeof console != 'undefined') {
									console.log('Malformed JSON data, unable to parse it. '+e);
								} else {
									alert('Malformed JSON data, unable to parse it. '+e);
								}
							}
						}

					}
					if (func == 's') {
						mthis.ret = js_sync_ret_value;
						js_sync_ret_value = null;
					}
				},
			error:
				function (request, textStatus, errorThrown) {
					if (debug) {
						if (typeof console != 'undefined') {
							console.log('Syncron Jajax error occured. Response: ', textStatus, errorThrown);
						} else {
							alert('Syncron Jajax error occured. Response: ' + textStatus);
						}
					}
				}
		});
		if (func == 's') {
			return this.ret;
		}
	}

	// call asyncron ajax function
	this.c = function() {
		this.real('c', arguments);
	}

	// call syncron ajax function
	this.s = function() {
		this.real('s', arguments);
	}

	// call x3x ajax function
	this.x = function() {
		this.real('x', arguments);
	}

	this.serialize = function(formID) {
		if (typeof formID == 'object') {
			var ser = $(formID).serialize();
		} else if (formID.indexOf(' ') > -1) {
			// JQselector
			var ser = $(formID).serialize();
		} else if (typeof formID != 'undefined' && formID) {
			// getElement ID
			var ser = $('#'+formID).serialize();
		} else {
			throw new exception ('Missing formID');
		}
		var jason = { 'jajaxformdata': ser }
		return jason;
	}

}
