/**
 * Copyright (c) 2010 Laszlo Systems, Inc.
 * All Rights Reserved.
 *
 * @author mdemmon
 * 
 * Provides an API to interact with the Strophe library to make use of a
 * BOSH connection.
 */
function StropheWrapper() {
    this.connection = null;
    this.connectionStatus = 'disconnected';
    this.loggingEnabled = false;
    this.rawLoggingEnabled = false;
    this.msgTypes = {
        status: true,
        log:true,
        rawin:true,
        rawout:true,
        stanza:true
    };

    var self = this;

    /** Sends messages into the webtop application. */
    this.msg = function(type, msg) {
        // Validate type
        if (!this.msgTypes[type]) {
            msg = "Invalid type: " + type;
            type = "log";
        }
        Lz.setCanvasAttribute('stropheMsg', type+':'+msg);
    }

    /** Sends a logging message into the webtop application. */
    this.log = function(msg) {
        if (this.loggingEnabled) this.msg('log', msg);
    }

    /** HANDLERS */
    this.onConnect = function(status) {
        if (status == Strophe.Status.CONNECTING) {
            self.connectionStatus = 'connecting';
        } else if (status == Strophe.Status.CONNFAIL) {
            self.connectionStatus = 'connectionfail';
        } else if (status == Strophe.Status.DISCONNECTING) {
            self.connectionStatus = 'disconnecting';
        } else if (status == Strophe.Status.DISCONNECTED) {
            self.connectionStatus = 'disconnected';
        } else if (status == Strophe.Status.CONNECTED || status == Strophe.Status.ATTACHED) {
            self.connectionStatus = 'connected';
        }
        self.msg('status', self.connectionStatus);
    }

    /** Sends debugging info into the webtop application for the "raw" incoming
        BOSH responses from the XMPP server. */
    this.rawInput = function(data) {
        if (self.rawLoggingEnabled) self.msg('rawin', data);
    }

    /** Sends debugging info into the webtop application for the "raw" outgoing
        BOSH requests to the XMPP server. */
    this.rawOutput = function(data) {
        if (self.rawLoggingEnabled) self.msg('rawout', data);
    }

    /** Sends XMPP stanzas into the webtop application. */
    this.handleStanza = function(stanza) {
        self.msg('stanza', Strophe.serialize(stanza, true));
        return true;
    }

    /** PUBLIC API */
    this.setLoggingLevel = function(loggingEnabled, rawLoggingEnabled) {
        this.loggingEnabled = loggingEnabled;
        this.rawLoggingEnabled = rawLoggingEnabled;
    }

    /** Creates a strophe connection object. */
    this.createConnection = function(service) {
        if (this.connection) return;
        
        this.connection = new Strophe.Connection(service);
        this.connection.rawInput = this.rawInput;
        this.connection.rawOutput = this.rawOutput;
        
        return true;
    }

    /** Adds connection handlers to the StropheConnection. */
    this.addHandler = function(ns, name, type, id, from) {
        if (!this.connection) return;
        this.connection.addHandler(this.handleStanza, ns, name, type, id, from);
    }

    /** Connects to the XMPP server. */
    this.connect = function(jid, pass) {
        if (!this.connection) return;
        if (this.connectionStatus == 'disconnected' || 
            this.connectionStatus == 'connectionfail'
        ) {
            this.connection.connect(jid, pass, this.onConnect);
        }
    }

    this.disconnect = function() {
        if (!this.connection) return;
        this.connection.disconnect();
    }

    /** Must be called after you disconnect before reusing a connection. */
    this.reset = function() {
        if (!this.connection) return;
        this.connection.reset();
        
        // Under normal operation this should never occur.
        if (this.connectionStatus != 'disconnected') {
            this.connectionStatus = 'disconnected';
            this.msg('status', this.connectionStatus);
        }
    }

    /** XMPP PRESENCE API */
    this.xmppPresence = function(available, show, status, priority) {
        if (!this.connection) return;
        if (this.connectionStatus != 'connected') return;
        
        var domElem = new Strophe.Builder('presence');
        if (available) domElem.attrs({type:available});
        if (show) domElem.c('show').t(show).up();
        for (lang in status) {
            var value = status[lang];
            if (value) {
                domElem.c('status', {'xml:lang':lang}).t(value).up();
            }
        }
        if (priority != 0) domElem.c('priority').t(priority);
        
        this.connection.send(domElem.tree());
    }

    this.xmppSubscribe = function(to) {
        this._xmppSubscription(to, 'subscribe');
    }

    this.xmppSubscribed = function(to) {
        this._xmppSubscription(to, 'subscribed');
    }

    this.xmppUnsubscribed = function(to) {
        this._xmppSubscription(to, 'unsubscribed');
    }

    this._xmppSubscription = function(to, type) {
        if (!this.connection) return;
        if (this.connectionStatus != 'connected') return;
        
        var domElem = new Strophe.Builder('presence', {
            type:type,
            to:to
        });
        
        this.connection.send(domElem.tree());
    }

    /** XMPP MESSAGING API */
    this.xmppMessageChat = function(to, from, msg, xmsg) {
        if (!this.connection) return;
        if (this.connectionStatus != 'connected') return;
        
        var domElem = new Strophe.Builder('message', {
            to: to,
            from: from,
            type: 'chat'
        });
        if (msg) domElem.c('body').t(msg).up();
        if (xmsg) domElem.c('xmesg').t(xmsg);
        
        this.connection.send(domElem.tree());
    }

    /** XMPP ROSTER API */
    this.xmppGetRoster = function(from, id) {
        if (!this.connection) return;
        if (this.connectionStatus != 'connected') return;
        
        var domElem = new Strophe.Builder('iq', {
            from:from,
            type:'get',
            id:id
        }).c('query', {
            xmlns:'jabber:iq:roster'
        });
        
        this.connection.send(domElem.tree());
    }

    this.xmppAddToRoster = function(from, id, jid, name, groups) {
        this._xmppRoster(from, id, jid, name, groups, null);
    }

    this.xmppUpdateInRoster = function(from, id, jid, name, groups) {
        this._xmppRoster(from, id, jid, name, groups, null);
    }

    this.xmppRemoveFromRoster = function(from, id, jid) {
        this._xmppRoster(from, id, jid, null, [], 'remove');
    }

    this._xmppRoster = function(from, id, jid, name, groups, subscription) {
        if (!this.connection) return;
        if (this.connectionStatus != 'connected') return;
        
        var domElem = new Strophe.Builder('iq', {
            from:from,
            type:'set',
            id:id
        }).c('query', {
            xmlns:'jabber:iq:roster'
        }).c('item', {
            jid:jid
        });
        if (name) domElem.attrs({name:name});
        if (subscription) domElem.attrs({subscription:subscription});
        for (var i = 0; groups.length > i; i++) {
            domElem.c('group').t(groups[i]).up();
        }
        
        this.connection.send(domElem.tree());
    }
}
