var HTTP   = require('http');
var encode = require('../vendor/base64').encode;

this.Campfire = {
  initialize: function(options) {
    this.token         = options.token;
    this.account       = options.account;
    this.domain        = this.account + '.campfirenow.com';
    this.authorization = encode(this.token + ':x');
  },

  Room: function(id) {
    var self   = this;
    var result = {
      join: function(callback) {
        self.post('/room/' + id + '/join', '', callback);
      },
      leave: function(callback) {
        self.post('/room/' + id + '/leave', '', callback);
      },
      listen: function(callback) {
        var client  = HTTP.createClient(80, 'streaming.campfirenow.com');
        var headers = {
          'Host'          : 'streaming.campfirenow.com',
          'Authorization' : self.authorization
        };

        var
        request = client.request('GET', '/room/' + id + '/live.json', headers);
        request.addListener('response', function(response) {
          response.setEncoding('utf8');
          response.addListener('data', function(chunk) {
            if (chunk == ' ') {
              return;
            }

            if (typeof(callback) == 'function') {
              chunk = chunk.split("\r");

              for (var i = 0; i < chunk.length; ++i) {
                if (chunk[i] != '') {
                  var message = JSON.parse(chunk[i]);

                  try {
                    message.user = result.users[message.user_id];
                  } catch(e) {}

                  if (message.type == 'EnterMessage') {
                    exports.Campfire.User(message.user_id, function(data) {
                      result.users[message.user_id] = data.user;
                    });
                  } else if (message.type == 'LeaveMessage') {
                    delete result.users[message.user_id];
                  }

                  callback(message);
                }
              }
            }
          });
        });
        request.end();
      },
      lock: function(callback) {
        self.post('/room/' + id + '/lock', '', callback);
      },
      message: function(text, type, callback) {
        var message = { message : { body : text, type : type } };

        self.post('/room/' + id + '/speak', message, function(data) {
          if (typeof(callback) == 'function') {
            callback(data);
          }
        });
      },
      paste: function(text, callback) {
        this.message(text, 'PasteMessage', callback);
      },
      show: function(callback) {
        self.post('/room/' + id, '', callback);
      },
      sound: function(text, callback) {
        this.message(text, 'SoundMessage', callback);
      },
      speak: function(text, callback) {
        this.message(text, 'TextMessage', callback);
      },
      unlock: function(callback) {
        self.post('/room/' + id + '/unlock', '', callback);
      }
    };

    result.show(function(data) {
      var room = data.room;

      for (var key in room) {
        result[key] = room[key];
      }

      result.users = {};

      for (var i = 0, l = room.users.length; i < l; i++) {
        var user = room.users[i];

        result.users[user.id] = user;
      }
    });

    return result;
  },

  User: function(id, callback) {
    this.get('/users/' + id, callback);
  },

  request: function(method, path, body, callback) {
    var headers = {
      'Authorization' : this.authorization,
      'Host'          : this.domain,
      'Content-Type'  : 'application/json'
    };

    if (method == 'POST') {
      if (typeof(body) != 'string') {
        body = JSON.stringify(body);
      }

      headers['Content-Length'] = body.length;
    }

    var client  = HTTP.createClient(80, this.domain);
    var request = client.request(method, path, headers);

    request.addListener('response', function(response) {
      if (typeof(callback) == 'function') {
        var data = '';

        response.addListener('data', function(chunk) {
          data += chunk;
        });
        response.addListener('end', function() {
          try {
            data = JSON.parse(data);
          } catch(e) {}

          callback(data);
        });
      }
    });

    if (method == 'POST') {
      request.write(body);
    }

    request.end();
  },

  get: function(path, callback) {
    this.request('GET', path, null, callback);
  },

  post: function(path, body, callback) {
    this.request('POST', path, body, callback);
  }
};

@@ -619,32 +619,163 @@
 ion(callback) %7B%0A
+        if (typeof(callback) != 'function') %7B%0A          throw new Error('A callback must be provided for listening.');%0A        %7D;%0A%0A
         var clie
@@ -1295,60 +1295,8 @@
  %7D%0A%0A
-            if (typeof(callback) == 'function') %7B%0A  
     
@@ -1327,26 +1327,24 @@
 lit(%22%5Cr%22);%0A%0A
-  
             
@@ -1380,26 +1380,24 @@
 gth; ++i) %7B%0A
-  
             
@@ -1432,26 +1432,24 @@
             
-  
 var message 
@@ -1485,34 +1485,30 @@
             
-  
 try %7B%0A
-  
             
@@ -1567,34 +1567,32 @@
                 
-  
 %7D catch(e) %7B%7D%0A%0A 
@@ -1582,34 +1582,32 @@
  %7D catch(e) %7B%7D%0A%0A
-  
                 
@@ -1636,34 +1636,32 @@
 nterMessage') %7B%0A
-  
                 
@@ -1734,26 +1734,24 @@
             
-  
 result.users
@@ -1795,32 +1795,28 @@
             
-  
 %7D);%0A
-  
             
@@ -1882,18 +1882,16 @@
         
-  
 delete r
@@ -1928,39 +1928,35 @@
                 
-  
 %7D%0A%0A
-  
                 
@@ -1974,34 +1974,16 @@
 ssage);%0A
-                %7D%0A
         
@@ -2334,122 +2334,16 @@
 ge, 
-function(data) %7B%0A          if (typeof(callback) == 'function') %7B%0A            callback(data);%0A          %7D%0A        %7D
+callback
 );%0A 
@@ -3750,24 +3750,68 @@
  headers);%0A%0A
+    if (typeof(callback) == 'function') %7B%0A  
     request.
@@ -3859,52 +3859,8 @@
 ) %7B%0A
-      if (typeof(callback) == 'function') %7B%0A
     
@@ -4139,32 +4139,32 @@
  %7D);%0A      %7D
+);
 %0A    %7D
-);
 %0A%0A    if (me

Improve callback checks.