/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is JIM.
 *
 * The Initial Developer of the Original Code is
 * Pawel Chmielowski <prefiks@o2.pl>
 *
 * Portions created by the Initial Developer are Copyright (C) 2003
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 * Pawel Chmielowski <prefiks@o2.pl>
 *
 * ***** END LICENSE BLOCK ***** */

/**
 * services.Core
 *
 *
 */
ML.load("utils/observable.js");
ML.load("utils/debug.js");
ML.load("xml/xmldomutils.js");
ML.load("xml/xmldombuilder.js");
ML.load("xml/xmldomparser.js");
ML.load("xml/xmlsocketlistener.js");

ML.load("services/iq/auth.js");
ML.load("services/iq/time.js");
ML.load("services/iq/version.js");
ML.load("services/iq/roster.js");
ML.load("services/iq/register.js");
ML.load("services/iq/search.js");
ML.load("services/iq/agents.js");
ML.load("services/iq/avatar.js");
ML.load("services/iq/last.js");
ML.load("services/iq/gateway.js");
ML.load("services/iq/vcard.js");
ML.load("services/iq/private.js");

ML.load("services/highlevel/users.js");
ML.load("services/highlevel/avatars.js");
ML.load("services/highlevel/iconstyles.js");
ML.load("services/highlevel/accounts.js");
ML.load("services/highlevel/agents.js");
ML.load("services/highlevel/statustext.js");
/**
 * CoreServise
 *   jabber:client protocol handler
 *
 * Constructors:
 *   CoreService(jabberService) - constructor
 *
 * Fields:
 *   iq - handlers of jabber:iq:* protocols
 *   uid - current user UID
 *   uidShort - current user UID
 *
 * Methods:
 *   message(to, body, subject, thread) - sends message with raw text as body
 *   messageTag(to, body, subject, thread) - sends message with XMLDOM object as body
 *   presence(from, to, type, show, status, body, priority)
 *   presenceTag(from, to, type, show, status, body, priority)
 *   subscribe(to, status)
 *   subscribed(to)
 *   unsubscribe(to, status)
 *   iqTag(from, to, id, type, body, handler)
 *   iqError(from, to, id, errorCode, errorBody)
 *
 * Events:
 *   onMessageSend(tag)
 *   onPresenceSend(tag)
 *   onSubscribeSend(tag)
 *   onSubscribedSend(tag)
 *   onUnsubscribeSend(tag)
 *   onIQSend(tag)
 *   onIQErrorSend(tag)
 *   onMessage(tag)
 *   onPresence(tag)
 *   onIQ(tag)
 *   onIQResponse(tag)
 *   onIQHandler(tag)
 *   onIQError(tag)
 *   onRecv(tag)
 *
 */

function CoreService(jabberService)
{
    this.base = Observable;
    this.base();

    this.iqMsgHandlers = {};
    this.iqHandlers = {};
    this.jabberService = jabberService;
    this.parser = new XMLDOMParser();
    this.socketListener = new XMLSocketListener(this.parser, null, this);

    jabberService.core = this;

    this.iq = {};
    this.iq.auth = new IQAuth(jabberService);
    this.iq.time = new IQTime(jabberService);
    this.iq.version = new IQVersion(jabberService);
    this.iq.roster = new IQRoster(jabberService);
    this.iq.register = new IQRegister(jabberService);
    this.iq.search = new IQSearch(jabberService);
    this.iq.agents = new IQAgents(jabberService);
    this.iq.avatar = new IQAvatar(jabberService);
    this.iq.last = new IQLast(jabberService);
    this.iq.gateway = new IQGateway(jabberService);
    this.iq.vCard = new IQVCard(jabberService);
    this.iq.privat = new IQPrivate(jabberService);

    this.highlevel = {};
    this.highlevel.users = new HLUsers(jabberService);
    this.highlevel.avatars = new HLAvatars(jabberService);
    this.highlevel.iconstyles = new HLIconStyles(jabberService);
    this.highlevel.accounts = new HLAccounts(jabberService);
    this.highlevel.agents = new HLAgents(jabberService);
    this.highlevel.statustext = new HLStatusText(jabberService);

    for (var i in this.iq)
        this.iqHandlers[this.iq[i].namespaceURI] = this.iq[i];

    this.parser.setHandler(this);
    this.socketListener.setSocket(jabberService.socket);
    this.jabberService.addObserver(this);
}

CoreService.prototype =
{
    __proto__: Observable.prototype,
    uid: null,
    uidShort: null,
    timeout: 60*1000,

    message: function(to, type, body, subject, thread)
    {
        this.messageTag(to, type, DB.createElement("jabber:client", "body").
            addText(body), subject, thread);
    },

    messageTag: function(to, type, body, subject, thread)
    {
        var tag = DB.createElement("jabber:client", "message",
            "from", this.uid,
            "type", type,
            "to", to);
        if (subject)
            tag.addElement("jabber:client", "subject").addText(subject);
        if (thread)
            tag.addElement("jabber:client", "thread").addText(thread);
        tag.addDOM(body);

        this.fireEvent("onMessageSend", tag);
        this.jabberService.send(tag);
    },

    presence: function(from, to, type, show, status, body, priority)
    {
        this.presenceTag(from, to, type, show, status, 
            body ? DB.createElement("jabber:client", "body").addText(body) : null, priority);
    },

    presenceTag: function(from, to, type, show, status, body, priority)
    {
        var tag = DB.createElement("jabber:client", "presence",
            "from", from == "" ? this.uid : from,
            "to", to,
            "type", type);
        if (show)
            tag.addElement("jabber:client", "show").addText(show);
        if (priority)
            tag.addElement("jabber:client", "priority").addText(priority);
        if (status != null)
            tag.addElement("jabber:client", "status").addText(status);
        tag.addDOM(body);

        this.fireEvent("onPresenceSend", tag);
        this.jabberService.send(tag);
    },

    subscribe: function(to, status)
    {
        var tag = DB.createElement("jabber:client", "presence",
            "to", to,
            "type", "subscribe");
        if (status)
            tag.addElement("jabber:client", "status").addText(status);

        this.fireEvent("onSubscribeSend", tag);
        this.jabberService.send(tag);
    },

    subscribed: function(to)
    {
        var tag = DB.createElement("jabber:client", "presence",
            "to", to,
            "type", "subscribed");

        this.fireEvent("onSubscribedSend", tag);
        this.jabberService.send(tag);
    },

    unsubscribe: function(to, status)
    {
        var tag = DB.createElement("jabber:client", "presence",
            "to", to,
            "type", "unsubscribe");
        if (status)
            tag.addElement("jabber:client", "status").addText(status);

        this.fireEvent("onUnsubscribeSend", tag);
        this.jabberService.send(tag);
    },

    unsubscribed: function(to)
    {
        var tag = DB.createElement("jabber:client", "presence",
            "to", to,
            "type", "unsubscribed");

        this.fireEvent("onUnsubscribeSend", tag);
        this.jabberService.send(tag);
    },

    iqTag: function(from, to, id, type, body, handler)
    {
        var tag = DB.createElement("jabber:client", "iq",
            "from", from == "" ? this.uid : from,
            "to", to,
            "id", id,
            "type", type);
        if (body)
            tag.addDOM(body);

        this.fireEvent("onIQSend", tag);
        id = this.jabberService.send(tag);

        if (handler)
            this.iqMsgHandlers[id] = [handler, 
                setTimeout(this.sendTimeoutError, this.timeout, this, id, to)];
        return id;
    },

    iqError: function(from, to, id, errorCode, errorBody)
    {
        var tag = DB.createElement("jabber:client", "iq",
            "from", from,
            "to", to,
            "id", id,
            "type", "error");
        tag.addElement("jabber:client", "error",
            "code", ""+errorCode).addText(errorBody);

        this.fireEvent("onIQErrorSend", tag);
        this.jabberService.send(tag);
    },

    cancelResponse: function(msgid)
    {
        var h = this.iqMsgHandlers[msgid];

        if (h) {
            clearTimeout(h[1]);
            delete this.iqMsgHandlers[msgid];
        }
    },

    sendTimeoutError: function(_this, id, from)
    {
        var tag = DB.createElement("jabber:client", "iq",
            "from", from,
            "id", id,
            "type", "error");
            tag.addElement("jabber:client", "error",
            "code", "408").addText("Request Timeout")

        _this.onCompleteTag(tag);
    },

    onParserError: function(ex, data)
    {
        this.jabberService.handleError(ex, data);
    },

    onStartTag: function(tag)
    {
        if (tag.namespaceURI == "http://etherx.jabber.org/streams") {
            if (tag.localName == "stream")
                this.streamId = tag.getAttribute("id");
            tag.type = 1;
            this.fireEvent("onRecv", tag);
            this.jabberService.__gotResponse();

            return false;
        }
        return true;
    },

    onCompleteTag: function(tag)
    {
        var h;

        tag.type = 0;
        this.fireEvent("onRecv", tag);
        if (tag.namespaceURI == "jabber:client") {
            if (tag.localName == "message")
                this.fireEvent("onMessage", tag);
            else if (tag.localName == "presence") {
                this.fireEvent("onPresence", tag);
            } else if (tag.localName == "iq") {
                if (h = this.iqMsgHandlers[tag.getAttribute("id")]) {
                    this.cancelResponse(tag.getAttribute("id"));
                    if (h[0].onIQResponse)
                        h[0].onIQResponse(tag);
                } else if ((h = tag.firstChildElement) && 
                    (h = this.iqHandlers[h.namespaceURI])) {
                    if (h.onIQHandler)
                        h.onIQHandler(tag);
                } else if (tag.getAttribute("type") != "error") {
                    this.iqError(tag.getAttribute("to"),
                        tag.getAttribute("from"),
                        tag.getAttribute("id"),
                        501,
                        "Not Implemented");
                    this.fireEvent("onIQ", tag);
                } else {
                    this.fireEvent("onIQError", tag);
                }
            }
        }
    },

    onEndTag: function(tag)
    {
        tag.type = 2;
        this.fireEvent("onRecv", tag);
    },

    onDisconnect: function(status)
    {
        var i;
        for (i in this.iqMsgHandlers)
            clearTimeout(this.iqMsgHandlers[i][1]);
        this.iqMsgHandlers = { };
    },
}
