// Contact object
function Contact() {
	this.id = "";
    this.name = "";
	this.image = "";
	this.domain = "";
    this.resources = {}; //assoc. array with status, show and language
    this.subscription = "none";
    this.ask = "";
    this.groups = [];
}

Contact.prototype = {
    // compute whether user is online from their list of resources
    online: function () {
        var result = false;
        for (var k in this.resources) {
            result = true;
            break;
        }
        return result;
    },

    /* 
     * Get/Set the language
     * If 'language' is given set the language and return it, else just return current language
    */
	language: function(language) {
    	var rez = this._getResource();
    	
    	if(rez)
    	{
	    	if(language)
	    		this.resources[rez].language = language;
	    	
    		return this.resources[rez].language;
    	}	
    	
    	return null;
    },
    
    /* 
     * Get/Set the mood
     * If 'mood' is given set the mood and return it, else just return current mood
    */
    mood: function(mood) {
    	var rez = this._getResource();
    	
    	if(rez)
    	{
    		if(mood)
	    		this.resources[rez].status = mood;
    		return this.resources[rez].status;
    	}	
    	
    	return null;
    },

	setResource: function(resource, language, mood, show)	{
		this.resources[resource] = {
			    show: show,
			    status: mood,
			    language: language
			};
	},

	getResource: function(resource){
		try{
			return this.resources[resource];
		}catch(e){return false}
	},

	clearResources : function() {
		this.resources = {};
	},
    
    _getResource : function(){
    	for (var k in this.resources) {
            return k;
        }
    	
    	return null;
    }
}

//Makes it easy to query for roster changes
var RosterManager = {
    getLanguage : function(jid){
		var info = this.getInfo(jid);
		return (info)?info.language():'';
    },
    getMood : function(jid){
		var info = this.getInfo(jid);
		return (info)?info.mood():'';
    },
    getId : function(jid){
        var info = this.getInfo(jid);
        return (info)?info.id:'';
    },
    getImage : function(jid){
        var info = this.getInfo(jid);
        return (info)?info.image:'';
    },
    getName : function(jid){
        var info = this.getInfo(jid);
		return (info)?info.name:'';
    },
    getInfo : function(jid){		
		return connection.roster.contacts[this._key(jid)];
    },
    set : function(jid, id, name, image, resource, language, mood, show){
        var contact = new Contact();
        contact.domain = Strophe.getDomainFromJid(jid);
        contact.id = id;
        contact.name = name;
        contact.image = image;
        contact.setResource(resource,language,mood,show);
        connection.roster.contacts[Strophe.getNodeFromJid(jid)] = contact;
    },
    update : function(jid, language, mood, show)
    {
        var jid = Strophe.getNodeFromJid(jid);
        var contact = connection.roster.contacts[jid];
        if(!contact) return false;

        var resource = Strophe.getResourceFromJid(jid) || contact._getResource();
        contact.setResource(resource, language, mood, show);
        connection.roster.contacts[jid] = contact;
        return true;
    },
    setFromPresence : function( presence ){
        //console.log('setFromPresence',presence);
        var from = $(presence).attr("from");
        var user = $(presence).find('user');
        var lang = $(presence).find('language');
        var show = $(presence).find('show');
        this.set(from, $(user).attr('id'), $(user).attr('name'), $(user).attr('image'), Strophe.getResourceFromJid(from), lang.attr('code'), $(user).attr('mood'), show);
    },
    setLanguageAndMood : function(jid, language, mood)
    {
        var jid = Strophe.getNodeFromJid(jid);
        if(!connection.roster.contacts[jid]) return false;
        connection.roster.contacts[jid].language(language);
        connection.roster.contacts[jid].language(mood);
        return true;
    },
    remove : function(jid){
        var node = Strophe.getNodeFromJid(jid);

        if(connection.roster.contacts[node]){
            connection.roster.contacts[node].clearResources();
            delete connection.roster.contacts[node];
        }
    },
    count : function(){
        var ctr = 0;
        var tmp = connection.roster.contacts;
        for(var i in tmp) if(tmp[i].online()) ctr++
        return ctr;
    },
    _key : function(jid) {
        return Strophe.getNodeFromJid(jid) || jid;
    }
}

// example roster plugin
Strophe.addConnectionPlugin('roster', {
    init: function (connection) {
        this.connection = connection;
        this.contacts = {};		
        Strophe.addNamespace('ROSTER', 'jabber:iq:roster');
    },

    // called when connection status is changed
    statusChanged: function (status) {
    	
    	if (status === Strophe.Status.CONNECTED) {
            this.contacts = {};

            // set up handlers for updates
            /*this.connection.addHandler(this.rosterChanged.bind(this),
                                       Strophe.NS.ROSTER, "iq", "set");*/
            this.connection.addHandler(this.presenceChanged.bind(this),
                                       null, "presence");

			//<editor-fold defaultstate="collapsed" desc="Old code">

            // build and send initial roster query
            /*var roster_iq = $iq({type: "get"}).c('query', {xmlns: Strophe.NS.ROSTER});
            
            var that = this;
            this.connection.sendIQ(roster_iq, function (iq) {
                $(iq).find("item").each(function () {
                    // build a new contact and add it to the roster
                	var contact = new Contact();
                    contact.name = $(this).attr('name') || "";
                    contact.subscription = $(this).attr('subscription') || "none";
                    contact.ask = $(this).attr('ask') || ""; 
                    $(this).find("group").each(function () {
                        contact.groups.push($(this).text());
                    });
                    that.contacts[$(this).attr('jid')] = contact;
                    return true;
                });

                // let user code know something happened
                $(document).trigger('roster_changed', that);
                return true;
            });*/
			//</editor-fold>
        } else if (status === Strophe.Status.DISCONNECTED) {
            // set all users offline
            for (var contact in this.contacts) {
                this.contacts[contact].resources = {};
            }
            
            // notify user code
            $(document).trigger('roster_changed', this);
            return true;
        }
    	
    	return true;
    },

    // called when roster udpates are received
    /*rosterChanged: function (iq) {
    	var item = $(iq).find('item');
        var jid = item.attr('jid');
        var subscription = item.attr('subscription') || "";
        
        if (subscription === "remove") {
            // removing contact from roster
            delete this.contacts[jid];
        } else if (subscription === "none") {
            // adding contact to roster
            var contact = new Contact();
            contact.name = item.attr('name') || "";
            item.find("group").each(function () {
                contact.groups.push(this.text());
            });
            this.contacts[jid] = contact;
        } else {
            // modifying contact on roster
            var contact = this.contacts[jid];
            contact.name = item.attr('name') || contact.name;
            contact.subscription = subscription || contact.subscription;
            contact.ask = item.attr('ask') || contact.ask;
            contact.groups = [];
            item.find("group").each(function () {
                contact.groups.push($(this).text());
            });
        }
        
        // acknowledge receipt
        this.connection.send($iq({type: "result", id: $(iq).attr('id')}));
        
        // notify user code of roster changes
        $(document).trigger("roster_changed", this);
        
        return true;
    },*/

    // called when presence stanzas are received
    presenceChanged: function (presence) {
		//try{console.log('strophe.roster.presenceChanged',presence)}catch(e){}
		var from = $(presence).attr("from");

		if(Strophe.getDomainFromJid(from) == ChatConfig.CONFERENCE_DOMAIN
			&& Strophe.getResourceFromJid(from) != ChatConfig.DEFAULT_RESOURCE) // If this presence is from muc, handle it in connection.muc
		{
			connection.muc.presenceChanged(presence);
			return true;
		}

        var jid = Strophe.getBareJidFromJid(from);
        var resource = Strophe.getResourceFromJid(from);
        var ptype = $(presence).attr("type") || "available";
              		
		if(jid == Strophe.getBareJidFromJid(connection.jid) || ptype === "error"){ // if this presence is from same jid, return
			// ignore presence updates from things not on the roster as well as error presence
		    return true;
		}
		
		if (ptype === "unavailable") {
		    // remove resource, contact went offline
			if(connection.roster.contacts[Strophe.getNodeFromJid(jid)])
				connection.roster.contacts[Strophe.getNodeFromJid(jid)].clearResources();
		} else
			RosterManager.setFromPresence(presence);		

		// notify user code of roster changes
		$(document).trigger("roster_changed", this);
		return true;
    },

    // add a contact to the roster
    addContact: function (jid, name, groups) {
        var iq = $iq({type: "set"})
            .c("query", {xmlns: Strophe.NS.ROSTER})
            .c("item", {name: name || "", jid: jid});
        if (groups && groups.length > 0) {
            $.each(groups, function () {
                iq.c("group").t(this).up();
            });
        }
        this.connection.sendIQ(iq);
    },
    
    // delete a contact from the roster
    deleteContact: function (jid) {
        var iq = $iq({type: "set"})
            .c("query", {xmlns: Strophe.NS.ROSTER})
            .c("item", {jid: jid, subscription: "remove"});
        this.connection.sendIQ(iq);
    },

    isContactOnRoster : function( jid ) {
    	for(var contact in this.contacts)
    	{
    		if(contact == jid)
    			return true;			
    	}
    	return false;
    },

	fetchRoster: function(jid){

		var iq = $iq({from:jid, type: "get"})
            .c("query", {xmlns: Strophe.NS.ROSTER});
        this.connection.sendIQ(iq);
	},

    /* modify a roster contact
    modifyContact: function (jid, name, groups) {
        this.addContact(jid, name, groups);
    },*/

    // subscribe to a new contact's presence
    subscribe: function (jid, name, groups) {
        this.addContact(jid, name, groups);
        
        var presence = $pres({to: jid, "type": "subscribe"});
        this.connection.send(presence);
    },
    
    // unsubscribe from a contact's presence
    unsubscribe: function (jid) {
        var presence = $pres({to: jid, "type": "unsubscribe"});
        this.connection.send(presence);
        this.deleteContact(jid);
    },
    
    //Approve a subscription request from jid
    approveSubscription : function(jid) {
    	var presence = $pres({to: jid, "type": "subscribed"});
        this.connection.send(presence);        
    },
    
    //Reject a subscription request from jid
    rejectSubscription : function(jid) {
    	var presence = $pres({to: jid, "type": "unsubscribed"});
        this.connection.send(presence);        
    },

	sendPresence : function(jid, id, name, image, mood, language_code, language_id, language_name, show){
		var fj = Strophe.getBareJidFromJid(connection.jid) + '/' + Strophe.getResourceFromJid(connection.jid);
		var attrs = (!jid)?{from:fj}:{from:fj, to:jid};
		
		if(show)
			var pres_req = $pres(attrs).c('user',{id:id, name:name, image:image, mood:mood}).
										up().c('language',{id:language_id, code:language_code}).t(language_name)
										.up().c('show').t(show);
		else
			var pres_req = $pres(attrs).c('user',{id:id, name:name, image:image, mood:mood}).
										up().c('language',{id:language_id, code:language_code}).t(language_name)

		this.connection.send(pres_req.tree());
	},

	disconnect : function(jid)
	{
		var pres_req = null;

		if(jid && jid.length > 0)
			pres_req = $pres({type: "unavailable", from:connection.jid, to:jid});
		else
			pres_req = $pres({type: "unavailable", from:connection.jid});

		this.connection.send(pres_req.tree());
	}
});
