// Generated by IcedCoffeeScript 1.7.1-b
(function() {
  var C, PpBuffer, U32MAX, Unpacker, default_ext, modes, pow2, twos_compl_inv, _ref;

  C = require('./const').C;

  PpBuffer = require('./buffer').PpBuffer;

  _ref = require('./util'), pow2 = _ref.pow2, twos_compl_inv = _ref.twos_compl_inv, U32MAX = _ref.U32MAX;

  modes = {
    NONE: 0,
    BINARY: 1,
    START: 2
  };

  default_ext = function(type, raw) {
    return {
      type: type,
      raw: raw
    };
  };

  exports.Unpacker = Unpacker = (function() {
    function Unpacker(b, _opts) {
      this._opts = _opts != null ? _opts : {};
      this._buffer = new PpBuffer(b);
      this._ext = this._opts.ext || (this._opts.no_ext ? null : default_ext);
    }

    Unpacker.prototype.u_buf = function(n) {
      return this._buffer.read_buffer(n);
    };

    Unpacker.prototype.u_str = function(n) {
      return this.u_buf(n).toString('utf8');
    };

    Unpacker.prototype.u_bin = function(n) {
      return this.u_buf(n);
    };

    Unpacker.prototype.u_ext = function(n) {
      var buf, typ;
      typ = this.u_uint8();
      buf = this.u_buf(n);
      if (this._opts.ext != null) {
        return this._opts.ext(typ, buf);
      } else {
        throw new Error("No ext hook but got message type: " + typ);
      }
    };

    Unpacker.prototype.u_array = function(n) {
      var i, _i, _results;
      _results = [];
      for (i = _i = 0; 0 <= n ? _i < n : _i > n; i = 0 <= n ? ++_i : --_i) {
        _results.push(this.u());
      }
      return _results;
    };

    Unpacker.prototype.u_map = function(n) {
      var i, ret, _i;
      ret = {};
      for (i = _i = 0; 0 <= n ? _i < n : _i > n; i = 0 <= n ? ++_i : --_i) {
        ret[this.u()] = this.u();
      }
      return ret;
    };

    Unpacker.prototype.u_uint8 = function() {
      return this._buffer.read_uint8();
    };

    Unpacker.prototype.u_uint16 = function() {
      return this._buffer.read_uint16();
    };

    Unpacker.prototype.u_uint32 = function() {
      return this._buffer.read_uint32();
    };

    Unpacker.prototype.u_int8 = function() {
      return this._buffer.read_int8();
    };

    Unpacker.prototype.u_int16 = function() {
      return this._buffer.read_int16();
    };

    Unpacker.prototype.u_int32 = function() {
      return this._buffer.read_int32();
    };

    Unpacker.prototype.u_uint64 = function() {
      return (this.u_uint32() * U32MAX) + this.u_uint32();
    };

    Unpacker.prototype.u_double = function() {
      return this._buffer.read_float64();
    };

    Unpacker.prototype.u_float = function() {
      return this._buffer.read_float32();
    };

    Unpacker.prototype.u_int64 = function() {
      var a, b, i, _ref1;
      _ref1 = (function() {
        var _i, _results;
        _results = [];
        for (i = _i = 0; _i < 2; i = ++_i) {
          _results.push(this.u_uint32());
        }
        return _results;
      }).call(this), a = _ref1[0], b = _ref1[1];
      return U32MAX * (a - U32MAX) + b;
    };

    Unpacker.prototype.u = function() {
      var b, l;
      if ((b = this.u_uint8()) <= C.positive_fix_max) {
        return b;
      } else if (b >= C.negative_fix_min && b <= C.negative_fix_max) {
        return twos_compl_inv(b, 8);
      } else if (b >= C.fix_str_min && b <= C.fix_str_max) {
        l = b & C.fix_str_count_mask;
        return this.u_str(l);
      } else if (b >= C.fix_array_min && b <= C.fix_array_max) {
        l = b & C.fix_array_count_mask;
        return this.u_array(l);
      } else if (b >= C.fix_map_min && b <= C.fix_map_max) {
        l = b & C.fix_map_count_mask;
        return this.u_map(l);
      } else {
        switch (b) {
          case C["null"]:
            return null;
          case C["true"]:
            return true;
          case C["false"]:
            return false;
          case C.uint8:
            return this.u_uint8();
          case C.uint16:
            return this.u_uint16();
          case C.uint32:
            return this.u_uint32();
          case C.uint64:
            return this.u_uint64();
          case C.int8:
            return this.u_int8();
          case C.int16:
            return this.u_int16();
          case C.int32:
            return this.u_int32();
          case C.int64:
            return this.u_int64();
          case C.double:
            return this.u_double();
          case C.float:
            return this.u_float();
          case C.str8:
            return this.u_str(this.u_uint8());
          case C.str16:
            return this.u_str(this.u_uint16());
          case C.str32:
            return this.u_str(this.u_uint32());
          case C.bin8:
            return this.u_bin(this.u_uint8());
          case C.bin16:
            return this.u_bin(this.u_uint16());
          case C.bin32:
            return this.u_bin(this.u_uint32());
          case C.array16:
            return this.u_array(this.u_uint16());
          case C.array32:
            return this.u_array(this.u_uint32());
          case C.map16:
            return this.u_map(this.u_uint16());
          case C.map32:
            return this.u_map(this.u_uint32());
          case C.fix_ext1:
            return this.u_ext(1);
          case C.fix_ext2:
            return this.u_ext(2);
          case C.fix_ext4:
            return this.u_ext(4);
          case C.fix_ext8:
            return this.u_ext(8);
          case C.fix_ext16:
            return this.u_ext(16);
          case C.ext8:
            return this.u_ext(this.u_uint8());
          case C.ext16:
            return this.u_ext(this.u_uint16());
          case C.ext32:
            return this.u_ext(this.u_uint32());
          default:
            throw new Error("unhandled type " + b);
        }
      }
    };

    return Unpacker;

  })();

  exports.unpack = function(x, opts) {
    var unpacker;
    if (opts == null) {
      opts = {};
    }
    unpacker = new Unpacker(x, opts);
    return unpacker.u();
  };

}).call(this);
