// Generated by IcedCoffeeScript 1.7.1-c
(function() {
  var Packetizer, Ring, is_array, msgpack_frame_len, pack, unpack, _ref;

  _ref = require('./pack'), unpack = _ref.unpack, pack = _ref.pack;

  Ring = require('./ring').Ring;

  msgpack_frame_len = function(buf) {
    var b;
    b = buf[0];
    if (b < 0x80) {
      return 1;
    } else if (b === 0xcc) {
      return 2;
    } else if (b === 0xcd) {
      return 3;
    } else if (b === 0xce) {
      return 5;
    } else {
      return 0;
    }
  };

  is_array = function(a) {
    return (typeof a === 'object') && Array.isArray(a);
  };

  exports.Packetizer = Packetizer = (function() {
    "A packetizer that is used to read and write to an underlying stream\n(like a Transport below).  Should be inherited by such a class.\nThe subclasses should implement:\n\n   @_raw_write(msg,enc) - write this msg to the stream with the\n     given encoding. Typically handled at the transport level\n     (2 classes higher in the inheritance graph)\n    \n   @_packetize_error(err) - report an error with the stream.  Typically\n     calls up to the Transport class (2 classes higher).\n  \n   @_dispatch(msg) - emit a packetized incoming message. Typically\n     handled by the Dispatcher (1 class higher in the inheritance\n     graph).\n\nThe subclass should call @packetize_data(m) whenever it has data to stuff\ninto the packetizer's input path, and call @send(m) whenever it wants\nto stuff data into the packterizer's output path.\n ";
    Packetizer.prototype.FRAME = 1;

    Packetizer.prototype.DATA = 2;

    Packetizer.prototype.OK = 0;

    Packetizer.prototype.WAIT = 1;

    Packetizer.prototype.ERR = -1;

    function Packetizer() {
      this._ring = new Ring();
      this._state = this.FRAME;
      this._next_msg_len = 0;
    }

    Packetizer.prototype.send = function(msg) {
      var b, b1, b2, bufs, enc, rc, _i, _len;
      b2 = pack(msg);
      b1 = pack(b2.length);
      bufs = [b1, b2];
      rc = 0;
      enc = 'binary';
      for (_i = 0, _len = bufs.length; _i < _len; _i++) {
        b = bufs[_i];
        this._raw_write(b.toString(enc), enc);
      }
      return true;
    };

    Packetizer.prototype._get_frame = function() {
      var f0, f_full, frame_len, r, res, typ, w, _ref1;
      if (!(this._ring.len() > 0)) {
        return this.WAIT;
      }
      f0 = this._ring.grab(1);
      if (!f0) {
        return this.WAIT;
      }
      frame_len = msgpack_frame_len(f0);
      if (!frame_len) {
        this._packetize_error("Bad frame header received");
        return this.ERR;
      }
      if ((f_full = this._ring.grab(frame_len)) == null) {
        return this.WAIT;
      }
      _ref1 = unpack(f_full), w = _ref1[0], r = _ref1[1];
      if (w != null) {
        this._packetize_warning(w);
      }
      res = (function() {
        switch ((typ = typeof r)) {
          case 'number':
            if (r < 0) {
              throw new Error("Negative len " + len + " should not have happened");
            }
            this._ring.consume(frame_len);
            this._next_msg_len = r;
            this._state = this.DATA;
            return this.OK;
          case 'undefined':
            return this.WAIT;
          default:
            this._packetize_error("bad frame; got type=" + typ + ", which is wrong");
            return this.ERR;
        }
      }).call(this);
      return res;
    };

    Packetizer.prototype._get_msg = function() {
      var b, l, msg, pw, ret, _ref1;
      l = this._next_msg_len;
      ret = l > this._ring.len() || ((b = this._ring.grab(l)) == null) ? this.WAIT : ((_ref1 = unpack(b), pw = _ref1[0], msg = _ref1[1], _ref1) == null) || (msg == null) ? (this._packetize_error("bad encoding found in data/payload; len=" + l), this.ERR) : !is_array(msg) ? (this._packetize_error("non-array found in data stream: " + (JSON.stringify(msg))), this.ERR) : (this._ring.consume(l), this._state = this.FRAME, this._dispatch(msg), this.OK);
      if (pw != null) {
        this._packetize_warning(pw);
      }
      return ret;
    };

    Packetizer.prototype.packetize_data = function(m) {
      var go, _results;
      this._ring.buffer(m);
      go = this.OK;
      _results = [];
      while (go === this.OK) {
        _results.push(go = this._state === this.FRAME ? this._get_frame() : this._get_msg());
      }
      return _results;
    };

    Packetizer.prototype._packetizer_reset = function() {
      this._state = this.FRAME;
      return this._ring = new Ring();
    };

    return Packetizer;

  })();

}).call(this);
