// Generated by IcedCoffeeScript 1.7.1-g
(function() {
  var C, ChainTail, Leaf, Parser;

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

  exports.ChainTail = ChainTail = (function() {
    function ChainTail(_arg) {
      this.seqno = _arg.seqno, this.payload_hash = _arg.payload_hash, this.sig_id = _arg.sig_id;
    }

    ChainTail.prototype.to_json = function() {
      return [this.seqno, this.payload_hash, this.sig_id];
    };

    return ChainTail;

  })();

  Parser = (function() {
    function Parser(val) {
      this.val = val;
    }

    Parser.prototype.parse = function() {
      var version;
      if (!Array.isArray(this.val) || this.val.length < 1) {
        throw new Error("Expected an array of length 1 or more");
      } else if (typeof this.val[0] !== 'number') {
        throw new Error("Need a number for first slot");
      } else if (typeof this.val[1] === 'string') {
        version = 1;
      } else {
        version = this.val[0];
      }
      switch (version) {
        case C.versions.leaf.v1:
          return this.parse_v1();
        case C.versions.leaf.v2:
          return this.parse_v2();
        default:
          throw new Error("unknown leaf version: " + version);
      }
    };

    Parser.prototype.parse_v1 = function() {
      var pub;
      pub = this.parse_chain_tail(this.val);
      return new Leaf({
        pub: pub
      });
    };

    Parser.prototype.parse_v2 = function() {
      var eldest_kid, pub, semipriv, _ref, _ref1;
      if (this.val.length < 2) {
        throw new Error("No public chain");
      }
      pub = this.val.length > 1 && ((_ref = this.val[1]) != null ? _ref.length : void 0) ? this.parse_chain_tail(this.val[1]) : null;
      semipriv = (this.val.length > 2) && ((_ref1 = this.val[2]) != null ? _ref1.length : void 0) ? this.parse_chain_tail(this.val[2]) : null;
      eldest_kid = this.val.length > 3 && (this.val[3] != null) ? this.parse_kid(this.val[3]) : null;
      return new Leaf({
        pub: pub,
        semipriv: semipriv,
        eldest_kid: eldest_kid
      });
    };

    Parser.prototype.match_hex = function(s) {
      return (typeof s === 'string') && !!(s.match(/^([a-fA-F0-9]*)$/)) && (s.length % 2 === 0);
    };

    Parser.prototype.parse_kid = function(x) {
      if (!this.match_hex(x)) {
        throw new Error("bad kid: " + x);
      }
      return x;
    };

    Parser.prototype.parse_chain_tail = function(val) {
      var i, msg, v, _i, _len, _ref;
      msg = null;
      if (val.length < 2) {
        msg = "Bad chain tail with < 2 values";
      } else if (typeof val[0] !== 'number') {
        msg = "Bad sequence #";
      } else {
        _ref = val.slice(1, 3);
        for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
          v = _ref[i];
          if ((v != null) && v.length) {
            if (!this.match_hex(v)) {
              msg = "bad value[" + i + "]";
              break;
            }
          }
        }
      }
      if (msg != null) {
        throw new Error(msg);
      }
      return new ChainTail({
        seqno: val[0],
        payload_hash: val[1],
        sig_id: val[2]
      });
    };

    return Parser;

  })();

  exports.Leaf = Leaf = (function() {
    function Leaf(_arg) {
      this.pub = _arg.pub, this.semipriv = _arg.semipriv, this.eldest_kid = _arg.eldest_kid;
    }

    Leaf.prototype.get_public = function() {
      return this.pub;
    };

    Leaf.prototype.get_semiprivate = function() {
      return this.semipriv;
    };

    Leaf.prototype.get_eldest_kid = function() {
      return this.eldest_kid;
    };

    Leaf.prototype.to_json = function() {
      var ret;
      ret = [C.versions.leaf.v2, (this.pub ? this.pub.to_json() : []), (this.semipriv != null ? this.semipriv.to_json() : []), this.eldest_kid];
      return ret;
    };

    Leaf.prototype.to_string = function() {
      return JSON.stringify(this.to_json());
    };

    Leaf.parse = function(val) {
      var e, err, leaf, parser;
      parser = new Parser(val);
      err = leaf = null;
      try {
        leaf = parser.parse();
      } catch (_error) {
        e = _error;
        err = e;
      }
      return [err, leaf];
    };

    Leaf.prototype.seqno_assertion = function() {
      return (function(_this) {
        return function(rows) {
          var chain_tail, found, seqno, seqno_type, _i, _len, _ref, _ref1, _ref2;
          found = {};
          for (_i = 0, _len = rows.length; _i < _len; _i++) {
            _ref = rows[_i], seqno_type = _ref.seqno_type, seqno = _ref.seqno;
            chain_tail = (function() {
              switch (seqno_type) {
                case C.seqno_types.PUBLIC:
                  return this.pub;
                case C.seqno_types.SEMIPRIVATE:
                  return this.semipriv;
                default:
                  return null;
              }
            }).call(_this);
            if ((chain_tail == null) || (chain_tail.seqno !== seqno)) {
              return false;
            }
            found[seqno_type] = true;
          }
          if (((_ref1 = _this.semipriv) != null ? _ref1.seqno : void 0) && (!found[C.seqno_types.SEMIPRIVATE])) {
            return false;
          }
          if (((_ref2 = _this.pub) != null ? _ref2.seqno : void 0) && (!found[C.seqno_types.PUBLIC])) {
            return false;
          }
          return true;
        };
      })(this);
    };

    Leaf.prototype.seqno_and_prev_assertion = function(typ) {
      return (function(_this) {
        return function(rows) {
          var chain_tail;
          chain_tail = (function() {
            switch (typ) {
              case C.seqno_types.PUBLIC:
                return this.pub;
              case C.seqno_types.SEMIPRIVATE:
                return this.semipriv;
              default:
                return null;
            }
          }).call(_this);
          if (rows.length === 0) {
            if (chain_tail === null || chain_tail.length === 0) {
              return true;
            } else {
              return false;
            }
          } else if (rows.length === 1 && (chain_tail != null)) {
            return (chain_tail.seqno === rows[0].seqno) && (chain_tail.payload_hash === rows[0].payload_hash);
          } else {
            return false;
          }
        };
      })(this);
    };

    return Leaf;

  })();

}).call(this);
