{"size": 1473, "ext": "js", "max_stars_repo_path": "lib/listener.js", "max_stars_repo_name": "lodosstm/pouch-mirror", "max_stars_repo_stars_event_min_datetime": "2015-04-11T12:08:20.000Z", "max_stars_repo_stars_event_max_datetime": "2021-04-09T22:42:47.000Z", "max_issues_repo_path": "lib/listener.js", "max_issues_repo_name": "lodosstm/pouch-mirror", "max_issues_repo_issues_event_min_datetime": "2016-04-30T16:19:38.000Z", "max_issues_repo_issues_event_max_datetime": "2017-05-08T13:13:54.000Z", "max_forks_repo_path": "lib/listener.js", "max_forks_repo_name": "lodosstm/pouch-mirror", "max_forks_repo_forks_event_min_datetime": "2016-01-02T00:54:37.000Z", "max_forks_repo_forks_event_max_datetime": "2019-04-25T08:27:50.000Z"}
{"max_stars_count": 27, "max_issues_count": 8, "max_forks_count": 8, "avg_line_length": 24.9661016949, "max_line_length": 84, "alphanum_fraction": 0.600814664}
'use strict';
var utils = require('./utils');
var defer = utils.defer;
var timeout = utils.timeout;

var timeLimit = 4900;

module.exports = function (db) {
  var pending = {};
  var bufferedChanges = {};

  // Keep a buffer of recent changes in case the change comes in before our response
  function bufferChange(rev) {
    bufferedChanges[rev] = new Date();
    // get rid of any expired changes
    for(var key in bufferedChanges) {
      if((bufferedChanges[key] + timeLimit) < new Date()) {
        delete bufferedChanges[key];
      }
    }
  }

  // Init Listener
  var listener = db.changes({ since: 'now', live: true })
    .on('change', function (change) {
      change.changes.forEach(function (item) {
        if(typeof pending[item.rev] !== 'undefined') {
          pending[item.rev].resolve({rev: item.rev});
          delete(pending[item.rev]);
        } else {
          bufferChange(item.rev);
        }
      });
    });

  function waitForChange(rev) {
    var deferred = defer();
    timeout(deferred.promise, timeLimit)
      .catch(Promise.TimeoutError, function(err) {
        delete(pending[rev]);
        return Promise.reject(err);
      });
    if(bufferedChanges[rev]) {
      deferred.resolve({rev: rev});
      delete bufferedChanges[rev];
    } else {
      pending[rev] = deferred;
    }
    return deferred.promise;
  }
  
  return {
    waitForChange: waitForChange,
    cancel: function() {
      return listener.cancel();
    }
  };

};