// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static abstract class BaseLocalTermEnv<T extends FieldType & FacetPayload, K extends FacetKey<K>> extends LocalEnv<T, K> {
// 
//   public BaseLocalTermEnv(int offset, int limit, int startTermIndex, int adjust, int targetIdx, int nTerms, Predicate<BytesRef> termFilter,
//       int mincount, int[] counts, CharsRefBuilder charsRef, boolean extend, SortedSetDocValues si,
//       SolrIndexSearcher searcher, List<Entry<LeafReader, Bits>> leaves, String fieldName, T ft, NamedList res) {
//     super(offset, limit, startTermIndex, adjust, targetIdx, nTerms, termFilter, mincount, counts,
//         charsRef, extend, si, searcher, leaves, fieldName, ft, res);
//   }
// 
//   protected final int incrementTermIndex(int lastKeyIndex) {
//     for (int i = lastKeyIndex + 1; i < endTermOrd; i++) {
//       if (acceptTerm(i)) {
//         return i;
//       }
//     }
//     return -1;
//   }
// 
//   protected final int decrementTermIndex(int lastKeyIndex) {
//     for (int i = lastKeyIndex - 1; i >= startTermOrd; i--) {
//       if (acceptTerm(i)) {
//         return i;
//       }
//     }
//     return -1;
//   }
// 
//   protected final int getTargetKeyIndex() {
//     return (targetIdx < 0 ? ~targetIdx : targetIdx);
//   }
// 
//   protected final int getTargetKeyIndexInit(boolean ascending) {
//     int index = getTargetKeyIndex();
//     if (index >= startTermOrd && index < endTermOrd && acceptTerm(index)) {
//       return index;
//     } else if (ascending) {
//       return incrementTermIndex(index);
//     } else {
//       return decrementTermIndex(index);
//     }
//   }
// }
// 
// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static class BaseTermIndexKey<K extends BaseTermIndexKey<K>> implements FacetKey<K> {
// 
//   public final int index;
//     
//   public BaseTermIndexKey(int index) {
//     this.index = index;
//   }
//     
//   @Override
//   public int compareTo(BaseTermIndexKey o) {
//     return Integer.compare(index, o.index);
//   }
// 
//   @Override
//   public String toString() {
//     return BaseTermIndexKey.class.getSimpleName() + "(index=" + index + ')';
//   }
// 
// }
// 
// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static interface LimitMinder<T extends FieldType & FacetPayload, K extends FacetKey<K>> {
//   K startKey();
//   K nextKey(K lastKey, Env<T, K> env);
//   void addEntry(Entry<String, Object> entry, Deque<Entry<String, Object>> entryBuilder);
//   boolean updateEntry(String term, String docId, SolrDocument doc, Deque<Entry<String, Object>> entryBuilder);
//   void removeTail(Deque<Entry<String, Object>> entryBuilder);
// }


import java.io.IOException;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.lucene.util.UnicodeUtil;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.BaseLocalTermEnv;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.BaseTermIndexKey;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.LimitMinder;
import org.apache.solr.response.DocsStreamer;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.SolrIndexSearcher;
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.request;


/**
 *
 * @author magibney
 */
public class DocBasedFacetResponseBuilder {

  public static class TermDocIndexKey extends BaseTermIndexKey<TermDocIndexKey> {

    public final BytesRef docId;

    public TermDocIndexKey(int index, BytesRef docId) {
      super(index);
      this.docId = docId;
    }

    @Override
    public String toString() {
      return TermDocIndexKey.class.getSimpleName() + "(index=" + index + ", docId=" + LocalDocEnv.brToString(docId) + ')';
    }

  }

// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static abstract class BaseLocalTermEnv<T extends FieldType & FacetPayload, K extends FacetKey<K>> extends LocalEnv<T, K> {
// 
//   public BaseLocalTermEnv(int offset, int limit, int startTermIndex, int adjust, int targetIdx, int nTerms, Predicate<BytesRef> termFilter,
//       int mincount, int[] counts, CharsRefBuilder charsRef, boolean extend, SortedSetDocValues si,
//       SolrIndexSearcher searcher, List<Entry<LeafReader, Bits>> leaves, String fieldName, T ft, NamedList res) {
//     super(offset, limit, startTermIndex, adjust, targetIdx, nTerms, termFilter, mincount, counts,
//         charsRef, extend, si, searcher, leaves, fieldName, ft, res);
//   }
// 
//   protected final int incrementTermIndex(int lastKeyIndex) {
//     for (int i = lastKeyIndex + 1; i < endTermOrd; i++) {
//       if (acceptTerm(i)) {
//         return i;
//       }
//     }
//     return -1;
//   }
// 
//   protected final int decrementTermIndex(int lastKeyIndex) {
//     for (int i = lastKeyIndex - 1; i >= startTermOrd; i--) {
//       if (acceptTerm(i)) {
//         return i;
//       }
//     }
//     return -1;
//   }
// 
//   protected final int getTargetKeyIndex() {
//     return (targetIdx < 0 ? ~targetIdx : targetIdx);
//   }
// 
//   protected final int getTargetKeyIndexInit(boolean ascending) {
//     int index = getTargetKeyIndex();
//     if (index >= startTermOrd && index < endTermOrd && acceptTerm(index)) {
//       return index;
//     } else if (ascending) {
//       return incrementTermIndex(index);
//     } else {
//       return decrementTermIndex(index);
//     }
//   }
// }
// 
// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static class BaseTermIndexKey<K extends BaseTermIndexKey<K>> implements FacetKey<K> {
// 
//   public final int index;
//     
//   public BaseTermIndexKey(int index) {
//     this.index = index;
//   }
//     
//   @Override
//   public int compareTo(BaseTermIndexKey o) {
//     return Integer.compare(index, o.index);
//   }
// 
//   @Override
//   public String toString() {
//     return BaseTermIndexKey.class.getSimpleName() + "(index=" + index + ')';
//   }
// 
// }
// 
// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static interface LimitMinder<T extends FieldType & FacetPayload, K extends FacetKey<K>> {
//   K startKey();
//   K nextKey(K lastKey, Env<T, K> env);
//   void addEntry(Entry<String, Object> entry, Deque<Entry<String, Object>> entryBuilder);
//   boolean updateEntry(String term, String docId, SolrDocument doc, Deque<Entry<String, Object>> entryBuilder);
//   void removeTail(Deque<Entry<String, Object>> entryBuilder);
// }


// Path: src/main/java/org/apache/solr/request/DocBasedFacetResponseBuilder.java
import java.io.IOException;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.function.Predicate;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.PostingsEnum;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.lucene.util.UnicodeUtil;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.BaseLocalTermEnv;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.BaseTermIndexKey;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.LimitMinder;
import org.apache.solr.response.DocsStreamer;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.search.DocList;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.SolrIndexSearcher;

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.solr.request;


/**
 *
 * @author magibney
 */
public class DocBasedFacetResponseBuilder {

  public static class TermDocIndexKey extends BaseTermIndexKey<TermDocIndexKey> {

    public final BytesRef docId;

    public TermDocIndexKey(int index, BytesRef docId) {
      super(index);
      this.docId = docId;
    }

    @Override
    public String toString() {
      return TermDocIndexKey.class.getSimpleName() + "(index=" + index + ", docId=" + LocalDocEnv.brToString(docId) + ')';
    }

  }

  public static class LocalDocEnv<T extends FieldType & FacetPayload> extends BaseLocalTermEnv<T, TermDocIndexKey> {