/**
   * in CBL_Puller.m - (void) changeTrackerReceivedSequence: (id)remoteSequenceID docID:
   * (NSString*)docID revIDs: (NSArray*)revIDs deleted: (BOOL)deleted
   */
  protected void processChangeTrackerChange(final Map<String, Object> change) {
    String lastSequence = change.get("seq").toString();
    String docID = (String) change.get("id");
    if (docID == null) {
      return;
    }

    if (!Document.isValidDocumentId(docID)) {
      Log.w(Log.TAG_SYNC, "%s: Received invalid doc ID from _changes: %s", this, change);
      return;
    }
    boolean deleted =
        (change.containsKey("deleted") && ((Boolean) change.get("deleted")).equals(Boolean.TRUE));
    List<Map<String, Object>> changes = (List<Map<String, Object>>) change.get("changes");
    for (Map<String, Object> changeDict : changes) {
      String revID = (String) changeDict.get("rev");
      if (revID == null) {
        continue;
      }

      PulledRevision rev = new PulledRevision(docID, revID, deleted);

      // Remember its remote sequence ID (opaque), and make up a numeric sequence
      // based on the order in which it appeared in the _changes feed:
      rev.setRemoteSequenceID(lastSequence);

      if (changes.size() > 1) rev.setConflicted(true);

      Log.d(Log.TAG_SYNC, "%s: adding rev to inbox %s", this, rev);

      Log.v(Log.TAG_SYNC, "%s: changeTrackerReceivedChange() incrementing changesCount by 1", this);

      // this is purposefully done slightly different than the ios version
      addToChangesCount(1);

      addToInbox(rev);
    }

    pauseOrResume();
  }
  /** Process a bunch of remote revisions from the _changes feed at once */
  @Override
  @InterfaceAudience.Private
  protected void processInbox(RevisionList inbox) {
    Log.d(Log.TAG_SYNC, "processInbox called");

    if (canBulkGet == null) {
      canBulkGet = serverIsSyncGatewayVersion("0.81");
    }

    // Ask the local database which of the revs are not known to it:
    String lastInboxSequence = ((PulledRevision) inbox.get(inbox.size() - 1)).getRemoteSequenceID();

    int numRevisionsRemoved = 0;
    try {
      // findMissingRevisions is the local equivalent of _revs_diff. it looks at the
      // array of revisions in "inbox" and removes the ones that already exist.
      // So whatever's left in 'inbox'
      // afterwards are the revisions that need to be downloaded.
      numRevisionsRemoved = db.findMissingRevisions(inbox);
    } catch (SQLException e) {
      Log.e(Log.TAG_SYNC, String.format("%s failed to look up local revs", this), e);
      inbox = null;
    }

    // introducing this to java version since inbox may now be null everywhere
    int inboxCount = 0;
    if (inbox != null) {
      inboxCount = inbox.size();
    }

    if (numRevisionsRemoved > 0) {
      Log.v(
          Log.TAG_SYNC,
          "%s: processInbox() setting changesCount to: %s",
          this,
          getChangesCount().get() - numRevisionsRemoved);
      // May decrease the changesCount, to account for the revisions we just found out we don't need
      // to get.
      addToChangesCount(-1 * numRevisionsRemoved);
    }

    if (inboxCount == 0) {
      // Nothing to do. Just bump the lastSequence.
      Log.w(
          Log.TAG_SYNC,
          "%s no new remote revisions to fetch.  add lastInboxSequence (%s) to pendingSequences (%s)",
          this,
          lastInboxSequence,
          pendingSequences);
      long seq = pendingSequences.addValue(lastInboxSequence);
      pendingSequences.removeSequence(seq);
      setLastSequence(pendingSequences.getCheckpointedValue());
      pauseOrResume();
      return;
    }

    Log.v(Log.TAG_SYNC, "%s: fetching %s remote revisions...", this, inboxCount);

    // Dump the revs into the queue of revs to pull from the remote db:
    for (int i = 0; i < inbox.size(); i++) {
      PulledRevision rev = (PulledRevision) inbox.get(i);
      if (canBulkGet || (rev.getGeneration() == 1 && !rev.isDeleted() && !rev.isConflicted())) {
        bulkRevsToPull.add(rev);
      } else {
        queueRemoteRevision(rev);
      }
      rev.setSequence(pendingSequences.addValue(rev.getRemoteSequenceID()));
    }
    pullRemoteRevisions();
    pauseOrResume();
  }