
function XMPPHandler() {
	var domain = 'www.synmarket.de';
    var httpBind = 'http://www.synaxon.de/http-bind/';
    var authType = 'saslanon';

	var pageName =  document.title;
	// attributes for scrolling title
	var scrollingMsg = "";
	var pos = 0;
	var spacer = " ... ";
	var time_length = 150;
	var stop = false;
	var c = 0;
  
 
    this.load = function () {
        //init the shitty logger, because we need it, it is the chat you know
        if (typeof(Debugger) == 'function') {
			oDbg = new Debugger(1,'simpleclient');
			oDbg.start();
		} else {
			// if you're using firebug or safari, use this for debugging
			oDbg = new JSJaCConsoleLogger(2);
		}
    }
    
    // call this method on page unload
    this.unload = function () {
	 // writes the togglestate of the roster into a cookie
	 try{
		(new JSJaCCookie('rosterState',jQuery('#buddyContainer').css("display"))).write();
	  } catch (e) {}
	  
	  if (typeof con != 'undefined' && con && con.connected()) {
        // save backend type
	    if (con._hold){ 
	      // must be binding, don't change this value'
	      (new JSJaCCookie('btype','binding')).write();
	    }
	    if (con.suspend) {
	      con.suspend(); 
	    }
	  }
  
	  // tabnames persistence
	  var tabnames = jQuery('.ui-tabs-nav li a');
	  var names = new Array();
	  jQuery.each(tabnames, function(index, value) {
		if(value != null){
			var conversationId = value.hash.replace('#','');
			names[index] = conversationId  + '@' + con.domain;
		}
	  });
	  // write the names into a cookie
	  if(names.length > 0){
		var tabsToSave = new TabPersistence();
		// selected Tab
		tabsToSave.selectedTab = tabulatoren.tabs('option', 'selected');
		tabsToSave.alltabs = names;
		// transform object to json and save it in a cookie 
		(new JSJaCCookie('conversations', escape(JSJaCJSON.toString(tabsToSave)))).write();
	  }else {
		  // removes conversations cookie and ignores exceptions
		  try{
			JSJaCCookie.read('conversations').erase();
		  } catch (e) {}
	  }
	  
	  // save the chatbox status (hidden or visible)
	  // in a cookie
      (new JSJaCCookie('display',tabulatoren.css('display'))).write();
    }
    
    function setupCon(con) {
	    con.registerHandler('message',handleMessage);
	    con.registerHandler('presence',handlePresence);
	    con.registerHandler('iq',handleIQ);
	    con.registerHandler('onconnect',handleConnected);
	    con.registerHandler('onerror',handleError);
	    con.registerHandler('status_changed',handleStatusChanged);
	    con.registerHandler('ondisconnect',handleDisconnected);
	    con.registerIQGet('query', NS_VERSION, handleIqVersion);
	    con.registerIQGet('query', NS_TIME, handleIqTime);
    }
    
    XMPPHandler.anonymousLogin = function () {
        try {
			if (typeof con == 'undefined' || !con || !con.connected()){
			   var creds = XMPPHandler.encode('anonymous') + ',' + XMPPHandler.encode('anonymous');
			   //var creds = XMPPHandler.encode('test') + ',' + XMPPHandler.encode('test');
			   (new JSJaCCookie('credentials',creds)).write();

			   oArgs = new Object();
			   // setup username and password
			   oArgs.username = 'anonymous';
			   oArgs.pass =  'anonymous'; 
			   // further setup args for connect method
			   oArgs.resource = 'synaxonhomepage';
			   oArgs.httpbase = httpBind;
			   oArgs.timerval = 2000;
			   oArgs.authtype = 'saslanon'; //'nonsasl';
			   oArgs.domain = domain;
				
			   if (typeof(oDbg) != 'undefined'){
				 oArgs.oDbg = oDbg;
			   }
			   // use httpbinding
			   con = new JSJaCHttpBindingConnection(oArgs);
				
			   setupCon(con);
			   con.connect(oArgs);
			}
		 } catch (e) {}
		   finally {
		     return false;
		 }
   }
    
    this.logout = function() {
	  if (typeof con != 'undefined' && con && con.connected()){
		  var p = new JSJaCPresence();
		  p.setType("unavailable");
		  con.send(p);
		  con.disconnect();
	  }
	  
	  // removes all cookies and ignores exceptions
	  try{
        JSJaCCookie.read('btype').erase();
		JSJaCCookie.read('conversations').erase();
		JSJaCCookie.read('credentials').erase();
		JSJaCCookie.read('display').erase();
	  } catch (e) {}
	  jQuery('#chatWrapper').children().remove();

    }
    
    this.init = function () {
        this.load();
		
		//register some events due stop title scrolling  
		jQuery('body').mousemove(function(event) {stop = true; document.title = pageName;});
		jQuery('body').focus(function(event) {stop = true; document.title = pageName;});
		jQuery('body').blur(function(event) {stop = true; document.title = pageName;});
		
		XMPPHandler.scrollTitle();
	
        jQuery('#chatWrapper').append('<div id="tabs"><ul></ul></div>');			
		// tab template contains the remove icon and the message
		tabulatoren = jQuery("#tabs").tabs({
			tabTemplate: "<li><a href='#{href}'>#{label}</a> <span class='ui-icon ui-icon-close'>Remove Tab</span></li>",
			select: function(event, ui) {
				jQuery(ui.tab).parent().removeClass('newMessage');
			}
		});
		
		tabulatoren.hide();
		
		// close icon: removing the tab on click
		jQuery( "#tabs span.ui-icon-close" ).live( "click", function() {
			var index = jQuery( "li", tabulatoren ).index( jQuery( this ).parent() );
			tabulatoren.tabs( "remove", index );
			// hide the tabcontainer and remove the chatLink
			// if all tabs are closed
			var tabsCount = jQuery( "#tabs span.ui-icon-close").length;
			if(tabsCount == 0){
				tabulatoren.css('display', 'none');
				jQuery('#chatLink').remove();
			}
		});
	
		try { // try to resume a session
			if (JSJaCCookie.read('btype').getValue() == 'binding'){
			  con = new JSJaCHttpBindingConnection({'oDbg':oDbg});
			}
				
			setupCon(con);
			if (!con.resume()) {}
            this.restoreChatWindow();
	    } catch (e) {}
}
  
  // creates tabs and renders the chathistory
	this.restoreChatWindow = function(){
        try {
			var tabnames = JSJaCJSON.parse(unescape(JSJaCCookie.get('conversations')));
			if(tabnames != null && tabnames.alltabs != null){
			  jQuery.each(tabnames.alltabs, function(index, value) { 
					  if(value != null){
						var createJID = new JSJaCJID(value);
						XMPPHandler.openChatWith(createJID);
						XMPPHandler.retrieveConversations(value);
					  }
			   });
			tabulatoren.tabs('select', tabnames.selectedTab);
			scrollDown();
			}
		 }catch(e){} 
	}
  
  XMPPHandler.retrieveConversations = function(jID) {
		oDbg.log(jID);	
		
		var aIQ = new JSJaCIQ();
		aIQ.setType('get');
		var aNode = aIQ.appendNode('list',{'xmlns': 'urn:xmpp:archive','with': jID, 'start': XMPPHandler.formatDate(new Date())});
		var node2 = aNode.appendChild(aIQ.buildNode('set',{'xmlns':'http://jabber.org/protocol/rsm'}));
	    var node3 = node2.appendChild(aIQ.buildNode('max',{},5));
				
		con.send(aIQ, function(iq) {
		
		var items = iq.getNode().firstChild.getElementsByTagName('chat');
				
		for (var i=0; i<items.length; i++) {
			var item = items.item(i);
			var start = item.getAttribute('start');
			var chat_hist_with = item.getAttribute('with');
			
			var chat = new JSJaCIQ();
			chat.setType('get');
			var aNode = chat.appendNode(
				'retrieve',{'xmlns': 'urn:xmpp:archive','with': chat_hist_with, 'start':start}
			);	
			
			con.send(chat, function(iq){
				var tabID = new JSJaCJID(jID);
				var aStore = iq.getNode().firstChild;
				

				var div = jQuery("<div>");
				
				for (var i=0; i < aStore.childNodes.length; i++) {
					var aChild = aStore.childNodes.item(i);
					// message from me
					if (aChild.nodeName == 'to'){
						var span = jQuery("<span>", {'class': 'msg'}); 
						    span.append('<b>ich: </b>');
						div.append(span);
					}
					else{
						var span = jQuery("<span>", {'class': 'retrievedMsg'});
  						    span.append('<b>'+XMPPHandler.receipientFullName(tabID)+': </b>');
						div.append(span);
					}
					if (aChild.firstChild.firstChild){
						var span = jQuery("<span>");
						    span.append(document.createTextNode(aChild.firstChild.firstChild.nodeValue));
						div.append(span);
						div.append('<br/>');
					}
				}
				jQuery('#conversation_' + tabID.getNode()).append(div);				
			});
		}
	});
	return false;
  }

  // formates the date specified in XEP-0082
  // XMPP Date and Time Profiles: 2010-12-10T00:00:00.000000Z 
  // for more information take a lokk at: http://xmpp.org/extensions/xep-0082.html
  XMPPHandler.formatDate = function(date){
	var formatted = '';
	if(date != null){
		var curr_date = date.getDate();
		var curr_month = date.getMonth();
		var curr_year = date.getFullYear();
		curr_month++;
		formatted = curr_year + '-' + curr_month + '-' + curr_date + 'T00:00:00.000000Z';
	}
	return formatted;
  }

  // calls the openChatWith method and changes
  // the visibility to display = block so the
  // visibility defined in the called method will
  // be ignored.
  XMPPHandler.openChatWithFocus = function(jid) {
	XMPPHandler.anonymousLogin();  
    XMPPHandler.openChatWith(jid);
    tabulatoren.css('display', 'block');
    // selects the open chat tab
    var tabnames = jQuery('.ui-tabs-nav li a');
    jQuery.each(tabnames, function(index, value) {
    	if(value != null){
	  var tabId = value.hash.replace('#','').toLowerCase();
	  if(tabId == jid.getNode().toLowerCase()){
	  	tabulatoren.tabs('select', index);
	  }
   	}
   });
  }
  
  // creates a new Tab for conversation
  XMPPHandler.openChatWith = function(jid){      
    // open the chatwindow only if a connection exists 
    if (typeof con != 'undefined' && con){
		// adds a new tag if none exists
	    var tabId = jid.getNode().toLowerCase();
	    var tab = jQuery("#"+tabId);		
		if(tab.length == 0){
			
			createActiveChatsBtn();
			
			try{
				var display = JSJaCCookie.get('display');
				tabulatoren.css('display', display);
			}
			catch(e){}
					
			tabulatoren.tabs("add","#"+tabId, tabId);
			//erst jetzt existiert der Knoten
			tab = jQuery("#"+tabId);
			// conversation div where received and send messages are placed
			var conversation = jQuery("<div>", {id: 'conversation_' + tabId, 'class': 'conversation'});
			tab.append( conversation);
			
			// reply div contains the form, the inputfield and the submit button
			var reply = jQuery("<div>", {'class': 'replyContainer'});
						
						
			// inputfield containing the message
			var inputfield = jQuery("<input>", {type: "text", id: 'input_'+tabId});
	
			// submit message button
			var button = jQuery('<a href="#"> Senden</a>').button();
				button.click(function() {
					 XMPPHandler.sendMsg(jid , inputfield.val());
					 this.blur();
				});
			
			// submits the input on enter and animates the button			
			inputfield.keypress(function(e) {
				if(e.which == 13) {
					jQuery(this).blur();					
					button.focus().click();
					this.focus();
				}
			});
				
			reply.append(inputfield);
			reply.append(button);
			tab.append(reply);	
		}
	 }
  }
  
  XMPPHandler.sendMsg = function(receipienJID, msg, from) {
	  if (receipienJID == null || (msg == null || msg.length == 0)) {
	    return false;
	 }
	
	  try {
	    var aMsg = new JSJaCMessage();
				
	    aMsg.setTo(receipienJID);
	    aMsg.setBody(msg);
	    con.send(aMsg);
		
		var html = '';
		if(from != null && typeof from != 'undefined'){
			html += '<span class="retrievedMsg"><b>' +from+ ': </b></span>';
		}else {
			html += '<span class="msg"><b>ich: </b></span>';
		}
		html += '<span>' + aMsg.getBody().htmlEnc() + '</span><br/>';
		
		XMPPHandler.addMessageToTab(receipienJID, html);
		// clear the input field here
		jQuery('#input_' +receipienJID.getNode().toLowerCase()).removeAttr('value');
	    return false;
		
	  } catch (e) {
	    html = "<div class='msg error''>Error: "+e.message+"</div>"; 
	    jQuery('#chatStatus').append(html);
	    return false;
	  }
  }
  
	// Creates a new tab if not exists 
	// add the message to the tab.
	XMPPHandler.addMessageToTab = function(jid, msg){
		XMPPHandler.openChatWith(jid);
		var userId = jid.getNode().toLowerCase();
		jQuery('#conversation_'+userId).append(msg);
		scrollDown();
		var receipientTabId = '#'+userId;
		var selectedTabId = jQuery(".ui-state-active a").attr('href');
		if(typeof selectedTabId != 'undefined' && selectedTabId != receipientTabId) {
			jQuery( "#tabs li a[href='#"+userId+"']").parent().addClass('newMessage');
		}
	}
	
	// function for scrolling down on new message arrival
	function scrollDown(){
		var conversations = jQuery("div:[id^='conversation_']");
		jQuery.each(conversations, function(index, value) {
		if(value != null){
			jQuery(value).attr({ scrollTop: jQuery(value).attr("scrollHeight") });	
		}
	  });
	}
  
  /* Handler Section */
  function handleIQ(aIQ) {
	  jQuery('#chatStatus').append("<div class='msg'>IN (raw): " +aIQ.xml().htmlEnc() + '</div>');
	  con.send(aIQ.errorReply(ERR_FEATURE_NOT_IMPLEMENTED));
  }
  
  function handleIqVersion(iq) {
	  con.send(iq.reply([
	                     iq.buildNode('name', 'jsjac simpleclient'),
	                     iq.buildNode('version', JSJaC.Version),
	                     iq.buildNode('os', navigator.userAgent)
	                     ]));
	  return true;
  }

  function handleIqTime(iq) {
	  var now = new Date();
	  con.send(iq.reply([iq.buildNode('display', now.toLocaleString()),
	                     iq.buildNode('utc', now.jabberDate()),
	                     iq.buildNode('tz', now.toLocaleString().substring(now.toLocaleString().lastIndexOf(' ')+1))
	                     ]));
	  return true;
  }
  
  function handleError(e) {
	  jQuery('#chatStatus').append(e); 
  }
  
  function handleMessage(aJSJaCPacket) {
	 // do not send empty messages
	  if(aJSJaCPacket.getBody() != ''){
		 var html = '';
		 html += '<span class="retrievedMsg"><b>'+XMPPHandler.receipientFullName(aJSJaCPacket.getFromJID())+': </b></span>';
	 	 html += '<span>' + aJSJaCPacket.getBody().htmlEnc() + '</span><br/>';
	  
	 
	  	// put message into a tab
      	  	XMPPHandler.addMessageToTab(aJSJaCPacket.getFromJID(), html);
	  
	  	// triggers an effect if the chatwindow is closed
	 	 // and a message arrives
	  	if(tabulatoren.css('display') == 'none') {
		 	 var options = {};
		 	 jQuery("#chatLink").effect('pulsate', options, 500, callback);
		 	 jQuery("#chatLink").css('background','red');
	  	}
		scrollingMsg = 'Neue Nachricht: ' + aJSJaCPacket.getBody().htmlEnc();
		stop = false;
	}
   }

	// callback function to bring a hidden box back
	function callback() {
		setTimeout(function() {
			jQuery('#chatLink').removeAttr('style');
			jQuery("#chatLink").css('background','red');
		}, 1000 );
	};
   
   function handlePresence(aJSJaCPacket) {
		
	if(aJSJaCPacket.getFromJID() != null){
		var conversation = jQuery('#conversation_' + aJSJaCPacket.getFromJID().getNode());
		if(conversation.length != 0){
			if(aJSJaCPacket.getType() == 'unavailable' && typeof con != 'undefined' && con && con.connected()){
				XMPPHandler.sendMsg(aJSJaCPacket.getFromJID(), "Der Benutzer ist jetzt Offline. Ihm werden keine weiteren Nachrichten zugestellt!", "SYSTEM");
			}
		}
	}
	  var html = '<div class="msg">';
	  if (!aJSJaCPacket.getType() && !aJSJaCPacket.getShow()) 
	    html += '<b>'+aJSJaCPacket.getFromJID()+' has become available.</b>';
	  else {
	    html += '<b>'+aJSJaCPacket.getFromJID()+' has set his presence to ';
	    if (aJSJaCPacket.getType())
	      html += aJSJaCPacket.getType() + '.</b>';
	    else
	      html += aJSJaCPacket.getShow() + '.</b>';
	    if (aJSJaCPacket.getStatus())
	      html += ' ('+aJSJaCPacket.getStatus().htmlEnc()+')';
	  }
	  html += '</div>';
	  jQuery('#chatStatus').append(html);
	}
	
	// handles the presence
	function handleConnected() {
	  con.send(new JSJaCPresence());
	}
	
	function handleStatusChanged(status) {
		oDbg.log("status changed: "+status);
		jQuery('#chatStatus').append("status changed: "+status);
	}
	
	function handleDisconnected() {
		jQuery('#chatStatus').append('logout processing');
	}
  
    // creates a Link if not exists that toggles the chatwindow
	// from hidden to visible and viceversa
    function createActiveChatsBtn() {
     if(jQuery('#chatLink').length == 0) {
		 var div = jQuery('<div style="text-align:right">');
		 div.append(jQuery('<a href="#" id="chatLink"> Aktuelle Chats </a>').button({icons: {primary: "ui-icon-newwin"}}));
		 jQuery('#chatWrapper').append(div);
		 jQuery('#chatLink').click(function() {
			tabulatoren.toggle();
			jQuery('#chatLink').blur();
			jQuery('#chatLink').removeAttr('style');
		 });
	 }
    }
	
   // responsible for scrolling title	
   XMPPHandler.scrollTitle = function()  {
  	if (!stop){
		document.title = scrollingMsg.substring(pos, scrollingMsg.length) + spacer + scrollingMsg.substring(0, pos);
		pos++;
		if (pos > scrollingMsg.length) pos=0;
	}
	window.setTimeout("XMPPHandler.scrollTitle()",time_length);
  }
  
   XMPPHandler.decode = function(input) {
		var output = "";
		var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		
		var chr1, chr2, chr3;
		var enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
 
		while (i < input.length) {
 
			enc1 = _keyStr.indexOf(input.charAt(i++));
			enc2 = _keyStr.indexOf(input.charAt(i++));
			enc3 = _keyStr.indexOf(input.charAt(i++));
			enc4 = _keyStr.indexOf(input.charAt(i++));
 
			chr1 = (enc1 << 2) | (enc2 >> 4);
			chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
			chr3 = ((enc3 & 3) << 6) | enc4;
 
			output = output + String.fromCharCode(chr1);
 
			if (enc3 != 64) {
				output = output + String.fromCharCode(chr2);
			}
			if (enc4 != 64) {
				output = output + String.fromCharCode(chr3);
			}
 
		}
 
		output = _utf8_decode(output);
 
		return output;
 
	}
	
	XMPPHandler.encode = function(input) {
		var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;
 
		input = _utf8_encode(input);
 
		while (i < input.length) {
 
			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);
 
			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;
 
			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}
 
			output = output +
			_keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
			_keyStr.charAt(enc3) + _keyStr.charAt(enc4);
 
		}
 
		return output;
	}
	
	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;
	}
	
	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;
	}
	

	XMPPHandler.receipientFullName = function(jid) {
		var fullname = null;
		try {
			fullname = jQuery('.ui-tabs-nav li a[href$="#'+jid.getNode()+'"]')[0].innerHTML;
		}catch(e){
			 fullname = jid.getNode();
		}
		return fullname;
	}
	
} 

function TabPersistence() {
	this.selectedTab = 0;
	this.alltabs = new Object();
}

