// core.js
if(!(isset(console))) {
	var console;
}

if(!(isset(WCH))) {
	var WCH;
}

// string functions
String.prototype.trim = function () {
	return this.replace(/^\s*/, "").replace(/\s*$/, "");
}

function createAjaxObj() {
	var httprequest=false;
	if(window.XMLHttpRequest) { // if mozilla, safari etc
		httprequest=new XMLHttpRequest();
		if(httprequest.overrideMimeType) {
			httprequest.overrideMimeType("text/xml");
		}
	} else if (window.ActiveXObject) { // if ie
		try {
			httprequest=new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				httprequest=new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (e) {
			}
		}
	}
	return httprequest;
}

// functions from php_js project (http://kevin.vanzonneveld.net)

function isset(mixed_var) {
	// http://kevin.vanzonneveld.net
	// +original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// example 1: isset(undefined, true);
	// returns 1: false
	// example 2: isset('Kevin van Zonneveld');
	// returns 2: true
	var i=0,argc=arguments.length,argv=arguments,set=true;
	for(i=0;i<argc;i++){
		if(argv[i] == undefined){
			set = false;
			break;
		}
	}
	return set;
}

// utility functions

function addEvent(element,listener,handler) {
	var flow = "add:";
	// if the system is not set up, set it up, and store any outside script's event registration in the first handler slot
	if(typeof element[listener] != 'function' || typeof element[listener+'_num'] == 'undefined') {
		flow += " 1a";
		element[listener+'_num'] = 0;
		if(typeof element[listener] == 'function') {
			flow += ", 1ai";
			element[listener+0] = element[listener];
			element[listener+'_num']++;
		} else {
			flow += ", 1aii";
		}
		element[listener] = function(e) {
			var r = true;
			e = (e)?e:window.event;
			for(var i=0;i<element[listener+'_num'];i++) {
				if(element[listener+i](e) === false) {
					r = false;
				}
			}
			return r;
		}
	}else {
		flow += ", 1b";
	}
	//assign handler
	for(var i=0;i<element[listener+'_num'];i++) {
		if(element[listener+i] == handler) {
			flow += ", 2a";
			return flow;
		}
	}
	flow += ", 2b";
	element[listener+element[listener+'_num']] = handler;
	element[listener+'_num']++;
	return flow;
}

function removeEvent(element,listener,handler) {
	var flow = "remove:";
	//if the system is not set up, or there are no handlers to remove, exit
	if(typeof element[listener] != 'function' || typeof element[listener + '_num'] == 'undefined' || element[listener + '_num'] == 0) {
		flow += " 1a";
		return flow;
	} else {
		flow += " 1b";
	}
	// loop through handlers, if target handler is reached, begin overwriting each handler with the handler in front of it until one before the last
	var found = false;
	for(var i = 0;i<element[listener+'_num'];i++) {
		if(!found){
			found = element[listener+i] == handler;
			if(found) {
				flow += ", 2a("+i+")";
			}
		}
		if(found && (i+1) < element[listener+'_num']) {
			element[listener+i] = element[listener+(i+1)];
		}
	}
	//if handler was found, decrement the handler count
	if(found) {
		flow += ", --";
		element[listener+'_num']--;
	} else {
		flow += ", 2b";
	}
	return flow;
}

function img_preload(img_file) {
	var img_pre = new Image();
	img_pre.src = img_file;
}

function img_swap(img_id,img_file) {
	// console.log("img_swap("+img_id+","+img_file+") called");
	var img_ = document.getElementById(img_id);
	if(img_ && img_.src) {
		img_.src = img_file;
	}
}

function findPosX(obj) {
	var curleft = 0;
	if(obj.offsetParent) {
		while(1) {
			curleft += obj.offsetLeft;
			if(!obj.offsetParent) {
				break;
			}
			obj = obj.offsetParent;
		}
	} else if(obj.x) {
		curleft += obj.x;
	}
	// if(console && console.log) { console.log("findPosX("+obj+"): "+curleft); } else { alert("findPosX("+obj+"): "+curleft) }
	return curleft;
}

function findPosY(obj) {
	var curtop = 0;
	if(obj.offsetParent) {
		while(1) {
			curtop += obj.offsetTop;
			if(!obj.offsetParent) {
				break;
			}
			obj = obj.offsetParent;
		}
	} else if(obj.y) {
		curtop += obj.y;
	}
	// if(console && console.log) { console.log("findPosY("+obj+"): "+curtop); } else { alert("findPosY("+obj+"): "+curtop) }
	return curtop;
}

function findPos(obj) {
	var curleft = curtop = 0;
	if(obj.offsetParent) {
		do {
			curleft += obj.offsetLeft;
			curtop  += obj.offsetTop;
			// if(console && console.log) { console.log("findPos("+obj+")[oP]: top: "+curtop+", left: "+curleft); }
		} while(obj = obj.offsetParent);
	} else if(obj.x && obj.y) {
		curleft = obj.x;
		curtop  = obj.y;
		// if(console && console.log) { console.log("findPos("+obj+")[x|y]: top: "+curtop+", left: "+curleft); }
	}
	return {"left":curleft,"top":curtop};
}

function _serialize(_obj) {
	// Let Gecko browsers do this the easy way
	if(_obj) {
		if(_obj.toSource && (typeof _obj.toSource !== 'undefined' && typeof _obj.callee === 'undefined')) {
			return _obj.toSource();
		}
		
		// Other browsers must do it the hard way
		switch(typeof _obj) {
			// numbers, booleans, and functions are trivial:
			// just return the object itself since its default .toString()
			// gives us exactly what we want
			case 'number':
			case 'boolean':
			case 'function': {
				return _obj;
				break;
			}
			// for JSON format, strings need to be wrapped in quotes
			case 'string': {
				return '\'' + _obj + '\'';
				break;
			}
			case 'object': {
				var str;
				if(_obj.constructor === Array || typeof _obj.callee !== 'undefined') {
					str = '[';
					var i, len = _obj.length;
					for(i = 0; i < len-1; i++) { str += serialize(_obj[i]) + ','; }
					str += serialize(_obj[i]) + ']';
				} else {
					str = '{';
					var key;
					for(key in _obj) { str += key + ':' + serialize(_obj[key]) + ','; }
					str = str.replace(/\,$/,'') + '}';
				}
				return str;
				break;
			}
			default: {
				return 'UNKNOWN';
				break;
			}
		}
	} else {
		return 'NULL';
	}
}

function serialize(mixed_value) {
	// http://kevin.vanzonneveld.net
	// +   original by: Arpad Ray (mailto:arpad@php.net)
	// +   improved by: Dino
	// +   bugfixed by: Andrej Pavlovic
	// +   bugfixed by: Garagoth
	// %          note: We feel the main purpose of this function should be to ease the transport of data between php & js
	// %          note: Aiming for PHP-compatibility, we have to translate objects to arrays
	// *     example 1: serialize(['Kevin', 'van', 'Zonneveld']);
	// *     returns 1: 'a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}'
	// *     example 2: serialize({firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'});
	// *     returns 2: 'a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}'
	
	var _getType = function(inp) {
		var type = typeof inp, match;
		var key;
		if(type == 'object' && !inp) {
			return 'null';
		}
		if(type == "object") {
			if(!inp.constructor) {
				return 'object';
			}
			var cons = inp.constructor.toString();
			if(match = cons.match(/(\w+)\(/)) {
				cons = match[1].toLowerCase();
			}
			var types = ["boolean","number","string","array"];
			for(key in types) {
				if(cons == types[key]) {
					type = types[key];
					break;
				}
			}
		}
		return type;
	};
	var type = _getType(mixed_value);
	var val, ktype = '';
	
	switch(type) {
		case("function"): {
			val = "";
			break;
		}
		case("undefined"): {
			val = "N";
			break;
		}
		case("boolean"): {
			val = "b:" + (mixed_value ? "1" : "0");
			break;
		}
		case("number"): {
			val = (Math.round(mixed_value) == mixed_value ? "i" : "d") + ":" + mixed_value;
			break;
		}
		case("string"): {
			val = "s:" + mixed_value.length + ":\"" + mixed_value + "\"";
			break;
		}
		case("array"):
		case("object"): {
			val = "a";
			/*
			if (type == "object") {
				var objname = mixed_value.constructor.toString().match(/(\w+)\(\)/);
				if (objname == undefined) {
					return;
				}
				objname[1] = serialize(objname[1]);
				val = "O" + objname[1].substring(1, objname[1].length - 1);
			}
			*/
			var count = 0;
			var vals = "";
			var okey;
			var key;
			for(key in mixed_value) {
				ktype = _getType(mixed_value[key]);
				if(ktype == "function") {
					continue;
				}
				
				okey = (key.match(/^[0-9]+$/) ? parseInt(key) : key);
				// ((vals && vals.length && vals.length > 0 && vals.charAt((vals.length-1)) == "}")?";":"") + 
				vals += serialize(okey) + serialize(mixed_value[key]);
				count++;
			}
			val += ":" + count + ":{" + vals + "}";
			break;
		}
	}
	if(type != "object" && type != "array") val += ";";
	return val;
}

function unserialize(data){
	// http://kevin.vanzonneveld.net
	// +     original by: Arpad Ray (mailto:arpad@php.net)
	// +     improved by: Pedro Tainha (http://www.pedrotainha.com)
	// +     bugfixed by: dptr1988
	// +      revised by: d3x
	// +     improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
	// %            note: We feel the main purpose of this function should be to ease the transport of data between php & js
	// %            note: Aiming for PHP-compatibility, we have to translate objects to arrays 
	// *       example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}');
	// *       returns 1: ['Kevin', 'van', 'Zonneveld']
	// *       example 2: unserialize('a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}');
	// *       returns 2: {firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'}
	
	var error = function(type,msg,filename,line) {throw new window[type](msg,filename,line);};
	var read_until = function(data,offset,stopchr) {
		var buf = [];
		var chr = data.slice(offset,offset+1);
		var i = 2;
		while(chr != stopchr){
			if((i+offset) > data.length){
				error('Error','Invalid');
			}
			buf.push(chr);
			chr = data.slice(offset+(i-1),offset+i);
			i += 1;
		}
		return [buf.length, buf.join('')];
	};
	var read_chrs = function(data,offset,length) {
		buf = [];
		for(var i=0;i<length;i++){
			var chr = data.slice(offset+(i-1),offset+i);
			buf.push(chr);
		}
		return [buf.length,buf.join('')];
	};
	var _unserialize = function(data,offset) {
		if(!offset) offset = 0;
		var buf = [];
		var dtype = (data.slice(offset, offset + 1)).toLowerCase();
		
		var dataoffset = offset + 2;
		var typeconvert = new Function('x','return x');
		var chrs = 0;
		var datalength = 0;
		
		switch(dtype) {
			case("i"): {
				typeconvert = new Function('x','return parseInt(x)');
				var readData = read_until(data,dataoffset,';');
				var chrs = readData[0];
				var readdata = readData[1];
				dataoffset += chrs + 1;
				break;
			}
			case("b"): {
				typeconvert = new Function('x','return (parseInt(x) == 1)');
				var readData = read_until(data,dataoffset,';');
				var chrs = readData[0];
				var readdata = readData[1];
				dataoffset += chrs + 1;
				break;
			}
			case("d"): {
				typeconvert = new Function('x','return parseFloat(x)');
				var readData = read_until(data,dataoffset,';');
				var chrs = readData[0];
				var readdata = readData[1];
				dataoffset += chrs + 1;
				break;
			}
			case("n"): {
				readdata = null;
				break;
			}
			case("s"): {
				var ccount = read_until(data,dataoffset,':');
				var chrs = ccount[0];
				var stringlength = ccount[1];
				dataoffset += chrs + 2;
				
				var readData = read_chrs(data,dataoffset+1,parseInt(stringlength));
				var chrs = readData[0];
				var readdata = readData[1];
				dataoffset += chrs + 2;
				if(chrs != parseInt(stringlength) && chrs != readdata.length){
					error('SyntaxError','String length mismatch');
				}
				break;
			}
			case("a"): {
				var readdata = {};
				
				var keyandchrs = read_until(data,dataoffset,':');
				var chrs = keyandchrs[0];
				var keys = keyandchrs[1];
				dataoffset += chrs + 2;
				
				for(var i = 0;i < parseInt(keys);i++){
					var kprops = _unserialize(data,dataoffset);
					var kchrs = kprops[1];
					var key = kprops[2];
					dataoffset += kchrs;
					
					var vprops = _unserialize(data,dataoffset);
					var vchrs = vprops[1];
					var value = vprops[2];
					dataoffset += vchrs;
					
					readdata[key] = value;
				}
				dataoffset += 1;
				break;
			}
			default: {
				error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype);
				break;
			}
		}
		return [dtype,dataoffset-offset,typeconvert(readdata)];
	};
	return _unserialize(data,0)[2];
}