
/**
 * Packet types.
 */

var packets = exports.packets = {
    open:     0    // non-ws
  , close:    1    // non-ws
  , ping:     2
  , pong:     3
  , message:  4
  , error:    5
  , noop:     6
};

var packetslist = Object.keys(packets);

/**
 * Premade error packet.
 */

var err = { type: 'error', data: 'parser error' }

/**
 * Encodes a packet.
 *
 *     <packet type id> [ `:` <data> ]
 *
 * Example:
 *
 *     5:hello world
 *     3
 *     4
 *
 * @api private
 */

exports.encodePacket = function (packet) {
  var encoded = packets[packet.type]

  // data fragment is optional
  if ('undefined' != typeof packet.data) {
    encoded += ':' + packet.data;
  }

  return '' + encoded;
};

/**
 * Decodes a packet.
 *
 * @return {Object} with `type` and `data` (if any)
 * @api private
 */

exports.decodePacket = function (data) {
  if (':' === data[1]) {
    var pieces = data.match(/([0-9]+):(.*)?/)

    if (!pieces) {
      // parser error - ignoring packet
      return err;
    }

    var type = pieces[1]
      , data = pieces[2]

    if (!packetslist[type]) {
      // parser error - ignoring packet
      return err;
    }

    return { type: packetslist[type], data: undefined === data ? '' : data };
  } else {
    if (Number(data) != data || !packetslist[data]) return err;
    return { type: packetslist[data] };
  }
};

/**
 * Encodes multiple messages (payload).
 * 
 *     <length>:data
 *
 * Example:
 *
 *     11:hello world2:hi
 *
 * @param {Array} packets
 * @api private
 */

exports.encodePayload = function (packets) {
  if (!packets.length) {
    return '0:';
  }

  var encoded = ''
    , message

  for (var i = 0, l = packets.length; i < l; i++) {
    message = exports.encodePacket(packets[i]);
    encoded += message.length + ':' + message;
  }

  return encoded;
};

/*
 * Decodes data when a payload is maybe expected.
 *
 * @param {String} data
 * @return {Array} packets
 * @api public
 */

exports.decodePayload = function (data) {
  if (data == '') {
    // parser error - ignoring payload
    return [err];
  }

  var packets = []
    , length = ''
    , n, msg, packet

  for (var i = 0, l = data.length; i < l; i++) {
    var chr = data[i]

    if (':' != chr) {
      length += chr;
    } else {
      if ('' == length || (length != (n = Number(length)))) {
        // parser error - ignoring payload
        return [err];
      }

      msg = data.substr(i + 1, n);

      if (length != msg.length) {
        // parser error - ignoring payload
        return [err];
      }

      packet = exports.decodePacket(msg);

      if (err.type == packet.type && err.data == packet.data) {
        // parser error in individual packet - ignoring payload
        return [err];
      }

      packets.push(msg);

      // advance cursor
      i += n;
      length = ''
    }
  }

  if (length != '') {
    // parser error - ignoring payload
    return [err];
  }

  return packets;
};

@@ -2509,32 +2509,58 @@
 %5Berr%5D;%0A      %7D%0A%0A
+      if (msg.length) %7B%0A  
       packet = e
@@ -2588,24 +2588,26 @@
 sg);%0A%0A      
+ 
+ 
 if (err.type
@@ -2652,32 +2652,34 @@
 data) %7B%0A        
+  
 // parser error 
@@ -2718,32 +2718,34 @@
 payload%0A        
+ 
+ 
 return %5Berr%5D;%0A  
@@ -2734,32 +2734,34 @@
   return %5Berr%5D;%0A
+  
       %7D%0A%0A      p
@@ -2755,24 +2755,26 @@
    %7D%0A%0A      
+  
 packets.push
@@ -2774,21 +2774,32 @@
 ts.push(
-msg);
+packet);%0A      %7D
 %0A%0A      

Allow for no packet payloads and fixed packet decoding within payloads.