private void sendCommand(JObject c, object to, Action <object> fn, bool once)
        {
            //c = new SympleCommand(c, to);
            c = new SympleCommand(c); // NOTE: removed "to" since I don't know what to do with it
            this.send(c);

            if (fn != null)
            {
                JObject filters = new JObject();
                filters["id"] = c["id"];

                Action <object> after = (res) =>
                {
                    JObject resObj = (JObject)res;
                    int     status = (int)resObj["status"];

                    if (once || (
                            // 202 (Accepted) and 406 (Not acceptable) responses codes
                            // signal that the command has not yet completed.
                            status != 202 && status != 406))
                    {
                        this.clear("command", fn);
                    }
                };

                this.onResponse("command", filters, fn, after);
            }
        }
        public void connect()
        {
#if NETFX_CORE
            Messenger.Broadcast(SympleLog.LogInfo, "symple:client: connecting");

            if (this.socket != null)
            {
                string err = "the client socket is not null";
                Messenger.Broadcast(SympleLog.LogError, err);
                throw new Exception(err);
            }

            this.socket = IO.Socket(this.options["url"].ToString(), this.ioOptions);
            this.socket.On(Socket.EVENT_CONNECT, () => {
                Messenger.Broadcast(SympleLog.LogInfo, "symple:client: connected");
                Messenger.Broadcast(SympleLog.Connected);

                JObject announceData  = new JObject();
                announceData["user"]  = this.peer["user"] ?? "";
                announceData["name"]  = this.peer["name"] ?? "";
                announceData["type"]  = this.peer["type"] ?? "";
                announceData["token"] = options["token"] ?? "";

                string announceDataJsonString = JsonConvert.SerializeObject(announceData, Formatting.None);
                Messenger.Broadcast(SympleLog.LogTrace, "announceDataJsonString: " + announceDataJsonString);

                this.socket.Emit("announce", (resObj) => {
                    Messenger.Broadcast(SympleLog.LogDebug, "symple:client: announced " + resObj);
                    Messenger.Broadcast(SympleLog.Announced);

                    JObject res = (JObject)resObj;

                    if ((int)res["status"] != 200)
                    {
                        this.setError("auth", resObj.ToString());
                        return;
                    }

                    JObject resData = (JObject)res["data"];

                    this.peer = Symple.extend(this.peer, resData);
                    this.roster.add(resData);

                    JObject sendPresenceParams  = new JObject();
                    sendPresenceParams["probe"] = true;

                    this.sendPresence(sendPresenceParams);
                    this.dispatch("announce", res);
                    this.socket.On(Socket.EVENT_MESSAGE, (msg) =>
                    {
                        Messenger.Broadcast(SympleLog.LogTrace, "symple:client receive " + msg);

                        JObject m = (JObject)msg;

                        string mType = (string)m["type"];

                        switch (mType)
                        {
                        case "message":
                            m = new SympleMessage(m);
                            break;

                        case "command":
                            m = new SympleCommand(m);
                            break;

                        case "event":
                            m = new SympleEvent(m);
                            break;

                        case "presence":
                            m = new SymplePresence(m);
                            if ((bool)m["data"]["online"])
                            {
                                this.roster.update((JObject)m["data"]);
                            }
                            else
                            {
                                this.roster.remove((string)m["data"]["id"]);
                            }

                            if (m["probe"] != null && (bool)m["probe"] == true)
                            {
                                JObject presenceTo = new JObject();
                                presenceTo["to"]   = Symple.parseAddress(m["from"].ToString())["id"];

                                this.sendPresence(new SymplePresence(presenceTo));
                            }
                            break;

                        default:
                            var o     = m;
                            o["type"] = o["type"] ?? "message";
                            break;
                        }

                        if (m["from"].Type != JTokenType.String)
                        {
                            Messenger.Broadcast(SympleLog.LogError, "symple:client: invalid sender address: " + m);
                            return;
                        }

                        // replace the from attribute with the full peer object.
                        // this will only work for peer messages, not server messages.

                        string mFrom = (string)m["from"];
                        Messenger.Broadcast(SympleLog.LogTrace, "looking up rpeer in roster, mFrom = " + mFrom + "...");

                        var rpeer = this.roster.get(mFrom);
                        if (rpeer != null)
                        {
                            Messenger.Broadcast(SympleLog.LogTrace, "found rpeer: " + rpeer);
                            m["from"] = rpeer;
                        }
                        else
                        {
                            Messenger.Broadcast(SympleLog.LogDebug, "symple:client: got message from unknown peer: " + m);
                        }

                        // Dispatch to the application
                        this.dispatch((string)m["type"], m);
                    });
                }, announceData);
            });

            this.socket.On(Socket.EVENT_ERROR, () =>
            {
                // this is triggered when any transport fails, so not necessarily fatal
                this.dispatch("connect");
            });

            this.socket.On("connecting", () =>
            {
                Messenger.Broadcast(SympleLog.LogDebug, "symple:client: connecting");
                this.dispatch("connecting");
            });

            this.socket.On(Socket.EVENT_RECONNECTING, () =>
            {
                Messenger.Broadcast(SympleLog.LogDebug, "symple:client: connecting");
                Messenger.Broadcast(SympleLog.Reconnecting);
                this.dispatch("reconnecting");
            });

            this.socket.On("connect_failed", () =>
            {
                // called when all transports fail
                Messenger.Broadcast(SympleLog.LogError, "symple:client: connect failed");
                Messenger.Broadcast(SympleLog.ConnectFailed);
                this.dispatch("connect_failed");
                this.setError("connect");
            });

            this.socket.On(Socket.EVENT_DISCONNECT, (data) =>
            {
                try
                {
                    Messenger.Broadcast(SympleLog.LogInfo, "symple:client: disconnect");

                    string msg = (string)data;
                    Messenger.Broadcast(SympleLog.LogInfo, "symple:client: disconnect msg: " + msg);

                    Messenger.Broadcast(SympleLog.Disconnect);
                    this.peer["online"] = false;
                    this.dispatch("disconnect");
                }
                catch (Exception e)
                {
                    Messenger.Broadcast(SympleLog.LogInfo, "caught exception: " + e.Message);
                }
            });
#endif
        }