dojo.provide("dojox.xmpp.xmppSession");

dojo.require("dojox.xmpp.TransportSession");
dojo.require("dojox.xmpp.RosterService");
dojo.require("dojox.xmpp.PresenceService");
dojo.require("dojox.xmpp.UserService");
dojo.require("dojox.xmpp.ChatService");
dojo.require("dojox.xmpp.sasl");

dojox.xmpp.xmpp = {
	STREAM_NS:  'http://etherx.jabber.org/streams',
	CLIENT_NS: 'jabber:client',
	STANZA_NS: 'urn:ietf:params:xml:ns:xmpp-stanzas',
	SASL_NS: 'urn:ietf:params:xml:ns:xmpp-sasl',
	BIND_NS: 'urn:ietf:params:xml:ns:xmpp-bind',
	SESSION_NS: 'urn:ietf:params:xml:ns:xmpp-session',
	BODY_NS: "http://jabber.org/protocol/httpbind",

	XHTML_BODY_NS: "http://www.w3.org/1999/xhtml",
	XHTML_IM_NS: "http://jabber.org/protocol/xhtml-im",

	INACTIVE: "Inactive",
	CONNECTED: "Connected",
	ACTIVE: "Active",
	TERMINATE: "Terminate",
	LOGIN_FAILURE: "LoginFailure",

	INVALID_ID: -1,
	NO_ID: 0,

	error:{
		BAD_REQUEST: 'bad-request',
		CONFLICT: 'conflict',
		FEATURE_NOT_IMPLEMENTED: 'feature-not-implemented',
		FORBIDDEN: 'forbidden',
		GONE: 'gone',
		INTERNAL_SERVER_ERROR: 'internal-server-error',
		ITEM_NOT_FOUND: 'item-not-found',
		ID_MALFORMED: 'jid-malformed',
		NOT_ACCEPTABLE: 'not-acceptable',
		NOT_ALLOWED: 'not-allowed',
		NOT_AUTHORIZED: 'not-authorized',
		SERVICE_UNAVAILABLE: 'service-unavailable',
		SUBSCRIPTION_REQUIRED: 'subscription-required',
		UNEXPECTED_REQUEST: 'unexpected-request'
	}
};

dojox.xmpp.xmppSession = function(props){
	this.roster = [];
	this.chatRegister = [];
	this._iqId = Math.round(Math.random() * 1000000000);

	//mixin any options that we want to provide to this service
	if (props && dojo.isObject(props)) {
		dojo.mixin(this, props);
	}

	this.session = new dojox.xmpp.TransportSession(props);
	dojo.connect(this.session, "onReady", this, "onTransportReady");
	dojo.connect(this.session, "onTerminate", this, "onTransportTerminate");
	dojo.connect(this.session, "onProcessProtocolResponse", this, "processProtocolResponse");
};


dojo.extend(dojox.xmpp.xmppSession, {

		roster: [],
		chatRegister: [],
		_iqId: 0,

		open: function(user, password, resource){

			if (!user) {
				throw new Error("User id cannot be null");
			} else {
				this.jid = user;
				if(user.indexOf('@') == -1) {
					this.jid = this.jid + '@' + this.domain;
				}
			}

			//allow null password here as its not needed in the SSO case
			if (password) {
				this.password = password;
			}

			//normally you should NOT supply a resource and let the server send you one
			//as part of your jid...see onBindResource()
			if (resource) {
				this.resource = resource;
			}

			this.session.open();
		},

		close: function(){
			this.state = dojox.xmpp.xmpp.TERMINATE;
			this.session.close(dojox.xmpp.util.createElement("presence",{type:"unavailable",xmlns:dojox.xmpp.xmpp.CLIENT_NS},true));
		},

		processProtocolResponse: function(msg){
			//console.log("xmppSession::processProtocolResponse() ", msg, msg.nodeName);
			var type = msg.nodeName;
			var nsIndex =type.indexOf(":");
			if(nsIndex > 0) {
				type = type.substring(nsIndex+1);
			}
			switch(type){
				case "iq":
				case "presence":
				case "message":
				case "features":
					this[type + "Handler"](msg);
					break;
				default:
					//console.log("default action?", msg.getAttribute('xmlns'));
					if(msg.getAttribute('xmlns')==dojox.xmpp.xmpp.SASL_NS){
						this.saslHandler(msg);
					}
			}
		},

		//HANDLERS

		messageHandler: function(msg){
			//console.log("xmppSession::messageHandler() ",msg);
			switch(msg.getAttribute('type')){
				case "chat":
					this.chatHandler(msg);
					break;
				case "normal":
					break;
				default:
					this.simpleMessageHandler(msg);
			}

		},

		iqHandler: function(msg){
			//console.log("xmppSession::iqHandler()", msg);
			if (msg.getAttribute('type')=="set"){
				this.iqSetHandler(msg);
				return;
			} else if (msg.getAttribute('type')=='get'){
			//	this.sendStanzaError('iq', this.domain, msg.getAttribute('from'), 'cancel', 'service-unavailable', 'service not implemented');
				return;
			}
		},

		presenceHandler: function(msg){
			//console.log("xmppSession::presenceHandler()");
			switch(msg.getAttribute('type')){
				case 'subscribe':
					//console.log("PresenceHandler: ", msg.getAttribute('from'));
					this.presenceSubscriptionRequest(msg.getAttribute('from'));
					break;
				case 'subscribed':
				case 'unsubscribed':
					break;
				case 'error':
					this.processXmppError(msg);
					//console.log("xmppService::presenceHandler() Error");
					break;
				default:
					this.presenceUpdate(msg);
					break;
			}
		},

		featuresHandler: function(msg){
			//console.log("xmppSession::featuresHandler() ",msg);
			var authMechanisms = [];
			var hasBindFeature = false;
			var hasSessionFeature = false;

			if(msg.hasChildNodes()){
				for(var i=0; i<msg.childNodes.length;i++){
					var n = msg.childNodes[i];
					//console.log("featuresHandler::node", n);
					switch(n.nodeName){
						case 'mechanisms':
							for (var x=0; x<n.childNodes.length; x++){
								//console.log("featuresHandler::node::mechanisms", n.childNodes[x].firstChild.nodeValue);
								authMechanisms.push(n.childNodes[x].firstChild.nodeValue);
							}
							break;
						case 'bind':
							//if (n.getAttribute('xmlns')==dojox.xmpp.xmpp.BIND_NS) {
							hasBindFeature = true;
						//	}
							break;
						case 'session':
							hasSessionFeature = true;
					}
				}
			}
			//console.log("Has connected/bind?", this.state, hasBindFeature, authMechanisms);
			if(this.state == dojox.xmpp.xmpp.CONNECTED){
				if(!this.auth){
					// start the login
					for(var i=0; i<authMechanisms.length; i++){
						try{
							this.auth = dojox.xmpp.sasl.registry.match(authMechanisms[i], this);
							break;
						}catch(e){
							console.warn("No suitable auth mechanism found for: ", authMechanisms[i]);
						}
					}
				}else if(hasBindFeature){
					this.bindResource(hasSessionFeature);
				}
			}
		},

		saslHandler: function(msg){
			//console.log("xmppSession::saslHandler() ", msg);
			if(msg.nodeName=="success"){
				this.auth.onSuccess();
				return;
			}

			if(msg.nodeName=="challenge"){
				this.auth.onChallenge(msg);
				return;
			}

			if(msg.hasChildNodes()){
				this.onLoginFailure(msg.firstChild.nodeName);
				this.session.setState('Terminate', msg.firstChild.nodeName);
			}
		},

		sendRestart: function(){
			this.session._sendRestart();
		},


		//SUB HANDLERS

		chatHandler: function(msg){
			//console.log("xmppSession::chatHandler() ", msg);
			var message = {
				from: msg.getAttribute('from'),
				to: msg.getAttribute('to')
			};

			var chatState = null;
				//console.log("chat child node ", msg.childNodes, msg.childNodes.length);
			for (var i=0; i<msg.childNodes.length; i++){
				var n = msg.childNodes[i];
				if (n.hasChildNodes()){
					//console.log("chat child node ", n);
					switch(n.nodeName){
						case 'thread':
							message.chatid = n.firstChild.nodeValue;
							break;
						case 'body':
							if (!n.getAttribute('xmlns') || (n.getAttribute('xmlns')==="")){
								message.body = n.firstChild.nodeValue;
							}
							break;
						case 'subject':
							message.subject = n.firstChild.nodeValue;
							break;
						case 'html':
							if (n.getAttribute('xmlns')==dojox.xmpp.xmpp.XHTML_IM_NS){
								message.xhtml = n.getElementsByTagName("body")[0];
							}
							break;
						case 'x':
							break;
						default:
							//console.log("xmppSession::chatHandler() Unknown node type: ",n.nodeName);
					}
				}
				/*//console.log("Foo", n, n.nodeName);
				if(n.getAttribute('xmlns')==dojox.xmpp.chat.CHAT_STATE_NS){
					chatState = n.nodeName;
				}*/
			}

			var found = -1;
			if (message.chatid){
				for (var i=0; i< this.chatRegister.length; i++){
					var ci = this.chatRegister[i];
					////console.log("ci.chatid: ", ci.chatid, message.chatid);
					if (ci && ci.chatid == message.chatid) {
						found = i;
						break;
					}
				}
			} else {
				for (var i=0; i< this.chatRegister.length; i++){
					var ci = this.chatRegister[i];
					if(ci){
						if (ci.uid==this.getBareJid(message.from)){
							found = i;
						}
					}
				}
			}

			if (found>-1 && chatState){
				var chat = this.chatRegister[found];
				chat.setState(chatState);

				if (chat.firstMessage){
					if (chatState == dojox.xmpp.chat.ACTIVE_STATE) {
						chat.useChatState = (chatState !== null) ? true : false;
						chat.firstMessage = false;
					}
				}
			}

			if ((!message.body || message.body==="") && !message.xhtml) {return;}

			if (found>-1){
				var chat = this.chatRegister[found];
				chat.receiveMessage(message);
			}else{
				var chatInstance = new dojox.xmpp.ChatService();
				chatInstance.uid = this.getBareJid(message.from);
				chatInstance.chatid = message.chatid;
				chatInstance.firstMessage = true;
				if(!chatState || chatState != dojox.xmpp.chat.ACTIVE_STATE){
					this.useChatState = false;
				}
				this.registerChatInstance(chatInstance, message);
			}
		},

		simpleMessageHandler: function(msg){
			//console.log("xmppSession::simpleMessageHandler() ", msg);
		},

		registerChatInstance: function(chatInstance, message){
			chatInstance.setSession(this);
			this.chatRegister.push(chatInstance);
			this.onRegisterChatInstance(chatInstance, message);
			chatInstance.receiveMessage(message,true);
		},

		iqSetHandler: function(msg){
			if (msg.hasChildNodes()){
				var fn = msg.firstChild;
				switch(fn.nodeName){
					case 'query':
						if(fn.getAttribute('xmlns') == "jabber:iq:roster"){
							this.rosterSetHandler(fn);
							this.sendIqResult(msg.getAttribute('id'), msg.getAttribute('from'));
						}
						break;
					default:
					//	this.sendStanzaError('iq', this.domain, msg.getAttribute('id'), 'cancel', 'service-unavailable', 'service not implemented');
						break;
				}
			}
		},

		sendIqResult: function(iqId, to){
			var req = {
				id: iqId,
				to: to || this.domain,
				type: 'result',
				from: this.jid + "/" + this.resource
			};
			this.dispatchPacket(dojox.xmpp.util.createElement("iq",req,true));
		},

		rosterSetHandler: function(elem){
			//console.log("xmppSession::rosterSetHandler()", arguments);
			var r;
			for (var i=0; i<elem.childNodes.length;i++){
				var n = elem.childNodes[i];

				if (n.nodeName=="item"){
					var found = false;
					var state = -1;
					var rosterItem = null;
					var previousCopy = null;
					for(var x=0; x<this.roster.length;x++){
						r = this.roster[x];
						if(n.getAttribute('jid')==r.jid){
							found = true;
							if(n.getAttribute('subscription')=='remove'){
								//remove the item
								rosterItem = {
									id: r.jid,
									name: r.name,
									groups:[]
								};

								for (var y=0;y<r.groups.length;y++){
									rosterItem.groups.push(r.groups[y]);
								}

								this.roster.splice(x,1);
								state = dojox.xmpp.roster.REMOVED;

							} else { //update
								previousCopy = dojo.clone(r);
								var itemName = n.getAttribute('name');
								if (itemName){
									this.roster[x].name = itemName;
								}

								r.groups = [];

								if (n.getAttribute('subscription')){
									r.status = n.getAttribute('subscription');
								}

								r.substatus = dojox.xmpp.presence.SUBSCRIPTION_SUBSTATUS_NONE;
								if(n.getAttribute('ask')=='subscribe'){
									r.substatus = dojox.xmpp.presence.SUBSCRIPTION_REQUEST_PENDING;
								}

								for(var y=0;y<n.childNodes.length;y++){
									var groupNode = n.childNodes[y];
									if ((groupNode.nodeName=='group')&&(groupNode.hasChildNodes())){
										var gname = groupNode.firstChild.nodeValue;
										r.groups.push(gname);
									}
								}
								rosterItem = r;
								state = dojox.xmpp.roster.CHANGED;
							}
							break;
						}
					}
					if(!found && (n.getAttribute('subscription')!='remove')){
						r = this.createRosterEntry(n);
						rosterItem = r;
						state = dojox.xmpp.roster.ADDED;
					}

					switch(state){
						case dojox.xmpp.roster.ADDED:
							this.onRosterAdded(rosterItem);
							break;
						case dojox.xmpp.roster.REMOVED:
							this.onRosterRemoved(rosterItem);
							break;
						case dojox.xmpp.roster.CHANGED:
							this.onRosterChanged(rosterItem, previousCopy);
							break;
					}
				}
			}
		},

		presenceUpdate: function(msg){
			if(msg.getAttribute('to')){
				var jid = this.getBareJid(msg.getAttribute('to'));
				if(jid != this.jid) {
					//console.log("xmppService::presenceUpdate Update Received with wrong address - ",jid);
					return;
				}
			}

			var fromRes = this.getResourceFromJid(msg.getAttribute('from'));

			var p = {
				from: this.getBareJid(msg.getAttribute('from')),
				resource: fromRes,
				show: dojox.xmpp.presence.STATUS_ONLINE,
				priority: 5,
				hasAvatar: false
			};

			if(msg.getAttribute('type')=='unavailable'){
				p.show=dojox.xmpp.presence.STATUS_OFFLINE;
			}

			for (var i=0; i<msg.childNodes.length;i++){
				var n=msg.childNodes[i];
				if (n.hasChildNodes()){
					switch(n.nodeName){
						case 'status':
						case 'show':
							p[n.nodeName]=n.firstChild.nodeValue;
							break;
						case 'priority':
							p.priority=parseInt(n.firstChild.nodeValue, 10);
							break;
						case 'x':
							if(n.firstChild && n.firstChild.firstChild && n.firstChild.firstChild.nodeValue !== "") {
								p.avatarHash= n.firstChild.firstChild.nodeValue;
								p.hasAvatar = true;
							}
							break;
					}
				}
			}

			this.onPresenceUpdate(p);
		},

		retrieveRoster: function(){
			////console.log("xmppService::retrieveRoster()");
			var props={
				id: this.getNextIqId(),
				from: this.jid + "/" + this.resource,
				type: "get"
			};
			var req = new dojox.string.Builder(dojox.xmpp.util.createElement("iq",props,false));
			req.append(dojox.xmpp.util.createElement("query",{xmlns: "jabber:iq:roster"},true));
			req.append("</iq>");

			var def = this.dispatchPacket(req,"iq", props.id);
			def.addCallback(this, "onRetrieveRoster");

		},

		getRosterIndex: function(jid){
			if(jid.indexOf('@')==-1){
				jid += '@' + this.domain;
			}
			for (var i=0; i<this.roster.length;i++){
				if(jid == this.roster[i].jid) { return i; }
			}
			return -1;
		},

		createRosterEntry: function(elem){
			////console.log("xmppService::createRosterEntry()");
			var re = {
				name: elem.getAttribute('name'),
				jid: elem.getAttribute('jid'),
				groups: [],
				status: dojox.xmpp.presence.SUBSCRIPTION_NONE,
				substatus: dojox.xmpp.presence.SUBSCRIPTION_SUBSTATUS_NONE
			//	displayToUser: false
			};

			if (!re.name){
				re.name = re.id;
			}



			for(var i=0; i<elem.childNodes.length;i++){
				var n = elem.childNodes[i];
				if (n.nodeName=='group' && n.hasChildNodes()){
					re.groups.push(n.firstChild.nodeValue);
				}
			}

			if (elem.getAttribute('subscription')){
				re.status = elem.getAttribute('subscription');
			}

			if (elem.getAttribute('ask')=='subscribe'){
				re.substatus = dojox.xmpp.presence.SUBSCRIPTION_REQUEST_PENDING;
			}
			//Display contact rules from http://www.xmpp.org/extensions/xep-0162.html#contacts
		/*	if(re.status == dojox.xmpp.presence.SUBSCRIPTION_REQUEST_PENDING ||
				re.status == dojox.xmpp.presence.SUBSCRIPTION_TO ||
				re.status == dojox.xmpp.presence.SUBSCRIPTION_BOTH ||
				re.groups.length > 0 ||
				re.name
				) {
					re.displayToUser = true;
				}
*/
			return re;
		},

		bindResource: function(hasSession){
			var props = {
				id: this.getNextIqId(),
				type: "set"
			};
			var bindReq = new dojox.string.Builder(dojox.xmpp.util.createElement("iq", props, false));
			bindReq.append(dojox.xmpp.util.createElement("bind", {xmlns: dojox.xmpp.xmpp.BIND_NS}, false));

			if (this.resource){
				bindReq.append(dojox.xmpp.util.createElement("resource"));
				bindReq.append(this.resource);
				bindReq.append("</resource>");
			}

			bindReq.append("</bind></iq>");

			var def = this.dispatchPacket(bindReq, "iq", props.id);
			def.addCallback(this, function(msg){
				this.onBindResource(msg, hasSession);
				return msg;
			});
		},

		getNextIqId: function(){
			return "im_" + this._iqId++;
		},

		presenceSubscriptionRequest: function(msg) {
			this.onSubscriptionRequest(msg);
			/*
			this.onSubscriptionRequest({
				from: msg,
				resource:"",
				show:"",
				status:"",
				priority: 5
			});
			*/
		},

		dispatchPacket: function(msg, type, matchId){
			if (this.state != "Terminate") {
				return this.session.dispatchPacket(msg,type,matchId);
			}else{

				//console.log("xmppSession::dispatchPacket - Session in Terminate state, dropping packet");
			}
		},

		setState: function(state, message){
			if (this.state != state){
				if (this["on"+state]){
					this["on"+state](state, this.state, message);
				}
				this.state=state;
			}
		},

		search: function(searchString, service, searchAttribute){
			var req={
				id: this.getNextIqId(),
				"xml:lang": this.lang,
				type: 'set',
				from: this.jid + '/' + this.resource,
				to: service
			};
			var request = new dojox.string.Builder(dojox.xmpp.util.createElement("iq",req,false));
			request.append(dojox.xmpp.util.createElement('query',{xmlns:'jabber:iq:search'},false));
			request.append(dojox.xmpp.util.createElement(searchAttribute,{},false));
			request.append(searchString);
			request.append("</").append(searchAttribute).append(">");
			request.append("</query></iq>");

			var def = this.dispatchPacket(request.toString,"iq",req.id);
			def.addCallback(this, "_onSearchResults");
		},

		_onSearchResults: function(msg){
			if ((msg.getAttribute('type')=='result')&&(msg.hasChildNodes())){
				//console.log("xmppSession::_onSearchResults(): ", msg.firstChild);

				//call the search results event with an array of results
				this.onSearchResults([]);
			}
		},

		// EVENTS

		onLogin: function(){
			////console.log("xmppSession::onLogin()");
			this.retrieveRoster();
		},

		onLoginFailure: function(msg){
			//console.log("xmppSession::onLoginFailure ", msg);
		},

		onBindResource: function(msg, hasSession){
			//console.log("xmppSession::onBindResource() ", msg);

			if (msg.getAttribute('type')=='result'){
				//console.log("xmppSession::onBindResource() Got Result Message");
				if ((msg.hasChildNodes()) && (msg.firstChild.nodeName=="bind")){
					var bindTag = msg.firstChild;
					if ((bindTag.hasChildNodes()) && (bindTag.firstChild.nodeName=="jid")){
						if (bindTag.firstChild.hasChildNodes()){
							var fulljid = bindTag.firstChild.firstChild.nodeValue;
							this.jid = this.getBareJid(fulljid);
							this.resource = this.getResourceFromJid(fulljid);
						}
					}
					if(hasSession){
						var props = {
							id: this.getNextIqId(),
							type: "set"
						};
						var bindReq = new dojox.string.Builder(dojox.xmpp.util.createElement("iq", props, false));
						bindReq.append(dojox.xmpp.util.createElement("session", {xmlns: dojox.xmpp.xmpp.SESSION_NS}, true));
						bindReq.append("</iq>");

						var def = this.dispatchPacket(bindReq, "iq", props.id);
						def.addCallback(this, "onBindSession");
						return;
					}
				}else{
					//console.log("xmppService::onBindResource() No Bind Element Found");
				}

				this.onLogin();

			}else if(msg.getAttribute('type')=='error'){
				//console.log("xmppSession::onBindResource() Bind Error ", msg);
				var err = this.processXmppError(msg);
				this.onLoginFailure(err);
			}
		},

		onBindSession: function(msg){
			if(msg.getAttribute('type')=='error'){
				//console.log("xmppSession::onBindSession() Bind Error ", msg);
				var err = this.processXmppError(msg);
				this.onLoginFailure(err);
			}else{
				this.onLogin();
			}
		},

		onSearchResults: function(results){
			//console.log("xmppSession::onSearchResult() ", results);
		},

		onRetrieveRoster: function(msg){
			////console.log("xmppService::onRetrieveRoster() ", arguments);

			if ((msg.getAttribute('type')=='result') && msg.hasChildNodes()){
				var query = msg.getElementsByTagName('query')[0];
				if (query.getAttribute('xmlns')=="jabber:iq:roster"){
					for (var i=0;i<query.childNodes.length;i++){
						if (query.childNodes[i].nodeName=="item"){
							this.roster[i] = this.createRosterEntry(query.childNodes[i]);
						}
					}
				}
			}else if(msg.getAttribute('type')=="error"){
				//console.log("xmppService::storeRoster()  Error received on roster get");
			}

			////console.log("Roster: ", this.roster);
			this.setState(dojox.xmpp.xmpp.ACTIVE);
			this.onRosterUpdated();

			return msg;
		},

		onRosterUpdated: function() {},

		onSubscriptionRequest: function(req){},

		onPresenceUpdate: function(p){},

		onTransportReady: function(){
			this.setState(dojox.xmpp.xmpp.CONNECTED);
			this.rosterService = new dojox.xmpp.RosterService(this);
			this.presenceService= new dojox.xmpp.PresenceService(this);
			this.userService = new dojox.xmpp.UserService(this);

			////console.log("xmppSession::onTransportReady()");
		},

		onTransportTerminate: function(newState, oldState, message){
			this.setState(dojox.xmpp.xmpp.TERMINATE, message);
		},

		onConnected: function(){
			////console.log("xmppSession::onConnected()");
		},

		onTerminate: function(newState, oldState, message){
			//console.log("xmppSession::onTerminate()", newState, oldState, message);
		},

		onActive: function(){
			////console.log("xmppSession::onActive()");
			//this.presenceService.publish({show: dojox.xmpp.presence.STATUS_ONLINE});
		},

		onRegisterChatInstance: function(chatInstance, message){
			////console.log("xmppSession::onRegisterChatInstance()");
		},

		onRosterAdded: function(ri){},
		onRosterRemoved: function(ri){},
		onRosterChanged: function(ri, previousCopy){},

		//Utilities

		processXmppError: function(msg){
			////console.log("xmppSession::processXmppError() ", msg);
			var err = {
				stanzaType: msg.nodeName,
				id: msg.getAttribute('id')
			};

			for (var i=0; i<msg.childNodes.length; i++){
				var n = msg.childNodes[i];
				switch(n.nodeName){
					case 'error':
						err.errorType = n.getAttribute('type');
						for (var x=0; x< n.childNodes.length; x++){
							var cn = n.childNodes[x];
							if ((cn.nodeName=="text") && (cn.getAttribute('xmlns') == dojox.xmpp.xmpp.STANZA_NS) && cn.hasChildNodes()) {
								err.message = cn.firstChild.nodeValue;
							} else if ((cn.getAttribute('xmlns') == dojox.xmpp.xmpp.STANZA_NS) &&(!cn.hasChildNodes())){
								err.condition = cn.nodeName;
							}
						}
						break;
					default:
						break;
				}
			}
			return err;
		},

		sendStanzaError: function(stanzaType,to,id,errorType,condition,text){
			////console.log("xmppSession: sendStanzaError() ", arguments);
			var req = {type:'error'};
			if (to) { req.to=to; }
			if (id) { req.id=id; }

			var request = new dojox.string.Builder(dojox.xmpp.util.createElement(stanzaType,req,false));
			request.append(dojox.xmpp.util.createElement('error',{type:errorType},false));
			request.append(dojox.xmpp.util.createElement('condition',{xmlns:dojox.xmpp.xmpp.STANZA_NS},true));

			if(text){
				var textAttr={
					xmlns: dojox.xmpp.xmpp.STANZA_NS,
					"xml:lang":this.lang
				};
				request.append(dojox.xmpp.util.createElement('text',textAttr,false));
				request.append(text).append("</text>");
			}
			request.append("</error></").append(stanzaType).append(">");

			this.dispatchPacket(request.toString());
		},

		getBareJid: function(jid){
			var i = jid.indexOf('/');
			if (i != -1){
				return jid.substring(0, i);
			}
			return jid;
		},

		getResourceFromJid: function(jid){
			var i = jid.indexOf('/');
			if (i != -1){
				return jid.substring((i + 1), jid.length);
			}
			return "";
		}

});
