var chatWasOpen = 0;

// prüft, ob eine Variable definiert ist
function isDefined(variable) { 
	return variable === undefined ? false : true;
}

// ################ Chat anzeigen ##########################
	
function showChat() {
	
	initialConnect = 1;
	//overlayShow('overlay_chat', 750);
	
	// Meta-Refresh ausschalten
	window.clearInterval(timer_refresh);
	
	// Banner verstecken
	hideBanners();
	
	// Chatbubble verstecken, Chatcount auf 0 setzen
	var msgBubble = document.getElementsByName('chatBubble');
	if(msgBubble[0]!=undefined) msgBubble[0].innerHTML = '';
	
	var msgCountTitle = document.getElementsByName('chatMessageCountTitle');
	if(msgCountTitle[0]!=undefined) msgCountTitle[0].style.marginLeft = '20px';
	
	var msgCount = document.getElementsByName('chatMessageCount');
	if(msgCount[0]!=undefined) msgCount[0].innerHTML = '0';
	
	// Chat war noch nicht da -> chat_parent vom server holen und anzeigen
	if(chatWasOpen==0) {
		chatWasOpen = 1;
		
		// Overlay anzeigen
		var overlay = 'overlay_chat';
		var objWidth = 750;
		hideSelectBoxes();
		arrayPageSize = getPageSize();
		Element.setHeight('overlay_bg', arrayPageSize[1]);
		$(overlay).style.display = "block";
		$(overlay).style.zIndex = "1000";
		var arrayPageScroll = getPageScroll();
		var lightboxTop = arrayPageScroll[1] + (arrayPageSize[3] / 20);
	
		// Positionierung Abstand von oben. Mittige Positionierung über CSS?
		Element.setTop(overlay, lightboxTop);
		
		var offsetX = getWindowCenter(objWidth);
		$(overlay).style.left = offsetX+"px";
		$(overlay).style.display = "block";
		// Ende Overlay 
		
		// Shift-Taste überwachen
		document.onkeydown=shift;
		document.onkeyup=function(){shiftU=0;};
		
		var url = "/content/chat/chat_parent.php";	
		var pars = "";
		
		//pdisconnectChat();
		var myAjax = new Ajax.Request(
				url, 
				{
					method: 'post', 
					parameters: pars, 
					onComplete: showChatContent
				});
				
	// Chat war schon da-> nur Fenster wieder einblenden
	} else {
		document.getElementById('overlay_chat').style.display = 'block';
		chatframe.chat.connect();
		chatframe.focusChatWindow();
	}
	
	var chatBanner = document.getElementById('chatBanner')
	if(chatBanner!=undefined) chatBanner.style.display='block';
}

function hideChat() {
	
	chatframe.chat.isRunning = false;
	
	if(typeof(chatframe.chat.http_request) == 'object') {
		window.clearInterval(chatframe.chat.timer_FFCheck);	
		if(navigator.userAgent.indexOf('MSIE') == -1 || window.opera) {
			chatframe.chat.http_request.abort();
		}
	}
		
	// Meta-Refresh einschalten
	if(typeof(timer_refresh)=='number') {
		timer_refresh = window.setInterval(reload, 10000);
	}
	
	// Banner anzeigen
	document.getElementById('chatBanner').style.display='none';
	
	// Shift-Taste nicht mehr überwachen
	document.onkeydown=null;
	document.onkeyup=null;
	
	//overlayHide('overlay_chat');
	//document.getElementById('overlay_chat').innerHTML = '';
	
	document.getElementById('overlay_chat').style.display='none';
	showSelectBoxes();
	showBanners();

}

function showChatContent(Request) {
		document.getElementById('overlay_chat').innerHTML= Request.responseText;
	}

// #################### Chat-Klasse ##############################
var chat = {
    domain: "",
    path: "/content/chat/ajax_chat.php",
    url: '',
    pars: '',
    browser: 'other',					// 'other' oder 'IE'
    debug: 0,
    isRunning: false,					// wird beim Connect/Schließen des Layers gesetzt und bestimmt, ob automatisch reconnected wird
    iframe: null,
    timer_IECheck: null,
    timer_FFCheck: null,
    timer_PushCheck: null,
    http_request: null,
    http_request_startpos: 0,
    connectionType: 'push',
    connectionVerified: false,
    connectionCount: 0,				// wie oft eine Verbindung neu aufgebaut wurde
    connectionReadCount: 0,				// Wie oft die bestehende Verbindung schon ausgelesen wurde
    stream_isInitial: 1,
    stream_duration: 10,					// Dauer der Stream-Antwort
    stream_waitCycle_ms: 1000,			// Verzögerung zwischen den Stream-Teilen in Millisekunden
    pull_duration: 0,					// im Fehlerfall (switch auf Pull) wird auf diesen Wert gewechselt
    pull_waitCycle_ms: 2000,			// im Fehlerfall (switch auf Pull) wird auf diesen Wert gewechselt
    push_duration: 60,					// in Sekunden
    push_waitCycle_ms: 1000,
    checkPushConnection_ms: 8000,
    responseCheck_ms: 1000,
    lastUserIds: 0,
    lastDirection: '',
    php: new PHP_Serializer(),
    
	connect: function() {		
		
		// CSS für Safari fies umbiegen
		if(!this.isRunning) {
			if(navigator.userAgent.indexOf('Safari') != -1) {
				this.browser = "Safari";
				parent.document.getElementById('touid').style.top = '-7px';
				parent.document.getElementById('message').style.width = '705px';
			}
		}
		
		this.isRunning = true;
		
		// Firefox
		if(navigator.userAgent.indexOf('MSIE') == -1 || window.opera) {
			this.rebuildURL();
			
			this.http_request_startpos = 0;
			
			this.http_request = new XMLHttpRequest();			
			this.http_request.onreadystatechange = this.disconnect;		// wird nach Seitenende ausgeführt
			
			//this.debugInfo(this.url);
			this.http_request.open('GET', this.url, true);
			this.http_request.send(null);
			
			// Timer für Antwortüberwachung Firefox & Opera starten
			this.timer_FFCheck = window.setInterval(this.checkFFResponse, this.responseCheck_ms);
			
			//this.debugInfo('connect() on FireFox');
			
		// IE
		} else {
			this.browser = 'IE';
			this.rebuildURL();
			
			// Div erzeugen
			
			
			// I-Frame erzeugen
			var tempIFrame=document.createElement('iframe');
			tempIFrame.setAttribute('id','ieframe');
			tempIFrame.style.border='0px';
			tempIFrame.style.width='0px';
			tempIFrame.style.height='0px';
			this.iframe = document.body.appendChild(tempIFrame);
			
			
		    	this.iframe.src = this.url;
		    	this.iframe.onload = this.disconnectIE;
		    	// TODO !!
		    	this.timer_IECheck = window.setInterval(this.checkIEIFrame, this.responseCheck_ms);
			
			//this.debugInfo('connect() on IE');
		}
		
		this.connectionVerified = false;
		
		//DEBUG
		this.connectionCount++;
		this.connectionReadCount = 0;
		this.updateDebugStatus();
		
		this.stream_isInitial = 0;
		
		// Push-Verbindung überprüfen
		if(this.connectionType=="push") {
			this.timer_PushCheck = window.setInterval(this.checkPushConnection, this.checkPushConnection_ms);
		}

	},
	
	handleResponse: function(Response) {		
		if(Response!='') {
			//chat.connectionVerified = true;			
			//chat.debugInfo('Response: '+Response);
			
			responseArray = Response.split('\\n');
			for(var j = 0; j < responseArray.length; j++) {
				if(responseArray[j][0]!=" " && responseArray[j]!="") {
					// DEBUG
					if(this.debug==1) {
						parent.document.getElementById('stream').innerHTML = Response;
					}
					
					umsg = chat.php.unserialize(responseArray[j]);
	
					msgs = umsg[0];
					users = umsg[1];
									
					//chat.contentInfo('ra: '+umsg);
					//chat.contentInfo('txt: '+php.unserialize('a:2:{i:0;a:1:{i:0;a:5:{i:0;i:0;i:1;s:6:"System";i:2;s:20:"22.Jun.2007 13:26:57";i:3;i:0;i:4;s:22:"connectionVerification";}}i:1;a:0:{}}'));
			
					// wenn vorhanden, Infos über angemeldete User abgreifen
					fillChatSelect(users);		
					
					// wenn vorhanden, Message ausgeben
					if(msgs.length > 0) {												
						for (var i = 0; i < msgs.length; i++) {
							//this.debugInfo(msgs[i][4]+'-'+msgs[i][0])
							// Ausgabe erfolg nur, wenn es kein Verbindungstest ist
							if(!(msgs[i][4]=='connectionVerification' && msgs[i][0]==0)) {
								//document.getElementById('output').innerHTML += msgs[i][4].replace(/\n/g, '<br>') + '<br />';	

								chat.contentInfo(msgs[i]);
								focusChatWindow();
								
							} else {
								chat.connectionVerified = true;
												
								// DEBUG
								parent.document.getElementById('connectionVerified').innerHTML = chat.connectionVerified;
							}
						}
					}
				}
			}
		}
	},
	
	checkIEIFrame: function() {				// regelm. prüfen, ob die IE-Connection nicht schon beendet wurde
		//chat.debugInfo('checkIEIFrame');
		
		//DEBUG
		chat.connectionReadCount++;
		chat.updateDebugStatus();
		
		if(chat.iframe.readyState=='complete') chat.disconnectIE();
	},
	
	checkFFResponse: function() {
		//chat.debugInfo('checkFFResponse');
		
		//DEBUG
		chat.connectionReadCount++;
		chat.updateDebugStatus();
		
		var txt = chat.http_request.responseText;
		var pos = txt.length-1;
		
		// CHANGED
		//parent.document.getElementById('stream').innerHTML = txt;
		//chat.debugInfo('pos: '+pos);
		
		if(pos >= chat.http_request_startpos-1) {
			var newstring = txt.substring(chat.http_request_startpos);	
			chat.handleResponse(newstring);					
			chat.http_request_startpos = pos+1;		
		}
	},
	
	disconnect: function(Request) {					// FF-disconnect	
		if(isDefined("chat")) {
			chat.updateDebugStatus();
			if (chat.http_request.readyState == 4) {
				//chat.debugInfo('disconnect()');
				chat.updateDebugStatus();
				//chat.debugInfo('State 4');
				if (chat.http_request.status == 200) {	
					window.clearInterval(chat.timer_FFCheck);	
					chat.checkFFResponse();
					chat.http_request.abort();
					//chat.updateDebugStatus();
					//chat.http_request.close();
					if(chat.isRunning) chat.reconnect();
				} else {
					window.clearInterval(chat.timer_FFCheck);
					
					// CHANGED
					chat.http_request.abort();
					if(chat.isRunning) chat.reconnect();
				}				
			}
		}
	},
	
	disconnectIE: function() {				// IE disconnect
		//chat.debugInfo('disconnectIE()');
		//chat.debugInfo(escape(chat.iframe.innerHTML));
		
		window.clearInterval(chat.timer_IECheck);
		
		if(chat.isRunning) chat.reconnectIE();
	},
	
	reconnect: function() {
		//this.debugInfo('reconnect()');
		this.connect();
	},
	
	reconnectIE: function() {
		//this.debugInfo('reconnectIE');
		
		this.rebuildURL();
		
		this.iframe.src = this.url;
		this.timer_IECheck = window.setInterval(this.checkIEIFrame, this.responseCheck_ms);
	},
	
	rebuildURL: function() {
		this.pars = '?sii='+this.stream_isInitial+'&sd='+this.stream_duration+'&swc='+this.stream_waitCycle_ms+'&b='+this.browser+'&lastuids='+this.lastUserIds+'&lastdir='+this.lastDirection;
		this.url = this.domain+this.path+this.pars;
	},
	
	checkPushConnection: function() {
		//chat.debugInfo('checkPushConnection');
		window.clearInterval(chat.timer_PushCheck);
		
		// Verifizierung fehlgeschlagen
		if(!chat.connectionVerified) {			
			//chat.debugInfo('switched to Pull-Connection');
			chat.connectionType = 'pull';
			
			//DEBUG
			chat.updateDebugStatus();
			
			chat.stream_duration = chat.pull_duration;
			chat.stream_waitCycle_ms = chat.pull_waitCycle_ms;
			
			if(chat.browser!='IE') {
				// CHANGED
				//chat.http_request.abort();
				chat.disconnect();
			} else {
				chatframe.location.href = "about:empty";
			}
			
		// Verifizierung ok
		} else {
			chat.stream_duration = chat.push_duration;				// bei erfolgreicher Verbindung Stream-Dauer erhöhen
			chat.stream_waitCycle_ms = chat.push_waitCycle_ms;
			chat.connectionVerified = true;					// Bei neuer Verbindung, Verbindung neu überprüfen
		}
		
		// DEBUG
		chat.updateDebugStatus();
	},
	
	
	// Nachricht senden
	sendMessage: function(message, touid) {
		if(!message) {
			message = parent.document.getElementById('message').value;
		}
		
		// kein Empfänger -> Nachricht an alle
		if(touid=='') {
			alert('Bitte wähle mindestens einen Empfänger für deine Nachricht aus. Durch Drücken von STRG kannst du mehrere Empfänger für deine Nachricht auswählen.');
			/* default: Versand an alle
			selectbox = parent.document.getElementById("touid");
			for (var i = selectbox.options.length-1; i >= 0 ; i--) {
				// Trennzeichen hinzufügen, wenn schon Werte vorhanden sind
				if(touid!='') touid += ',';
				touid += selectbox.options[i].value;
			}
			*/
		}

		if(touid!='' && message!='') {
			// Nachricht mit ausschließlich Returnzeichen nicht übtermitteln
			if(!(message.length==1 && message.charCodeAt(0)==10)) {
				var url = "/content/chat/ajax_chatSend.php";	
				var msg = escape(message);
				var pars = "message="+msg+'&touid='+touid+'&lastuids='+this.lastUserIds+'&lastdir='+this.lastDirection;
				
				parent.document.getElementById('message').value = '';
				//parent.document.getElementById('message').value = url+'?'+pars;
				
				var myAjax = new Ajax.Request(
						url, 
						{
							method: 'post', 
							parameters: pars, 
							onComplete: this.showMessageSent
						});
						
			// stattdessen das Feld wieder leeren
			} else {
				parent.document.getElementById('message').value = '';
			}			
		}
	},
	
	// gesendete Nachricht ausgeben
	showMessageSent: function(Request) {
		chat.handleResponse(Request.responseText);
	},
	
	toggleDebugging: function() {
		if(this.debug==0) {
			this.debug=1;
			parent.document.getElementById('debuginfos').style.display='inline';
		}
		else {
			this.debug=0;		
			parent.document.getElementById('debuginfos').style.display='none';
		}
	},
	
	debugInfo: function(message) {
		if(this.debug==1) {
			document.getElementById('output').innerHTML += 'DEBUG: '+ message +'<br />';
		}
	},
	
	updateDebugStatus: function() {
		if(this.debug==1) {
			parent.document.getElementById('url').innerHTML = this.url;
			parent.document.getElementById('readyState').innerHTML = this.http_request.readyState;
			parent.document.getElementById('requestStatus').innerHTML = this.http_request.status;
			parent.document.getElementById('connectionType').innerHTML = this.connectionType;
			parent.document.getElementById('connectionVerified').innerHTML = this.connectionVerified;
			parent.document.getElementById('connectionCount').innerHTML = this.connectionCount;
			parent.document.getElementById('connectionReadCount').innerHTML = this.connectionReadCount;
			parent.document.getElementById('stream_duration').innerHTML = this.stream_duration;
			parent.document.getElementById('stream_waitCycle_ms').innerHTML = this.stream_waitCycle_ms;
		}
	},
	
	// Nachrichten darstellen
	contentInfo: function(message) {			// Content ausgeben
				
		msghtml = '';
		message[4] = message[4].replace(/\n/g, '<br>');
		
		// ausgehende Nachrichten
		if(message[5] == 'out') {
			if(message[0].length > 0) {
				// Neue ausgehende Nachricht
				if(String(this.lastUserIds) != String(message[0]) || String(this.lastDirection) != 'out') {
					msghtml += "<div class='chat_out'><span style='float:right; margin:0 5px 0 0;'>"+message[2]+"</span><span class='chat_user'><b>"+message[6]+"</b> <img src='/img/ic_chat_out.gif' /> <a style='text-decoration:none; color:#fff;' href=\"javascript:selectChatPartner('"+message[0]+"');\">"+message[1]+"</a></span></div>";
				// ausgehende Nachricht fortführen
				} else {
					msghtml += "<div class='chat_outthin'><span style='float:right; margin:0 5px 0 0;'>"+message[2]+"</span><span class='chat_user'>&nbsp;</span></div>";
				}
			 msghtml += "<div style='font-size:10px;'>"+message[4]+"</div>";
			 
			 // letzen User merken
			 this.lastUserIds = message[0];
			}
			
		// eingehende Nachrichten
		} else if(message[5] == 'in') {
			if(message[0].length > 0) {
				
				// Eingangssound abspielen
				if(chat_sound==1) msgSoundPlay();
				
				// Neue eingehende Nachricht
				if(String(this.lastUserIds) != String(message[7]) || String(this.lastDirection) != 'in') {
					msghtml += "<div class='chat_in'><span style='float:right; margin:0 5px 0 0;'>"+message[2]+"</span><span class='chat_user'><a style='text-decoration:none; color:#fff; font-weight:bold;' href=\"javascript:selectChatPartner('"+message[7]+"');\">"+message[6]+"</a> <img src='/img/ic_chat_out.gif' /> <a style='text-decoration:none; color:#fff; font-weight:bold;' href=\"javascript:selectChatPartner('"+message[0]+"');\">"+message[1]+"</a></span></div>";
				// eingehende Nachricht fortführen
				} else {
					msghtml += "<div class='chat_inthin'><span style='float:right; margin:0 5px 0 0;'>"+message[2]+"</span><span class='chat_user'>&nbsp;</span></div>";
				}
			 msghtml += "<div style='font-size:10px;'>"+message[4]+"</div>";
			 
			 // letzen User merken
			 this.lastUserIds = message[7];
			}
		}
		
		// neuen LastUer/Direction setzen
		this.lastDirection = message[5];
		
		/*
		parent.document.getElementById('lastUserIsd').innerHTML = this.lastUserIds;
		parent.document.getElementById('lastDirection').innerHTML = this.lastDirection;
		*/
								
		document.getElementById('output').innerHTML += msghtml +'<br />';
	}
	
};

// ####################### Funktionen #######################################

// Shift-Taste überwachen
var shiftU=0;
function shift(e){
	if(!e)e=window.event;
	key = (e.which) ? e.which : e.keyCode;
	if (key==16)shiftU=1;
}

// prüft die Eingabe auf Returns
function checkChatInput(e) {
	var keynum;
	var keychar;
	var numcheck;
	
	if(window.event) // IE
	{
		keynum = e.keyCode;
	}
	else if(e.which) // Netscape/Firefox/Opera
	{
		keynum = e.which;
	}
	
	// Bei Return-> abschicken, es sei denn Shift ist gedrückt

	if(keynum==13 && shiftU==0) {
		var message = document.getElementById('message').value;
		var mlength = message.length;
		
		if(message.charCodeAt(message.length-1)==10) {
			message = message.substr(0, message.length-1);
		}
		if(message.charCodeAt(message.length-1)==13) {
			message = message.substr(0, message.length-1);
		}
		
		chatframe.chat.sendMessage(message, getMultiple(document.getElementById('touid')));
		return false;
	} else return true;
}

function selectChatPartner(user_id) {
	var userid_hit = 0;
	var user_id = user_id.split(',');

	selectbox = parent.document.getElementById("touid");

	for (var i = selectbox.options.length-1; i >= 0 ; i--) {
		
		// alte Markierungen merken
		userid_hit = 0;
		for (var j = 0; j < user_id.length; j++) {
			if(selectbox.options[i].value == user_id[j]) {
				selectbox.options[i].selected = true;
				userid_hit = 1;
			} 
		}
		if(userid_hit==0) {
			selectbox.options[i].selected = false;
		}
	}
}

function getMultiple(ob) { 
	var arSelected = new Array();
	var tmpArray = new Array();
	
	while (ob.selectedIndex != -1) {
		arSelected.push(ob.options[ob.selectedIndex].value); 
		tmpArray.push(ob.options[ob.selectedIndex].index); 
		ob.options[ob.selectedIndex].selected = false; 
	}
	for(i=0; i<tmpArray.length; i++) {
		ob.options[tmpArray[i]].selected = true;
	}
	return arSelected;
}

var windowlen = 0;

function focusChatWindow() {
	var bodystr = document.body.innerHTML;
	var len = bodystr.length;
	
	if(len >= windowlen) {
		window.scrollTo(0, 9000000);
		
		/*
		document.getElementById('bottom').focus();	
		windowlen = len+1;	
		*/
	}
}


var tmpSelectedUsers = new Array();

// Selectbox mit Usern im Parentfenster neu befüllen
function fillChatSelect(users) {
	
	// ... leeren
	selectbox = parent.document.getElementById("touid");
	for (var i = selectbox.options.length-1; i >= 0 ; i--) {
		
		// alte Markierungen merken
		if(selectbox.options[i].selected) {
			tmpSelectedUsers.push(selectbox.options[i].value);
		}
		selectbox.remove(i);
	}

	// ... neu befüllen	
	for (var i = 0; i < users.length; i++) {
		var user = users[i];
		var isSelected = false;
		
		for(var k = 0; k < tmpSelectedUsers.length; k++) {
			if(user[0] == tmpSelectedUsers[k]) {
				isSelected = true;
			}
		}
		
		selectbox.options[i] = new Option(user[1], user[0], false, isSelected);
	}

	// tmp-Variable wieder löschen
	tmpSelectedUsers = new Array();
}

// Sounds
var soundEmbed = null;
					
function msgSoundPlay() {
	msgSoundStop();
	soundEmbed = document.createElement("embed");
	soundEmbed.setAttribute("src", "/audio/purr.wav");
	soundEmbed.setAttribute("hidden", true);
	soundEmbed.setAttribute("autostart", true);
	document.body.appendChild(soundEmbed);
}

function msgSoundStop() {
	if ( soundEmbed ) {
		document.body.removeChild(soundEmbed);
		soundEmbed = null;
	}
}

function soundOn() {
	chat_sound = 1;
	
	var url = "/content/chat/ajax_sound.php";	
	var pars = "state=1";
	
	//pdisconnectChat();
	var myAjax = new Ajax.Updater(
			{success: 'soundFlag'},
			url, 
			{
				method: 'post', 
				parameters: pars,
				onFailure: reportError,
				encoding: 'iso-8859-1'
			});
}

function soundOff() {
	chat_sound = 0;
	
	var url = "/content/chat/ajax_sound.php";	
	var pars = "state=0";
	
	//pdisconnectChat();
	var myAjax = new Ajax.Updater(
			{success: 'soundFlag'},
			url, 
			{
				method: 'post', 
				parameters: pars,
				onFailure: reportError,
				encoding: 'iso-8859-1'
			});
}

/**
 * Object PHP_Serializer
 * 	JavaScript to PHP serialize / unserialize class.
 * This class converts php variables to javascript and vice versa.
 *
 * PARSABLE JAVASCRIPT < === > PHP VARIABLES:
 *	[ JAVASCRIPT TYPE ]		[ PHP TYPE ]
 *	Array		< === > 	array
 *	Object		< === > 	class (*)
 *	String		< === > 	string
 *	Boolean		< === > 	boolean
 *	null		< === > 	null
 *	Number		< === > 	int or double
 *	Date		< === > 	class
 *	Error		< === > 	class
 *	Function	< === > 	class (*)
 *
 * (*) NOTE:
 * Any PHP serialized class requires the native PHP class to be used, then it's not a
 * PHP => JavaScript converter, it's just a usefull serilizer class for each
 * compatible JS and PHP variable types.
 * Lambda, Resources or other dedicated PHP variables are not usefull for JavaScript.
 * There are same restrictions for javascript functions*** too then these will not be sent.
 *
 * *** function test(); alert(php.serialize(test)); will be empty string but
 * *** mytest = new test(); will be sent as test class to php
 * _____________________________________________
 *
 * EXAMPLE:
 *	var php = new PHP_Serializer(); // use new PHP_Serializer(true); to enable UTF8 compatibility
 *	alert(php.unserialize(php.serialize(somevar)));
 *	// should alert the original value of somevar
 * ---------------------------------------------
 * @author              Andrea Giammarchi
 * @site		www.devpro.it
 * @date                2005/11/26
 * @lastmod             2006/05/15 19:00 [modified stringBytes method and removed replace for UTF8 and \r\n]
 * 			[add UTF8 var again, PHP strings if are not encoded with utf8_encode aren't compatible with this object]
 *			[Partially rewrote for a better stability and compatibility with Safari or KDE based browsers]
 *			[UTF-8 now has a native support, strings are converted automatically with ISO or UTF-8 charset]
 *
 * @specialthanks	Fabio Sutto, Kentaromiura, Kroc Camen, Cecile Maigrot, John C.Scott, Matteo Galli
 *
 * @version             2.2, tested on FF 1.0, 1.5, IE 5, 5.5, 6, 7 beta 2, Opera 8.5, Konqueror 3.5, Safari 2.0.3
 */
function PHP_Serializer(UTF8) {
	
	/** public methods */
	function serialize(v) {
		// returns serialized var
		var	s;
		switch(v) {
			case null:
				s = "N;";
				break;
			default:
				s = this[this.__sc2s(v)] ? this[this.__sc2s(v)](v) : this[this.__sc2s(__o)](v);
				break;
		};
		return s;
	};
	
	function unserialize(s) {
		// returns unserialized var from a php serialized string
		__c = 0;
		__s = s;
		//alert(__s.substr(__c, 1));
		return this[__s.substr(__c, 1)]();
	};
	
	function stringBytes(s) {
		// returns the php lenght of a string (chars, not bytes)
		return s.length;
	};
	
	function stringBytesUTF8(s) {
		// returns the php lenght of a string (bytes, not chars)
		var 	c, b = 0,
			l = s.length;
		while(l) {
			c = s.charCodeAt(--l);
			b += (c < 128) ? 1 : ((c < 2048) ? 2 : ((c < 65536) ? 3 : 4));
		};
		return b;
	};
	
	/** private methods */
	function __sc2s(v) {
		return v.constructor.toString();
	};
	
	function __sc2sKonqueror(v) {
		var	f;
		switch(typeof(v)) {
			case ("string" || v instanceof String):
				f = "__sString";
				break;
			case ("number" || v instanceof Number):
				f = "__sNumber";
				break;
			case ("boolean" || v instanceof Boolean):
				f = "__sBoolean";
				break;
			case ("function" || v instanceof Function):
				f = "__sFunction";
				break;
			default:
				f = (v instanceof Array) ? "__sArray" : "__sObject";
				break;
		};
		return f;
	};
	
	function __sNConstructor(c) {
		return (c === "[function]" || c === "(Internal Function)");
	};
	
	function __sCommonAO(v) {
		var	b, n,
			a = 0,
			s = [];
		for(b in v) {
			n = v[b] == null;
			if(n || v[b].constructor != Function) {
				s[a] = [
					(!isNaN(b) && parseInt(b).toString() === b ? this.__sNumber(b) : this.__sString(b)),
					(n ? "N;" : this[this.__sc2s(v[b])] ? this[this.__sc2s(v[b])](v[b]) : this[this.__sc2s(__o)](v[b]))
				].join("");
				++a;
			};
		};
		return [a, s.join("")];
	};
	
	function __sBoolean(v) {
		return ["b:", (v ? "1" : "0"), ";"].join("");
	};
	
	function __sNumber(v) {
		var 	s = v.toString();
		return (s.indexOf(".") < 0 ? ["i:", s, ";"] : ["d:", s, ";"]).join("");
	};
	
	function __sString(v) {
		return ["s:", v.length, ":\"", v, "\";"].join("");
	};
	
	function __sStringUTF8(v) {
		return ["s:", this.stringBytes(v), ":\"", v, "\";"].join("");
	};
	
	function __sArray(v) {
		var 	s = this.__sCommonAO(v);
		return ["a:", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sObject(v) {
		var 	o = this.__sc2s(v),
			n = o.substr(__n, (o.indexOf("(") - __n)),
			s = this.__sCommonAO(v);
		return ["O:", this.stringBytes(n), ":\"", n, "\":", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sObjectIE7(v) {
		var 	o = this.__sc2s(v),
			n = o.substr(__n, (o.indexOf("(") - __n)),
			s = this.__sCommonAO(v);
		if(n.charAt(0) === " ")
			n = n.substring(1);
		return ["O:", this.stringBytes(n), ":\"", n, "\":", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sObjectKonqueror(v) {
		var	o = v.constructor.toString(),
			n = this.__sNConstructor(o) ? "Object" : o.substr(__n, (o.indexOf("(") - __n)),
			s = this.__sCommonAO(v);
		return ["O:", this.stringBytes(n), ":\"", n, "\":", s[0], ":{", s[1], "}"].join("");
	};
	
	function __sFunction(v) {
		return "";
	};
	
	function __uCommonAO(tmp) {
		var	a, k;
		++__c;
		a = __s.indexOf(":", ++__c);
		k = parseInt(__s.substr(__c, (a - __c))) + 1;
		__c = a + 2;
		while(--k)
			tmp[this[__s.substr(__c, 1)]()] = this[__s.substr(__c, 1)]();
		return tmp;
	};

	function __uBoolean() {
		var	b = __s.substr((__c + 2), 1) === "1" ? true : false;
		__c += 4;
		return b;
	};
	
	function __uNumber() {
		var	sli = __s.indexOf(";", (__c + 1)) - 2,
			n = Number(__s.substr((__c + 2), (sli - __c)));
		__c = sli + 3;
		return n;
	};
	
	function __uStringUTF8() {
		var 	c, sls, sli, vls,
			pos = 0;
		__c += 2;
		sls = __s.substr(__c, (__s.indexOf(":", __c) - __c));
		sli = parseInt(sls);
		vls = sls = __c + sls.length + 2;
		while(sli) {
			c = __s.charCodeAt(vls);
			pos += (c < 128) ? 1 : ((c < 2048) ? 2 : ((c < 65536) ? 3 : 4));
			++vls;
			if(pos === sli)
				sli = 0;
		};
		pos = (vls - sls);
		__c = sls + pos + 2;
		return __s.substr(sls, pos);
	};
	
	function __uString() {
		var 	sls, sli;
		__c += 2;
		sls = __s.substr(__c, (__s.indexOf(":", __c) - __c));
		sli = parseInt(sls);
		sls = __c + sls.length + 2;
		__c = sls + sli + 2;
		return __s.substr(sls, sli);
	};
	
	function __uArray() {
		var	a = this.__uCommonAO([]);
		++__c;
		return a;
	};
	
	function __uObject() {
		var 	tmp = ["s", __s.substr(++__c, (__s.indexOf(":", (__c + 3)) - __c))].join(""),
			a = tmp.indexOf("\""),
			l = tmp.length - 2,
			o = tmp.substr((a + 1), (l - a));
		if(eval(["typeof(", o, ") === 'undefined'"].join("")))
			eval(["function ", o, "(){};"].join(""));
		__c += l;
		eval(["tmp = this.__uCommonAO(new ", o, "());"].join(""));
		++__c;
		return tmp;
	};
	
	function __uNull() {
		__c += 2;
		return null;
	};
	
	function __constructorCutLength() {
		function ie7bugCheck(){};
		var	o1 = new ie7bugCheck(),
			o2 = new Object(),
			c1 = __sc2s(o1),
			c2 = __sc2s(o2);
		if(c1.charAt(0) !== c2.charAt(0))
			__ie7 = true;
		return (__ie7 || c2.indexOf("(") !== 16) ? 9 : 10;
	};
	
	/** private variables */
	var 	__c = 0,
		__ie7 = false,
		__b = __sNConstructor(__c.constructor.toString()),
		__n = __b ? 9 : __constructorCutLength(),
		__s = "",
		__a = [],
		__o = {},
		__f = function(){};
	
	/** public prototypes */
	PHP_Serializer.prototype.serialize = serialize;
	PHP_Serializer.prototype.unserialize = unserialize;
	PHP_Serializer.prototype.stringBytes = UTF8 ? stringBytesUTF8 : stringBytes;
	
	/** serialize: private prototypes */
	if(__b) { // Konqueror / Safari prototypes
		PHP_Serializer.prototype.__sc2s = __sc2sKonqueror;
		PHP_Serializer.prototype.__sNConstructor = __sNConstructor;
		PHP_Serializer.prototype.__sCommonAO = __sCommonAO;
		PHP_Serializer.prototype[__sc2sKonqueror(__b)] = __sBoolean;
		PHP_Serializer.prototype.__sNumber = 
		PHP_Serializer.prototype[__sc2sKonqueror(__n)] = __sNumber;
		PHP_Serializer.prototype.__sString = PHP_Serializer.prototype[__sc2sKonqueror(__s)] = UTF8 ? __sStringUTF8 : __sString;
		PHP_Serializer.prototype[__sc2sKonqueror(__a)] = __sArray;
		PHP_Serializer.prototype[__sc2sKonqueror(__o)] = __sObjectKonqueror;
		PHP_Serializer.prototype[__sc2sKonqueror(__f)] = __sFunction;
	}
	else { // FireFox, IE, Opera prototypes
		PHP_Serializer.prototype.__sc2s = __sc2s;
		PHP_Serializer.prototype.__sCommonAO = __sCommonAO;
		PHP_Serializer.prototype[__sc2s(__b)] = __sBoolean;
		PHP_Serializer.prototype.__sNumber = 
		PHP_Serializer.prototype[__sc2s(__n)] = __sNumber;
		PHP_Serializer.prototype.__sString = PHP_Serializer.prototype[__sc2s(__s)] = UTF8 ? __sStringUTF8 : __sString;
		PHP_Serializer.prototype[__sc2s(__a)] = __sArray;
		PHP_Serializer.prototype[__sc2s(__o)] = __ie7 ? __sObjectIE7 : __sObject;
		PHP_Serializer.prototype[__sc2s(__f)] = __sFunction;
	};
	
	/** unserialize: private prototypes */
	PHP_Serializer.prototype.__uCommonAO = __uCommonAO;
	PHP_Serializer.prototype.b = __uBoolean;
	PHP_Serializer.prototype.i =
	PHP_Serializer.prototype.d = __uNumber;
	PHP_Serializer.prototype.s = UTF8 ? __uStringUTF8 : __uString;
	PHP_Serializer.prototype.a = __uArray;
	PHP_Serializer.prototype.O = __uObject;
	PHP_Serializer.prototype.N = __uNull;
}; 
   

function utf8_encode(string) {  
 string = string.replace(/\r\n/g,"\n");  
 var utftext = "";  

 for (var n = 0; n < string.length; n++) {  

     var c = string.charCodeAt(n);  

     if (c < 128) {  
         utftext += String.fromCharCode(c);  
     }  
     else if((c > 127) && (c < 2048)) {  
         utftext += String.fromCharCode((c >> 6) | 192);  
         utftext += String.fromCharCode((c & 63) | 128);  
     }  
     else {  
         utftext += String.fromCharCode((c >> 12) | 224);  
         utftext += String.fromCharCode(((c >> 6) & 63) | 128);  
         utftext += String.fromCharCode((c & 63) | 128);  
     }  

 }  

 return utftext;  
} 
   
function utf8_decode(utftext) {  
 var string = "";  
 var i = 0;  
 var c = c1 = c2 = 0;  

 while ( i < utftext.length ) {  

     c = utftext.charCodeAt(i);  

     if (c < 128) {  
         string += String.fromCharCode(c);  
         i++;  
     }  
     else if((c > 191) && (c < 224)) {  
         c2 = utftext.charCodeAt(i+1);  
         string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));  
         i += 2;  
     }  
     else {  
         c2 = utftext.charCodeAt(i+1);  
         c3 = utftext.charCodeAt(i+2);  
         string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));  
         i += 3;  
     }  

 }  

 return string;  
}  