// Generated by CoffeeScript 1.7.1

/*
 *Plugin to implement the MUC extension.
   http://xmpp.org/extensions/xep-0045.html
 *Previous Author:
    Nathan Zorn <nathan.zorn@gmail.com>
 *Complete CoffeeScript rewrite:
    Andreas Guth <guth@dbis.rwth-aachen.de>
 */

(function() {
  var Occupant, RoomConfig, XmppRoom,
    __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };

  Strophe.addConnectionPlugin('muc', {
    _connection: null,
    rooms: {},
    roomNames: [],

    /*Function
    Initialize the MUC plugin. Sets the correct connection object and
    extends the namesace.
     */
    init: function(conn) {
      this._connection = conn;
      this._muc_handler = null;
      Strophe.addNamespace('MUC_OWNER', Strophe.NS.MUC + "#owner");
      Strophe.addNamespace('MUC_ADMIN', Strophe.NS.MUC + "#admin");
      Strophe.addNamespace('MUC_USER', Strophe.NS.MUC + "#user");
      return Strophe.addNamespace('MUC_ROOMCONF', Strophe.NS.MUC + "#roomconfig");
    },

    /*Function
    Join a multi-user chat room
    Parameters:
    (String) room - The multi-user chat room to join.
    (String) nick - The nickname to use in the chat room. Optional
    (Function) msg_handler_cb - The function call to handle messages from the
    specified chat room.
    (Function) pres_handler_cb - The function call back to handle presence
    in the chat room.
    (Function) roster_cb - The function call to handle roster info in the chat room
    (String) password - The optional password to use. (password protected
    rooms only)
    (Object) history_attrs - Optional attributes for retrieving history
    (XML DOM Element) extended_presence - Optional XML for extending presence
     */
    join: function(room, nick, msg_handler_cb, pres_handler_cb, roster_cb, password, history_attrs) {
      var msg, room_nick;
      room_nick = this.test_append_nick(room, nick);
      msg = $pres({
        from: this._connection.jid,
        to: room_nick
      }).c("x", {
        xmlns: Strophe.NS.MUC
      });
      if (history_attrs != null) {
        msg = msg.c("history", history_attrs).up;
      }
      if (password != null) {
        msg.cnode(Strophe.xmlElement("password", [], password));
      }
      if (typeof extended_presence !== "undefined" && extended_presence !== null) {
        msg.up.cnode(extended_presence);
      }
      if (this._muc_handler == null) {
        this._muc_handler = this._connection.addHandler((function(_this) {
          return function(stanza) {
            var from, handler, handlers, id, roomname, x, xmlns, xquery, _i, _len;
            from = stanza.getAttribute('from');
            if (!from) {
              return true;
            }
            roomname = from.split("/")[0];
            if (!_this.rooms[roomname]) {
              return true;
            }
            room = _this.rooms[roomname];
            handlers = {};
            if (stanza.nodeName === "message") {
              handlers = room._message_handlers;
            } else if (stanza.nodeName === "presence") {
              xquery = stanza.getElementsByTagName("x");
              if (xquery.length > 0) {
                for (_i = 0, _len = xquery.length; _i < _len; _i++) {
                  x = xquery[_i];
                  xmlns = x.getAttribute("xmlns");
                  if (xmlns && xmlns.match(Strophe.NS.MUC)) {
                    handlers = room._presence_handlers;
                    break;
                  }
                }
              }
            }
            for (id in handlers) {
              handler = handlers[id];
              if (!handler(stanza, room)) {
                delete handlers[id];
              }
            }
            return true;
          };
        })(this));
      }
      if (!this.rooms.hasOwnProperty(room)) {
        this.rooms[room] = new XmppRoom(this, room, nick, password);
        this.roomNames.push(room);
      }
      if (pres_handler_cb) {
        this.rooms[room].addHandler('presence', pres_handler_cb);
      }
      if (msg_handler_cb) {
        this.rooms[room].addHandler('message', msg_handler_cb);
      }
      if (roster_cb) {
        this.rooms[room].addHandler('roster', roster_cb);
      }
      return this._connection.send(msg);
    },

    /*Function
    Leave a multi-user chat room
    Parameters:
    (String) room - The multi-user chat room to leave.
    (String) nick - The nick name used in the room.
    (Function) handler_cb - Optional function to handle the successful leave.
    (String) exit_msg - optional exit message.
    Returns:
    iqid - The unique id for the room leave.
     */
    leave: function(room, nick, handler_cb, exit_msg) {
      var id, presence, presenceid, room_nick;
      id = this.roomNames.indexOf(room);
      delete this.rooms[room];
      if (id >= 0) {
        this.roomNames.splice(id, 1);
        if (this.roomNames.length === 0) {
          this._connection.deleteHandler(this._muc_handler);
          this._muc_handler = null;
        }
      }
      room_nick = this.test_append_nick(room, nick);
      presenceid = this._connection.getUniqueId();
      presence = $pres({
        type: "unavailable",
        id: presenceid,
        from: this._connection.jid,
        to: room_nick
      });
      if (exit_msg != null) {
        presence.c("status", exit_msg);
      }
      if (handler_cb != null) {
        this._connection.addHandler(handler_cb, null, "presence", null, presenceid);
      }
      this._connection.send(presence);
      return presenceid;
    },

    /*Function
    Parameters:
    (String) room - The multi-user chat room name.
    (String) nick - The nick name used in the chat room.
    (String) message - The plaintext message to send to the room.
    (String) html_message - The message to send to the room with html markup.
    (String) type - "groupchat" for group chat messages o
                    "chat" for private chat messages
    Returns:
    msgiq - the unique id used to send the message
     */
    message: function(room, nick, message, html_message, type) {
      var msg, msgid, parent, room_nick;
      room_nick = this.test_append_nick(room, nick);
      type = type || (nick != null ? "chat" : "groupchat");
      msgid = this._connection.getUniqueId();
      msg = $msg({
        to: room_nick,
        from: this._connection.jid,
        type: type,
        id: msgid
      }).c("body", {
        xmlns: Strophe.NS.CLIENT
      }).t(message);
      msg.up();
      if (html_message != null) {
        msg.c("html", {
          xmlns: Strophe.NS.XHTML_IM
        }).c("body", {
          xmlns: Strophe.NS.XHTML
        }).h(html_message);
        if (msg.node.childNodes.length === 0) {
          parent = msg.node.parentNode;
          msg.up().up();
          msg.node.removeChild(parent);
        } else {
          msg.up().up();
        }
      }
      msg.c("x", {
        xmlns: "jabber:x:event"
      }).c("composing");
      this._connection.send(msg);
      return msgid;
    },

    /*Function
    Convenience Function to send a Message to all Occupants
    Parameters:
    (String) room - The multi-user chat room name.
    (String) message - The plaintext message to send to the room.
    (String) html_message - The message to send to the room with html markup.
    Returns:
    msgiq - the unique id used to send the message
     */
    groupchat: function(room, message, html_message) {
      return this.message(room, null, message, html_message);
    },

    /*Function
    Send a mediated invitation.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) receiver - The invitation's receiver.
    (String) reason - Optional reason for joining the room.
    Returns:
    msgiq - the unique id used to send the invitation
     */
    invite: function(room, receiver, reason) {
      var invitation, msgid;
      msgid = this._connection.getUniqueId();
      invitation = $msg({
        from: this._connection.jid,
        to: room,
        id: msgid
      }).c('x', {
        xmlns: Strophe.NS.MUC_USER
      }).c('invite', {
        to: receiver
      });
      if (reason != null) {
        invitation.c('reason', reason);
      }
      this._connection.send(invitation);
      return msgid;
    },

    /*Function
    Send a direct invitation.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) receiver - The invitation's receiver.
    (String) reason - Optional reason for joining the room.
    (String) password - Optional password for the room.
    Returns:
    msgiq - the unique id used to send the invitation
     */
    directInvite: function(room, receiver, reason, password) {
      var attrs, invitation, msgid;
      msgid = this._connection.getUniqueId();
      attrs = {
        xmlns: 'jabber:x:conference',
        jid: room
      };
      if (reason != null) {
        attrs.reason = reason;
      }
      if (password != null) {
        attrs.password = password;
      }
      invitation = $msg({
        from: this._connection.jid,
        to: receiver,
        id: msgid
      }).c('x', attrs);
      this._connection.send(invitation);
      return msgid;
    },

    /*Function
    Queries a room for a list of occupants
    (String) room - The multi-user chat room name.
    (Function) success_cb - Optional function to handle the info.
    (Function) error_cb - Optional function to handle an error.
    Returns:
    id - the unique id used to send the info request
     */
    queryOccupants: function(room, success_cb, error_cb) {
      var attrs, info;
      attrs = {
        xmlns: Strophe.NS.DISCO_ITEMS
      };
      info = $iq({
        from: this._connection.jid,
        to: room,
        type: 'get'
      }).c('query', attrs);
      return this._connection.sendIQ(info, success_cb, error_cb);
    },

    /*Function
    Start a room configuration.
    Parameters:
    (String) room - The multi-user chat room name.
    (Function) handler_cb - Optional function to handle the config form.
    Returns:
    id - the unique id used to send the configuration request
     */
    configure: function(room, handler_cb, error_cb) {
      var config, stanza;
      config = $iq({
        to: room,
        type: "get"
      }).c("query", {
        xmlns: Strophe.NS.MUC_OWNER
      });
      stanza = config.tree();
      return this._connection.sendIQ(stanza, handler_cb, error_cb);
    },

    /*Function
    Cancel the room configuration
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to cancel the configuration.
     */
    cancelConfigure: function(room) {
      var config, stanza;
      config = $iq({
        to: room,
        type: "set"
      }).c("query", {
        xmlns: Strophe.NS.MUC_OWNER
      }).c("x", {
        xmlns: "jabber:x:data",
        type: "cancel"
      });
      stanza = config.tree();
      return this._connection.sendIQ(stanza);
    },

    /*Function
    Save a room configuration.
    Parameters:
    (String) room - The multi-user chat room name.
    (Array) config- Form Object or an array of form elements used to configure the room.
    Returns:
    id - the unique id used to save the configuration.
     */
    saveConfiguration: function(room, config, success_cb, error_cb) {
      var conf, iq, stanza, _i, _len;
      iq = $iq({
        to: room,
        type: "set"
      }).c("query", {
        xmlns: Strophe.NS.MUC_OWNER
      });
      if (typeof Form !== "undefined" && config instanceof Form) {
        config.type = "submit";
        iq.cnode(config.toXML());
      } else {
        iq.c("x", {
          xmlns: "jabber:x:data",
          type: "submit"
        });
        for (_i = 0, _len = config.length; _i < _len; _i++) {
          conf = config[_i];
          iq.cnode(conf).up();
        }
      }
      stanza = iq.tree();
      return this._connection.sendIQ(stanza, success_cb, error_cb);
    },

    /*Function
    Parameters:
    (String) room - The multi-user chat room name.
    Returns:
    id - the unique id used to create the chat room.
     */
    createInstantRoom: function(room, success_cb, error_cb) {
      var roomiq;
      roomiq = $iq({
        to: room,
        type: "set"
      }).c("query", {
        xmlns: Strophe.NS.MUC_OWNER
      }).c("x", {
        xmlns: "jabber:x:data",
        type: "submit"
      });
      return this._connection.sendIQ(roomiq.tree(), success_cb, error_cb);
    },

    /*Function
    Set the topic of the chat room.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) topic - Topic message.
     */
    setTopic: function(room, topic) {
      var msg;
      msg = $msg({
        to: room,
        from: this._connection.jid,
        type: "groupchat"
      }).c("subject", {
        xmlns: "jabber:client"
      }).t(topic);
      return this._connection.send(msg.tree());
    },

    /*Function
    Internal Function that Changes the role or affiliation of a member
    of a MUC room. This function is used by modifyRole and modifyAffiliation.
    The modification can only be done by a room moderator. An error will be
    returned if the user doesn't have permission.
    Parameters:
    (String) room - The multi-user chat room name.
    (Object) item - Object with nick and role or jid and affiliation attribute
    (String) reason - Optional reason for the change.
    (Function) handler_cb - Optional callback for success
    (Function) error_cb - Optional callback for error
    Returns:
    iq - the id of the mode change request.
     */
    _modifyPrivilege: function(room, item, reason, handler_cb, error_cb) {
      var iq;
      iq = $iq({
        to: room,
        type: "set"
      }).c("query", {
        xmlns: Strophe.NS.MUC_ADMIN
      }).cnode(item.node);
      if (reason != null) {
        iq.c("reason", reason);
      }
      return this._connection.sendIQ(iq.tree(), handler_cb, error_cb);
    },

    /*Function
    Changes the role of a member of a MUC room.
    The modification can only be done by a room moderator. An error will be
    returned if the user doesn't have permission.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) nick - The nick name of the user to modify.
    (String) role - The new role of the user.
    (String) affiliation - The new affiliation of the user.
    (String) reason - Optional reason for the change.
    (Function) handler_cb - Optional callback for success
    (Function) error_cb - Optional callback for error
    Returns:
    iq - the id of the mode change request.
     */
    modifyRole: function(room, nick, role, reason, handler_cb, error_cb) {
      var item;
      item = $build("item", {
        nick: nick,
        role: role
      });
      return this._modifyPrivilege(room, item, reason, handler_cb, error_cb);
    },
    kick: function(room, nick, reason, handler_cb, error_cb) {
      return this.modifyRole(room, nick, 'none', reason, handler_cb, error_cb);
    },
    voice: function(room, nick, reason, handler_cb, error_cb) {
      return this.modifyRole(room, nick, 'participant', reason, handler_cb, error_cb);
    },
    mute: function(room, nick, reason, handler_cb, error_cb) {
      return this.modifyRole(room, nick, 'visitor', reason, handler_cb, error_cb);
    },
    op: function(room, nick, reason, handler_cb, error_cb) {
      return this.modifyRole(room, nick, 'moderator', reason, handler_cb, error_cb);
    },
    deop: function(room, nick, reason, handler_cb, error_cb) {
      return this.modifyRole(room, nick, 'participant', reason, handler_cb, error_cb);
    },

    /*Function
    Changes the affiliation of a member of a MUC room.
    The modification can only be done by a room moderator. An error will be
    returned if the user doesn't have permission.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) jid  - The jid of the user to modify.
    (String) affiliation - The new affiliation of the user.
    (String) reason - Optional reason for the change.
    (Function) handler_cb - Optional callback for success
    (Function) error_cb - Optional callback for error
    Returns:
    iq - the id of the mode change request.
     */
    modifyAffiliation: function(room, jid, affiliation, reason, handler_cb, error_cb) {
      var item;
      item = $build("item", {
        jid: jid,
        affiliation: affiliation
      });
      return this._modifyPrivilege(room, item, reason, handler_cb, error_cb);
    },
    ban: function(room, jid, reason, handler_cb, error_cb) {
      return this.modifyAffiliation(room, jid, 'outcast', reason, handler_cb, error_cb);
    },
    member: function(room, jid, reason, handler_cb, error_cb) {
      return this.modifyAffiliation(room, jid, 'member', reason, handler_cb, error_cb);
    },
    revoke: function(room, jid, reason, handler_cb, error_cb) {
      return this.modifyAffiliation(room, jid, 'none', reason, handler_cb, error_cb);
    },
    owner: function(room, jid, reason, handler_cb, error_cb) {
      return this.modifyAffiliation(room, jid, 'owner', reason, handler_cb, error_cb);
    },
    admin: function(room, jid, reason, handler_cb, error_cb) {
      return this.modifyAffiliation(room, jid, 'admin', reason, handler_cb, error_cb);
    },

    /*Function
    Change the current users nick name.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) user - The new nick name.
     */
    changeNick: function(room, user) {
      var presence, room_nick;
      room_nick = this.test_append_nick(room, user);
      presence = $pres({
        from: this._connection.jid,
        to: room_nick,
        id: this._connection.getUniqueId()
      });
      return this._connection.send(presence.tree());
    },

    /*Function
    Change the current users status.
    Parameters:
    (String) room - The multi-user chat room name.
    (String) user - The current nick.
    (String) show - The new show-text.
    (String) status - The new status-text.
     */
    setStatus: function(room, user, show, status) {
      var presence, room_nick;
      room_nick = this.test_append_nick(room, user);
      presence = $pres({
        from: this._connection.jid,
        to: room_nick
      });
      if (show != null) {
        presence.c('show', show).up();
      }
      if (status != null) {
        presence.c('status', status);
      }
      return this._connection.send(presence.tree());
    },

    /*Function
    List all chat room available on a server.
    Parameters:
    (String) server - name of chat server.
    (String) handle_cb - Function to call for room list return.
    (String) error_cb - Function to call on error.
     */
    listRooms: function(server, handle_cb, error_cb) {
      var iq;
      iq = $iq({
        to: server,
        from: this._connection.jid,
        type: "get"
      }).c("query", {
        xmlns: Strophe.NS.DISCO_ITEMS
      });
      return this._connection.sendIQ(iq, handle_cb, error_cb);
    },
    test_append_nick: function(room, nick) {
      var domain, node;
      node = Strophe.escapeNode(Strophe.getNodeFromJid(room));
      domain = Strophe.getDomainFromJid(room);
      return node + "@" + domain + (nick != null ? "/" + nick : "");
    }
  });

  XmppRoom = (function() {
    function XmppRoom(client, name, nick, password) {
      this.client = client;
      this.name = name;
      this.nick = nick;
      this.password = password;
      this._roomRosterHandler = __bind(this._roomRosterHandler, this);
      this._addOccupant = __bind(this._addOccupant, this);
      this.roster = {};
      this._message_handlers = {};
      this._presence_handlers = {};
      this._roster_handlers = {};
      this._handler_ids = 0;
      if (client.muc) {
        this.client = client.muc;
      }
      this.name = Strophe.getBareJidFromJid(name);
      this.addHandler('presence', this._roomRosterHandler);
    }

    XmppRoom.prototype.join = function(msg_handler_cb, pres_handler_cb, roster_cb) {
      return this.client.join(this.name, this.nick, msg_handler_cb, pres_handler_cb, roster_cb, this.password);
    };

    XmppRoom.prototype.leave = function(handler_cb, message) {
      this.client.leave(this.name, this.nick, handler_cb, message);
      return delete this.client.rooms[this.name];
    };

    XmppRoom.prototype.message = function(nick, message, html_message, type) {
      return this.client.message(this.name, nick, message, html_message, type);
    };

    XmppRoom.prototype.groupchat = function(message, html_message) {
      return this.client.groupchat(this.name, message, html_message);
    };

    XmppRoom.prototype.invite = function(receiver, reason) {
      return this.client.invite(this.name, receiver, reason);
    };

    XmppRoom.prototype.directInvite = function(receiver, reason) {
      return this.client.directInvite(this.name, receiver, reason, this.password);
    };

    XmppRoom.prototype.configure = function(handler_cb) {
      return this.client.configure(this.name, handler_cb);
    };

    XmppRoom.prototype.cancelConfigure = function() {
      return this.client.cancelConfigure(this.name);
    };

    XmppRoom.prototype.saveConfiguration = function(config) {
      return this.client.saveConfiguration(this.name, config);
    };

    XmppRoom.prototype.queryOccupants = function(success_cb, error_cb) {
      return this.client.queryOccupants(this.name, success_cb, error_cb);
    };

    XmppRoom.prototype.setTopic = function(topic) {
      return this.client.setTopic(this.name, topic);
    };

    XmppRoom.prototype.modifyRole = function(nick, role, reason, success_cb, error_cb) {
      return this.client.modifyRole(this.name, nick, role, reason, success_cb, error_cb);
    };

    XmppRoom.prototype.kick = function(nick, reason, handler_cb, error_cb) {
      return this.client.kick(this.name, nick, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.voice = function(nick, reason, handler_cb, error_cb) {
      return this.client.voice(this.name, nick, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.mute = function(nick, reason, handler_cb, error_cb) {
      return this.client.mute(this.name, nick, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.op = function(nick, reason, handler_cb, error_cb) {
      return this.client.op(this.name, nick, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.deop = function(nick, reason, handler_cb, error_cb) {
      return this.client.deop(this.name, nick, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.modifyAffiliation = function(jid, affiliation, reason, success_cb, error_cb) {
      return this.client.modifyAffiliation(this.name, jid, affiliation, reason, success_cb, error_cb);
    };

    XmppRoom.prototype.ban = function(jid, reason, handler_cb, error_cb) {
      return this.client.ban(this.name, jid, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.member = function(jid, reason, handler_cb, error_cb) {
      return this.client.member(this.name, jid, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.revoke = function(jid, reason, handler_cb, error_cb) {
      return this.client.revoke(this.name, jid, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.owner = function(jid, reason, handler_cb, error_cb) {
      return this.client.owner(this.name, jid, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.admin = function(jid, reason, handler_cb, error_cb) {
      return this.client.admin(this.name, jid, reason, handler_cb, error_cb);
    };

    XmppRoom.prototype.changeNick = function(nick) {
      this.nick = nick;
      return this.client.changeNick(this.name, nick);
    };

    XmppRoom.prototype.setStatus = function(show, status) {
      return this.client.setStatus(this.name, this.nick, show, status);
    };


    /*Function
    Adds a handler to the MUC room.
      Parameters:
    (String) handler_type - 'message', 'presence' or 'roster'.
    (Function) handler - The handler function.
    Returns:
    id - the id of handler.
     */

    XmppRoom.prototype.addHandler = function(handler_type, handler) {
      var id;
      id = this._handler_ids++;
      switch (handler_type) {
        case 'presence':
          this._presence_handlers[id] = handler;
          break;
        case 'message':
          this._message_handlers[id] = handler;
          break;
        case 'roster':
          this._roster_handlers[id] = handler;
          break;
        default:
          this._handler_ids--;
          return null;
      }
      return id;
    };


    /*Function
    Removes a handler from the MUC room.
    This function takes ONLY ids returned by the addHandler function
    of this room. passing handler ids returned by connection.addHandler
    may brake things!
      Parameters:
    (number) id - the id of the handler
     */

    XmppRoom.prototype.removeHandler = function(id) {
      delete this._presence_handlers[id];
      delete this._message_handlers[id];
      return delete this._roster_handlers[id];
    };


    /*Function
    Creates and adds an Occupant to the Room Roster.
      Parameters:
    (Object) data - the data the Occupant is filled with
    Returns:
    occ - the created Occupant.
     */

    XmppRoom.prototype._addOccupant = function(data) {
      var occ;
      occ = new Occupant(data, this);
      this.roster[occ.nick] = occ;
      return occ;
    };


    /*Function
    The standard handler that managed the Room Roster.
      Parameters:
    (Object) pres - the presence stanza containing user information
     */

    XmppRoom.prototype._roomRosterHandler = function(pres) {
      var data, handler, id, newnick, nick, _ref;
      data = XmppRoom._parsePresence(pres);
      nick = data.nick;
      newnick = data.newnick || null;
      switch (data.type) {
        case 'error':
          return;
        case 'unavailable':
          if (newnick) {
            data.nick = newnick;
            if (this.roster[nick] && this.roster[newnick]) {
              this.roster[nick].update(this.roster[newnick]);
              this.roster[newnick] = this.roster[nick];
            }
            if (this.roster[nick] && !this.roster[newnick]) {
              this.roster[newnick] = this.roster[nick].update(data);
            }
          }
          delete this.roster[nick];
          break;
        default:
          if (this.roster[nick]) {
            this.roster[nick].update(data);
          } else {
            this._addOccupant(data);
          }
      }
      _ref = this._roster_handlers;
      for (id in _ref) {
        handler = _ref[id];
        if (!handler(this.roster, this)) {
          delete this._roster_handlers[id];
        }
      }
      return true;
    };


    /*Function
    Parses a presence stanza
      Parameters:
    (Object) data - the data extracted from the presence stanza
     */

    XmppRoom._parsePresence = function(pres) {
      var a, c, c2, data, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7;
      data = {};
      a = pres.attributes;
      data.nick = Strophe.getResourceFromJid(a.from.textContent);
      data.type = ((_ref = a.type) != null ? _ref.textContent : void 0) || null;
      data.states = [];
      _ref1 = pres.childNodes;
      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        c = _ref1[_i];
        switch (c.nodeName) {
          case "status":
            data.status = c.textContent || null;
            break;
          case "show":
            data.show = c.textContent || null;
            break;
          case "x":
            a = c.attributes;
            if (((_ref2 = a.xmlns) != null ? _ref2.textContent : void 0) === Strophe.NS.MUC_USER) {
              _ref3 = c.childNodes;
              for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
                c2 = _ref3[_j];
                switch (c2.nodeName) {
                  case "item":
                    a = c2.attributes;
                    data.affiliation = ((_ref4 = a.affiliation) != null ? _ref4.textContent : void 0) || null;
                    data.role = ((_ref5 = a.role) != null ? _ref5.textContent : void 0) || null;
                    data.jid = ((_ref6 = a.jid) != null ? _ref6.textContent : void 0) || null;
                    data.newnick = ((_ref7 = a.nick) != null ? _ref7.textContent : void 0) || null;
                    break;
                  case "status":
                    if (c2.attributes.code) {
                      data.states.push(c2.attributes.code.textContent);
                    }
                }
              }
            }
        }
      }
      return data;
    };

    return XmppRoom;

  })();

  RoomConfig = (function() {
    function RoomConfig(info) {
      this.parse = __bind(this.parse, this);
      if (info != null) {
        this.parse(info);
      }
    }

    RoomConfig.prototype.parse = function(result) {
      var attr, attrs, child, field, identity, query, _i, _j, _k, _len, _len1, _len2, _ref;
      query = result.getElementsByTagName("query")[0].childNodes;
      this.identities = [];
      this.features = [];
      this.x = [];
      for (_i = 0, _len = query.length; _i < _len; _i++) {
        child = query[_i];
        attrs = child.attributes;
        switch (child.nodeName) {
          case "identity":
            identity = {};
            for (_j = 0, _len1 = attrs.length; _j < _len1; _j++) {
              attr = attrs[_j];
              identity[attr.name] = attr.textContent;
            }
            this.identities.push(identity);
            break;
          case "feature":
            this.features.push(attrs["var"].textContent);
            break;
          case "x":
            attrs = child.childNodes[0].attributes;
            if ((!attrs["var"].textContent === 'FORM_TYPE') || (!attrs.type.textContent === 'hidden')) {
              break;
            }
            _ref = child.childNodes;
            for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) {
              field = _ref[_k];
              if (!(!field.attributes.type)) {
                continue;
              }
              attrs = field.attributes;
              this.x.push({
                "var": attrs["var"].textContent,
                label: attrs.label.textContent || "",
                value: field.firstChild.textContent || ""
              });
            }
        }
      }
      return {
        "identities": this.identities,
        "features": this.features,
        "x": this.x
      };
    };

    return RoomConfig;

  })();

  Occupant = (function() {
    function Occupant(data, room) {
      this.room = room;
      this.update = __bind(this.update, this);
      this.admin = __bind(this.admin, this);
      this.owner = __bind(this.owner, this);
      this.revoke = __bind(this.revoke, this);
      this.member = __bind(this.member, this);
      this.ban = __bind(this.ban, this);
      this.modifyAffiliation = __bind(this.modifyAffiliation, this);
      this.deop = __bind(this.deop, this);
      this.op = __bind(this.op, this);
      this.mute = __bind(this.mute, this);
      this.voice = __bind(this.voice, this);
      this.kick = __bind(this.kick, this);
      this.modifyRole = __bind(this.modifyRole, this);
      this.update(data);
    }

    Occupant.prototype.modifyRole = function(role, reason, success_cb, error_cb) {
      return this.room.modifyRole(this.nick, role, reason, success_cb, error_cb);
    };

    Occupant.prototype.kick = function(reason, handler_cb, error_cb) {
      return this.room.kick(this.nick, reason, handler_cb, error_cb);
    };

    Occupant.prototype.voice = function(reason, handler_cb, error_cb) {
      return this.room.voice(this.nick, reason, handler_cb, error_cb);
    };

    Occupant.prototype.mute = function(reason, handler_cb, error_cb) {
      return this.room.mute(this.nick, reason, handler_cb, error_cb);
    };

    Occupant.prototype.op = function(reason, handler_cb, error_cb) {
      return this.room.op(this.nick, reason, handler_cb, error_cb);
    };

    Occupant.prototype.deop = function(reason, handler_cb, error_cb) {
      return this.room.deop(this.nick, reason, handler_cb, error_cb);
    };

    Occupant.prototype.modifyAffiliation = function(affiliation, reason, success_cb, error_cb) {
      return this.room.modifyAffiliation(this.jid, affiliation, reason, success_cb, error_cb);
    };

    Occupant.prototype.ban = function(reason, handler_cb, error_cb) {
      return this.room.ban(this.jid, reason, handler_cb, error_cb);
    };

    Occupant.prototype.member = function(reason, handler_cb, error_cb) {
      return this.room.member(this.jid, reason, handler_cb, error_cb);
    };

    Occupant.prototype.revoke = function(reason, handler_cb, error_cb) {
      return this.room.revoke(this.jid, reason, handler_cb, error_cb);
    };

    Occupant.prototype.owner = function(reason, handler_cb, error_cb) {
      return this.room.owner(this.jid, reason, handler_cb, error_cb);
    };

    Occupant.prototype.admin = function(reason, handler_cb, error_cb) {
      return this.room.admin(this.jid, reason, handler_cb, error_cb);
    };

    Occupant.prototype.update = function(data) {
      this.nick = data.nick || null;
      this.affiliation = data.affiliation || null;
      this.role = data.role || null;
      this.jid = data.jid || null;
      this.status = data.status || null;
      this.show = data.show || null;
      return this;
    };

    return Occupant;

  })();

}).call(this);
