// Generated by IcedCoffeeScript 1.7.1-c
(function() {
  var CHECK, E, Link, PT, ST, TrackWrapper, constants, db, deq, env, iced, log, make_esc, prompt_yn, proof_type_to_string, proofs, scrapers, session, unix_time, util, __iced_k, __iced_k_noop;

  iced = require('iced-runtime').iced;
  __iced_k = __iced_k_noop = function() {};

  db = require('./db').db;

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

  log = require('./log');

  proofs = require('keybase-proofs');

  proof_type_to_string = proofs.proof_type_to_string;

  PT = proofs.constants.proof_types;

  ST = constants.signature_types;

  deq = require('deep-equal');

  E = require('./err').E;

  unix_time = require('pgp-utils').util.unix_time;

  make_esc = require('iced-error').make_esc;

  prompt_yn = require('./prompter').prompt_yn;

  session = require('./session').session;

  db = require('./db');

  util = require('util');

  env = require('./env').env;

  scrapers = require('./scrapers');

  Link = require('./sigchain').Link;

  CHECK = require('./display').CHECK;

  exports.TrackWrapper = TrackWrapper = (function() {
    function TrackWrapper(_arg) {
      this.trackee = _arg.trackee, this.tracker = _arg.tracker, this.local = _arg.local, this.remote = _arg.remote;
      this.uid = this.trackee.id;
      this.sig_chain = this.trackee.sig_chain;
      this._ft = null;
    }

    TrackWrapper.prototype.last = function() {
      return this.sig_chain.last();
    };

    TrackWrapper.prototype.table = function() {
      var _ref, _ref1;
      return ((_ref = this.sig_chain.table) != null ? (_ref1 = _ref.get(ST.REMOTE_PROOF)) != null ? _ref1.to_dict() : void 0 : void 0) || {};
    };

    TrackWrapper.prototype.flat_table = function() {
      if (this._ft == null) {
        this._ft = this.sig_chain.flattened_remote_proofs();
      }
      return this._ft;
    };

    TrackWrapper.prototype._check_remote_proof = function(rp) {
      var a, b, d, link, proofs_with_service_names, rkp, stub, _ref;
      proofs_with_service_names = [PT.twitter, PT.github, PT.reddit, PT.coinbase, PT.hackernews];
      if ((rkp = rp.remote_key_proof) == null) {
        return new E.RemoteProofError("no 'remote_key_proof field'");
      } else if ((stub = scrapers.alloc_stub(rkp.proof_type)) == null) {
        return new E.RemoteProofError("Can't allocate a scraper stub for " + rkp.proof_type);
      } else if (!stub.check_proof(d = rkp.check_data_json)) {
        return new E.RemoteProofError("Bad proof found, for check data: " + (JSON.stringify(d)));
      } else if ((link = this.sig_chain.lookup(rp.curr)) == null) {
        return new E.RemoteProofError("Failed to find a chain link for " + rp.curr);
      } else if (!deq((a = (_ref = link.body()) != null ? _ref.service : void 0), (b = rkp.check_data_json))) {
        log.info("JSON obj mismatch: " + (JSON.stringify(a)) + " != " + (JSON.stringify(b)));
        return new E.RemoteProofError("The check data was wrong for the signature");
      } else {
        return null;
      }
    };

    TrackWrapper.prototype._check_track_obj = function(o) {
      var a, b, err, rp, _i, _len, _ref, _ref1;
      err = null;
      if ((a = o.id) !== (b = this.trackee.id)) {
        err = new E.UidMismatchError("" + a + " != " + b);
      } else if ((a = (_ref = o.basics) != null ? _ref.username : void 0) !== (b = this.trackee.username())) {
        err = new E.UsernameMismatchError("" + a + " != " + b);
      } else {
        _ref1 = o.remote_proofs;
        for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
          rp = _ref1[_i];
          if (err == null) {
            err = this._check_remote_proof(rp);
          }
        }
      }
      return err;
    };

    TrackWrapper.prototype._skip_remote_check = function(which) {
      var a, last, last_check, prob, ret, rpri, track_cert, _check_all_proofs_ok, _ref;
      track_cert = this[which];
      log.debug("+ _skip_remote_check for " + which);
      rpri = constants.time.remote_proof_recheck_interval;
      _check_all_proofs_ok = function(proofs) {
        var proof, _i, _len, _ref;
        for (_i = 0, _len = proofs.length; _i < _len; _i++) {
          proof = proofs[_i];
          if (((_ref = proof.remote_key_proof) != null ? _ref.state : void 0) !== 1) {
            return false;
          }
        }
        return true;
      };
      prob = track_cert == null ? "no track cert given" : (last = this.last()) == null ? "no last link found" : (last_check = track_cert.ctime) == null ? "no last_check" : unix_time() - last_check > rpri ? "timed out!" : !(this.sig_chain.is_track_fresh(a = (_ref = track_cert.seq_tail) != null ? _ref.payload_hash : void 0)) ? "we've signed link " + a + " which is no longer a fresh track" : !(_check_all_proofs_ok(track_cert.remote_proofs)) ? "all proofs were not OK" : void 0;
      ret = prob != null ? (log.debug("| problem: " + prob), track_cert != null ? log.debug("| track cert: " + (JSON.stringify(track_cert))) : void 0, last != null ? log.debug("| last link: " + (JSON.stringify(last))) : void 0, false) : (log.debug("| Timing was ok: " + (unix_time()) + " - " + last_check + " < " + rpri), true);
      log.debug("- _skip_remote_check -> " + ret);
      return ret;
    };

    TrackWrapper.prototype._skip_approval = function(which) {
      var a, b, dlen, prob, ret, rkp, row, rp, sub_id, tmp, track_cert;
      track_cert = this[which];
      log.debug("+ skip_approval(" + which + ")");
      dlen = function(d) {
        if (d != null) {
          return Object.keys(d).length;
        } else {
          return 0;
        }
      };
      prob = (function() {
        var _i, _len, _ref, _ref1, _ref2, _ref3;
        if (track_cert == null) {
          return "no cert found";
        } else if ((a = (_ref = track_cert.key) != null ? _ref.kid : void 0) !== (b = (_ref1 = this.trackee.merkle_data) != null ? _ref1.eldest_kid : void 0)) {
          return "trackee changed keys: " + a + " != " + b;
        } else if ((a = track_cert.remote_proofs.length) !== (b = this.flat_table().length)) {
          return "number of remote IDs changed: " + a + " != " + b;
        } else {
          tmp = null;
          _ref2 = track_cert.remote_proofs;
          for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
            rp = _ref2[_i];
            rkp = rp.remote_key_proof;
            row = this.table()[rkp.proof_type];
            if (row == null) {
              tmp = "Proof deleted: " + (JSON.stringify(rkp.check_data_json));
              break;
            } else {
              if (!row.is_leaf()) {
                sub_id = scrapers.alloc_stub(rkp.proof_type).get_sub_id(rkp.check_data_json);
                row = row.get(sub_id);
              }
              if (row == null) {
                tmp = "Missing sub ID: " + (JSON.stringify(rkp.proof_type));
                break;
              }
              if (!row.is_leaf()) {
                tmp = "Got bad link, it wasn't a link at all (for proof type: " + rkp.proof_type + ")";
                break;
              } else if (!deq((a = rkp.check_data_json), (b = row != null ? (_ref3 = row.body()) != null ? _ref3.service : void 0 : void 0))) {
                tmp = "Remote ID changed: " + (JSON.stringify(a)) + " != " + (JSON.stringify(b));
                break;
              }
            }
          }
          return tmp;
        }
      }).call(this);
      ret = true;
      if (prob != null) {
        log.debug("| failure: " + prob);
        ret = false;
      }
      log.debug("- skip_approval(" + which + ") -> " + ret);
      return ret;
    };

    TrackWrapper.prototype.skip_remote_check = function() {
      var ret;
      ret = this._skip_remote_check('remote') ? constants.skip.REMOTE : this._skip_remote_check('local') ? constants.skip.LOCAL : constants.skip.NONE;
      log.debug("| skip_remote_check -> " + ret);
      return ret;
    };

    TrackWrapper.prototype.skip_approval = function() {
      var ret;
      ret = this._skip_approval('remote') ? constants.skip.REMOTE : this._skip_approval('local') ? constants.skip.LOCAL : constants.skip.NONE;
      log.debug("| skip_approval -> " + ret);
      return ret;
    };

    TrackWrapper.prototype.load_local = function(cb) {
      var err, value, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      log.debug("+ getting local tracking info from DB");
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/node-client/src/trackwrapper.iced",
            funcname: "TrackWrapper.load_local"
          });
          db.get({
            type: constants.ids.local_track,
            key: _this.uid
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                err = arguments[0];
                return value = arguments[1];
              };
            })(),
            lineno: 174
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          _this.local = value;
          log.debug("- completed, with result: " + (!!value));
          return cb(err);
        };
      })(this));
    };

    TrackWrapper.prototype.store_local = function(cb) {
      var err, type, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      log.debug("+ storing local track object");
      type = constants.ids.local_track;
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/node-client/src/trackwrapper.iced",
            funcname: "TrackWrapper.store_local"
          });
          db.put({
            type: type,
            key: _this.uid,
            value: _this.track_obj
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return err = arguments[0];
              };
            })(),
            lineno: 184
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          log.info("" + CHECK + " Wrote tracking info to local database");
          log.debug("- stored local track object");
          return cb(err);
        };
      })(this));
    };

    TrackWrapper.remove_local_track = function(_arg, cb) {
      var err, uid, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      uid = _arg.uid;
      log.debug("+ removing local track object for " + uid);
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/node-client/src/trackwrapper.iced",
            funcname: "TrackWrapper.remove_local_track"
          });
          db.remove({
            type: constants.ids.local_track,
            key: uid,
            optional: true
          }, __iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return err = arguments[0];
              };
            })(),
            lineno: 197
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          log.debug("- removed local track object -> " + err);
          return cb(err);
        };
      })(this));
    };

    TrackWrapper.prototype.check = function() {
      var e;
      if (this.local) {
        if ((e = this._check_track_obj(this.local)) != null) {
          log.warn("Local tracking object was invalid: " + e.message);
          this.local = null;
        } else {
          log.debug("| local track checked out");
        }
      }
      if (this.remote != null) {
        if ((e = this._check_track_obj(this.remote)) != null) {
          log.warn("Remote tracking object was invalid: " + e.message);
          return this.remote = null;
        } else {
          return log.debug("| remote track checked out");
        }
      }
    };

    TrackWrapper.load = function(_arg, cb) {
      var err, remote, track, trackee, tracker, uid, ___iced_passed_deferral, __iced_deferrals, __iced_k, _ref;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      tracker = _arg.tracker, trackee = _arg.trackee;
      uid = trackee.id;
      remote = tracker != null ? (_ref = tracker.sig_chain) != null ? _ref.get_track_obj(uid) : void 0 : void 0;
      log.debug("+ loading Tracking info w/ remote=" + (!!remote));
      track = new TrackWrapper({
        uid: uid,
        trackee: trackee,
        tracker: tracker,
        remote: remote
      });
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/node-client/src/trackwrapper.iced",
            funcname: "TrackWrapper.load"
          });
          track.load_local(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return err = arguments[0];
              };
            })(),
            lineno: 224
          }));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          if (typeof err !== "undefined" && err !== null) {
            track = null;
          }
          if (track != null) {
            track.check();
          }
          log.debug("- loaded tracking info");
          return cb(err, track);
        };
      })(this));
    };

    TrackWrapper.prototype.is_tracking = function() {
      return {
        remote: !!this.remote,
        local: !!this.local
      };
    };

    TrackWrapper.prototype.store_remote = function(cb) {
      var esc, g, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      esc = make_esc(cb, "TrackWrapper::store_remote");
      (function(_this) {
        return (function(__iced_k) {
          __iced_deferrals = new iced.Deferrals(__iced_k, {
            parent: ___iced_passed_deferral,
            filename: "/home/jacko/node-client/src/trackwrapper.iced",
            funcname: "TrackWrapper.store_remote"
          });
          _this.tracker.gen_track_proof_gen({
            uid: _this.uid,
            track_obj: _this.track_obj
          }, esc(__iced_deferrals.defer({
            assign_fn: (function() {
              return function() {
                return g = arguments[0];
              };
            })(),
            lineno: 238
          })));
          __iced_deferrals._fulfill();
        });
      })(this)((function(_this) {
        return function() {
          (function(__iced_k) {
            __iced_deferrals = new iced.Deferrals(__iced_k, {
              parent: ___iced_passed_deferral,
              filename: "/home/jacko/node-client/src/trackwrapper.iced",
              funcname: "TrackWrapper.store_remote"
            });
            g.run(esc(__iced_deferrals.defer({
              lineno: 239
            })));
            __iced_deferrals._fulfill();
          })(function() {
            log.info("" + CHECK + " Wrote tracking info to remote keybase.io server");
            return cb(null);
          });
        };
      })(this));
    };

    TrackWrapper.prototype.store_track = function(_arg, cb) {
      var do_remote, esc, ___iced_passed_deferral, __iced_deferrals, __iced_k;
      __iced_k = __iced_k_noop;
      ___iced_passed_deferral = iced.findDeferral(arguments);
      do_remote = _arg.do_remote;
      esc = make_esc(cb, "TrackWrapper::store_track");
      log.debug("+ track user (remote=" + do_remote + ")");
      this.track_obj = this.trackee.gen_track_obj();
      log.debug("| object generated: " + (JSON.stringify(this.track_obj)));
      (function(_this) {
        return (function(__iced_k) {
          if (do_remote) {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/jacko/node-client/src/trackwrapper.iced",
                funcname: "TrackWrapper.store_track"
              });
              _this.store_remote(esc(__iced_deferrals.defer({
                lineno: 251
              })));
              __iced_deferrals._fulfill();
            })(__iced_k);
          } else {
            (function(__iced_k) {
              __iced_deferrals = new iced.Deferrals(__iced_k, {
                parent: ___iced_passed_deferral,
                filename: "/home/jacko/node-client/src/trackwrapper.iced",
                funcname: "TrackWrapper.store_track"
              });
              _this.store_local(esc(__iced_deferrals.defer({
                lineno: 253
              })));
              __iced_deferrals._fulfill();
            })(__iced_k);
          }
        });
      })(this)((function(_this) {
        return function() {
          log.debug("- tracked user");
          return cb(null);
        };
      })(this));
    };

    return TrackWrapper;

  })();

}).call(this);
