
var EDGY = EDGY || {};

EDGY.new_java_transport = function () {
    var pkt_applet = undefined; 

    var load_pkt_applet = function (extra_params) {
        var browser_specific_part = $.browser.msie ?
                        "classid='clsid:8AD9C840-044E-11D1-B3E9-00805F499D93'" :
                        "type='application/x-java-applet'";
        var params = {
            code: "com/edgynet/pktclient/PktApplet.class",
            archive: "/applets/pktclient.jar",
            java_version: "1.6+",
            classloader_cache: false,         // works for java 1.6.10+ 
            cache_option: "Browser",
            mayscript: true,
            port: 7777
        };
        if (extra_params) {
            for (var k in extra_params) {
                params[k] = extra_params[k];
            }
        }
        var param_tags = "";
        for (var k in params) {
            param_tags += "    <param name='" + k + "' value='" + params[k] + "'/> \n";
        }
        var object_tag = 
            "<object id='pkt_applet' \n" + 
            "        " + browser_specific_part + " \n" +
            "        width='0' \n" +
            "        height='0'> \n" +
            param_tags +
            "</object> \n";
        $("body").append($(object_tag));
        pkt_applet = document.getElementById("pkt_applet");
    };

    var unload_pkt_applet = function () {
        $("#pkt_applet").remove();
    };

    var java_tcp_transport = {
        applet_timeout_ref: null,
        on_connect_cb: null,
        on_message_cb: null,
        pre_connect_buffer: [],
        init: function (on_connect_cb, on_message_cb) {
            this.on_connect_cb = on_connect_cb;
            this.on_message_cb = on_message_cb;
            var meeting_point = "pkt_applet_listener";
            var connect_timeout = 20 * 1000;
            // Applet download + jvm initialization could take a while
            var applet_timeout = 60 * 1000;

            window[meeting_point] = this;    
            var on_applet_timeout = function () {
                on_connect_cb(false);
                java_tcp_transport._destroy();
            };
            this.applet_timeout_ref = window.setTimeout(
                                                on_applet_timeout, 
                                                applet_timeout);
            load_pkt_applet({
                meeting_point: meeting_point,
                connect_timeout: connect_timeout
            });
        },
        on_tcp: function (connected) {  
            window.clearTimeout(this.applet_timeout_ref);
            this.on_connect_cb(connected);
            this.connected = connected;
            if (connected) {
                var s;
                while ((s = this.pre_connect_buffer.pop()) !== undefined) {
                    this.send(s); 
                }
            } else {
                this._destroy();
            }
        },
        recv: function (javaStr) {
            var s = "" + javaStr;                           // for Opera
            this.on_message_cb(s);
        },
        send: function (s) {
            if (this.connected) {
                pkt_applet.send("" + s);            // just to be safe
            } else {
                this.pre_connect_buffer.push(s);
            }
        },
        _destroy: function () {
            // todo - if connected then disconnect
            var task = function () {
                unload_pkt_applet();
            };
            window.setTimeout(task, 0);
        }
    };
    return java_tcp_transport;
};

EDGY.new_pubsub = function (transport_type) {
    var new_comet_pubsub = function () {
        var pubsub = {
            client_id: null,
            init: function (client_on_connect_cb) {
                var on_handshake = function (msg) {
                    if (msg.successful) {
                        var client_id = msg.clientId;
                        pubsub.client_id = client_id;
                        client_on_connect_cb(client_id);
                    } else {
                        client_on_connect_cb(false);
                    }
                };
                $.cometd.addListener("/meta/handshake", this, on_handshake);
                $.cometd.init("/bayx");
                $(window).unload(function () {
                    $.cometd.disconnect();  
                });
            },
            subscribe: function (channel, context, callback) {
                return $.cometd.subscribe(channel, context, callback);
            },  
            unsubscribe: function (subscription_ref) {
                $.cometd.unsubscribe(subscription_ref);
            },  
            publish: function (channel, payload) {
                $.cometd.publish(channel, payload);
            }   
        };  
        return pubsub;
    };  

    var new_java_pubsub = function () {
        var pubsub = {
            transport: null,
            client_id: null,
            subscriptions: [],
            client_on_connect_cb: null,
            keepalive_task: null,
            init: function (client_on_connect_cb) {
                this.client_on_connect_cb = client_on_connect_cb
                this.transport = EDGY.new_java_transport();
                var on_tcp_connect = function (connected) {
                    pubsub.on_tcp_connect(connected);
                };
                var on_message = function (s) {
                    pubsub.on_message(s);
                };
                this.transport.init(on_tcp_connect, on_message);
                this._send("connect");
            },
            on_tcp_connect: function (connected) {
                if (! connected) {
                    this.client_on_connect_cb(false);
                }
            },
            on_message: function (s) {
                if (! this.client_id) {
                    this._expect_connect(s);
                } else if (s.match(/^message/)) {
                    this._handle_message(s);
                } else if (s.match(/^disconnect/)) {
                    this._handle_disconnect(s);
                }
            },
            subscribe: function (channel, cb_context, cb) {
                var callback = function (msg) {
                    cb.call(cb_context, msg);
                };
                var msg = "subscribe " + channel;
                this._send(msg);
                this.subscriptions[channel] = callback;
                return channel;         // use channel as a subscription ref
            },
            unsubscribe: function (channel) {
                if (this.subscriptions[channel]) {
                    this.subscriptions[channel] = undefined;
                    var msg = "unsubscribe " + channel;
                    this._send(msg);
                }
            },
            publish: function (channel, payload) {
                var msg = "publish " + channel + "\r\n" + payload;
                this._send(msg);
            },
            _send: function (msg) {
                // send all messages - even if we're not yet connected
                this.transport.send(msg);
            },
            _expect_connect: function (s) {
                var id = s.replace(/^connect_ok ([a-zA-Z0-9]+)$/, "$1");
                if (id !== s) {
                    this.client_id = id;
                    this.client_on_connect_cb(id);
                    var keepalive = function () {
                        pubsub._send("noop");
                    };
                    this.keepalive_task = window.setInterval(keepalive, 60 * 1000);
                } 
                // otherwise just drop the message 
            },
            _handle_message: function (s) {
                var r = s.match(/^message ([^\r]+)\r\n/);
                if (r) {
                    var channel = r[1];
                    var payload = s.substring(s.indexOf("\r\n") + 2);
                    var callback = this.subscriptions[channel];
                    if (callback) {
                        // TODO - make message returned fully compatible with cometd msg
                        callback({data: payload});
                    }
                }
            },
            _handle_disconnect: function (s) {
                // todo
            }
        };  
        return pubsub;
    };

    if (transport_type === "comet" || transport_type === undefined) {
        return new_comet_pubsub();
    } else if (transport_type === "java_tcp") {
        return new_java_pubsub();
    }
    return null;
};


