var Hippie = function(host, arg, on_connect, on_disconnect, on_event, path) {

    this.arg = arg ? arg : '';
    this.on_disconnect = on_disconnect;
    this.on_connect = on_connect;
    this.on_event = on_event;
    this.path = path ? path : '';
    this.detect();

    if (!host.match('://')) {// protcol not provided
        host = document.location.protocol.replace(/http/, 'ws') + '//' + host;
    }

    var that = this;
    if (this.mode == 'ws') {
        this.init = function() {
            ws = new WebSocket(host+that.path+"/_hippie/ws/"+that.arg + '?client_id=' + (that.client_id || ''));
            ws.onmessage = function(ev) {
                var d = eval("("+ev.data+")");
                if (d.type == "hippie.pipe.set_client_id") {
                    that.client_id = d.client_id;
                }
                that.on_event(d);
            }
            ws.onclose = ws.onerror = function(ev) {
                that.on_disconnect();
            }
            ws.onopen = function() {
                that.on_connect();
            }
            that.ws = ws;
        };
    }
    else if (this.mode == 'mxhr') {
        this.init = function() {
            var s = new DUI.Stream();
            // XXX: somehow s.listeners are shared between objects.
            // maybe a DUI class issue?  this workarounds issue where
            // reconnect introduces duplicated listeners.
            s.listeners = {};
            s.listen('application/json', function(payload) {
                var event = eval('(' + payload + ')');
                if (event.type == "hippie.pipe.set_client_id") {
                    that.client_id = event.client_id;
                }
                that.on_event(event);
            });
            s.listen('complete', function() {
                that.on_disconnect();
            });
            s.load(that.path + "/_hippie/mxhr/" + that.arg + '?client_id=' + (that.client_id || ''));
            that.on_connect();
            that.mxhr = s;
        };
    }
    else if (this.mode == 'poll') {
        this.init = function() {
            $.ev.loop(that.path + '/_hippie/poll/' + that.arg,
                      { '*': that.on_event,
                        'hippie.pipe.set_client_id': function(e) {
                            that.client_id = e.client_id;
                            $.ev.url = that.path + '/_hippie/poll/' + that.arg + '?client_id=' + e.client_id;
                            that.on_event(e);
                        }
                      }
                     );
            that.on_connect();
        }
    }
    else {
        throw new Error("unknown hippie mode: "+this.mode);
    }

    this.init();
};

Hippie.prototype = {
    detect: function() {
        var match = /hippie\.mode=(\w+)/.exec(document.location.search);
        if (match) {
            this.mode = match[1];
        }
        else {
            if ("WebSocket" in window) {
                this.mode = 'ws';
            }
            else {
                var req;
                try {
                    try { req = new ActiveXObject('MSXML2.XMLHTTP.6.0'); } catch(nope) {
                        try { req = new ActiveXObject('MSXML3.XMLHTTP'); } catch(nuhuh) {
                            try { req = new XMLHttpRequest(); } catch(noway) {
                                throw new Error('Could not find supported version of XMLHttpRequest.');
                            }
                        }
                    }
                }
                catch(e) {
                    this.mode = 'poll';
                    return;
                }

                this.mode = 'mxhr';
            }
        }
    },
    send: function(msg) {
        if (this.ws) {
            this.ws.send(JSON.stringify(msg));
        }
        else {
            var that = this;
            jQuery.ajax({
                url: this.path + "/_hippie/pub/"+this.arg,
                beforeSend: function(xhr, s) {
		    xhr.setRequestHeader("X-Hippie-ClientId", that.client_id);
                    return true;
                },
                data: { message: JSON.stringify(msg) },
                type: 'post',
                dataType: 'json',
                success: function(r) { }
            });
        }
    }
};
