// Generated by IcedCoffeeScript 1.7.1-g
(function() {
  var AND, Expr, Fingerprint, Host, Http, Keybase, OR, Parser, Proof, ProofSet, URI, Web, parse, urlmod,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
    __slice = [].slice;

  urlmod = require('url');

  Parser = require('./assertion_parser').Parser;

  Expr = (function() {
    function Expr() {}

    Expr.prototype.toString = function() {};

    Expr.prototype.match_set = function(proof_set) {
      return false;
    };

    return Expr;

  })();

  exports.URI = URI = (function(_super) {
    __extends(URI, _super);

    function URI(_arg) {
      this.key = _arg.key, this.value = _arg.value;
    }

    URI.prototype.keys = function() {
      return [this.key];
    };

    URI.prototype.check = function() {
      var _ref;
      if (!this.value && (this.value.length != null)) {
        throw new Error("Bad '" + this.key + "' assertion, no value found");
      }
      if ((_ref = this.key) !== 'twitter' && _ref !== 'github' && _ref !== 'hackernews' && _ref !== 'reddit' && _ref !== 'keybase' && _ref !== 'coinbase') {
        throw new Error("Unknown assertion type '" + this.key + "'");
      }
    };

    URI.prototype.to_lookup_query = function() {
      var d;
      d = {};
      d[this.key] = this.value;
      return d;
    };

    URI.parse_to_kv_pair = function(s) {
      var key, obj, value;
      obj = urlmod.parse(s);
      if (((key = obj.protocol) != null) && key.length) {
        key = key.toLowerCase();
        if ((key != null) && key.slice(-1) === ':') {
          key = key.slice(0, -1);
        }
      }
      value = obj.hostname;
      if ((key == null) && (value == null)) {
        value = obj.pathname;
      }
      if (value != null) {
        value = value.toLowerCase();
      }
      return {
        key: key,
        value: value
      };
    };

    URI.parse = function(_arg) {
      var key, klass, klasses, ret, s, strict, value, _ref;
      s = _arg.s, strict = _arg.strict;
      _ref = URI.parse_to_kv_pair(s), key = _ref.key, value = _ref.value;
      if (key != null ? key.length : void 0) {

      } else if (!strict) {
        key = "keybase";
      } else {
        throw new Error("Bad assertion, no 'type' given: " + s);
      }
      klasses = {
        web: Web,
        http: Http,
        dns: Host,
        https: Host,
        fingerprint: Fingerprint,
        keybase: Keybase
      };
      if ((klass = klasses[key]) == null) {
        klass = URI;
      }
      ret = new klass({
        key: key,
        value: value
      });
      ret.check();
      return ret;
    };

    URI.prototype.toString = function() {
      return "" + this.key + "://" + this.value;
    };

    URI.prototype.match_set = function(proof_set) {
      var proof, proofs, _i, _len;
      proofs = proof_set.get(this.keys());
      for (_i = 0, _len = proofs.length; _i < _len; _i++) {
        proof = proofs[_i];
        if (this.match_proof(proof)) {
          return true;
        }
      }
      return false;
    };

    URI.prototype.match_proof = function(proof) {
      var _ref;
      return (_ref = proof.key.toLowerCase(), __indexOf.call(this.keys(), _ref) >= 0) && (this.value === proof.value.toLowerCase());
    };

    URI.prototype.is_keybase = function() {
      return false;
    };

    return URI;

  })(Expr);

  Host = (function(_super) {
    __extends(Host, _super);

    function Host() {
      return Host.__super__.constructor.apply(this, arguments);
    }

    Host.prototype.check = function() {
      if (this.value.indexOf(".") < 0) {
        throw new Error("Bad hostname given: " + this.value);
      }
    };

    return Host;

  })(URI);

  Web = (function(_super) {
    __extends(Web, _super);

    function Web() {
      return Web.__super__.constructor.apply(this, arguments);
    }

    Web.prototype.keys = function() {
      return ['http', 'https', 'dns'];
    };

    return Web;

  })(Host);

  Http = (function(_super) {
    __extends(Http, _super);

    function Http() {
      return Http.__super__.constructor.apply(this, arguments);
    }

    Http.prototype.keys = function() {
      return ['http', 'https'];
    };

    return Http;

  })(Host);

  Fingerprint = (function(_super) {
    __extends(Fingerprint, _super);

    function Fingerprint() {
      return Fingerprint.__super__.constructor.apply(this, arguments);
    }

    Fingerprint.prototype.match_proof = function(proof) {
      return (this.key === proof.key.toLowerCase()) && (this.value === proof.value.slice(-1 * this.value.length).toLowerCase());
    };

    Fingerprint.prototype.check = function() {
      if (!this.value.match(/^[a-fA-F0-9]+$/)) {
        throw new Error("Bad fingerprint given: " + this.value);
      }
    };

    Fingerprint.prototype.to_lookup_query = function() {
      return {
        key_suffix: this.value
      };
    };

    return Fingerprint;

  })(URI);

  Keybase = (function(_super) {
    __extends(Keybase, _super);

    function Keybase() {
      return Keybase.__super__.constructor.apply(this, arguments);
    }

    Keybase.prototype.is_keybase = function() {
      return true;
    };

    return Keybase;

  })(URI);

  exports.AND = AND = (function(_super) {
    __extends(AND, _super);

    function AND() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      this.factors = args;
    }

    AND.prototype.toString = function() {
      var f;
      return "(" + ((function() {
        var _i, _len, _ref, _results;
        _ref = this.factors;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          f = _ref[_i];
          _results.push(f.toString());
        }
        return _results;
      }).call(this)).join(" && ") + ")";
    };

    AND.prototype.match_set = function(proof_set) {
      var f, _i, _len, _ref;
      _ref = this.factors;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        f = _ref[_i];
        if (!f.match_set(proof_set)) {
          return false;
        }
      }
      return true;
    };

    return AND;

  })(Expr);

  OR = (function(_super) {
    __extends(OR, _super);

    function OR() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      this.terms = args;
    }

    OR.prototype.toString = function() {
      var t;
      return "(" + ((function() {
        var _i, _len, _ref, _results;
        _ref = this.terms;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          t = _ref[_i];
          _results.push(t.toString());
        }
        return _results;
      }).call(this)).join(" || ") + ")";
    };

    OR.prototype.match_set = function(proof_set) {
      var t, _i, _len, _ref;
      _ref = this.terms;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        t = _ref[_i];
        if (t.match_set(proof_set)) {
          return true;
        }
      }
      return false;
    };

    return OR;

  })(Expr);

  exports.Proof = Proof = (function() {
    function Proof(_arg) {
      this.key = _arg.key, this.value = _arg.value;
    }

    return Proof;

  })();

  exports.ProofSet = ProofSet = (function() {
    function ProofSet(proofs) {
      this.proofs = proofs;
      this.make_index();
    }

    ProofSet.prototype.get = function(keys) {
      var k, out, v, _i, _len;
      out = [];
      for (_i = 0, _len = keys.length; _i < _len; _i++) {
        k = keys[_i];
        if ((v = this._index[k]) != null) {
          out = out.concat(v);
        }
      }
      return out;
    };

    ProofSet.prototype.make_index = function() {
      var d, proof, v, _i, _len, _ref;
      d = {};
      _ref = this.proofs;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        proof = _ref[_i];
        if ((v = d[proof.key]) == null) {
          v = d[proof.key] = [];
        }
        v.push(proof);
      }
      return this._index = d;
    };

    return ProofSet;

  })();

  exports.parse = parse = function(s) {
    var parser;
    parser = new Parser;
    parser.yy = {
      URI: URI,
      OR: OR,
      AND: AND
    };
    return parser.parse(s);
  };

}).call(this);
