// Path: src/main/java/org/apache/solr/handler/component/FacetComponent.java
// public static class TermDocEntry {
//   public final String term;
//   public final String docId;
//   public final String termDocId;
//   public NamedList<Object> termMetadata;
//   public final SolrDocument doc;
// 
//   public TermDocEntry(String term, String termDocId, String docId, NamedList<Object> termMetadata, SolrDocument doc) {
//     this.term = term;
//     this.docId = docId;
//     this.termDocId = termDocId;
//     this.termMetadata = termMetadata;
//     this.doc = doc;
//   }
// 
// }
// 
// Path: src/main/java/org/apache/solr/handler/component/FacetComponent.java
// public static class ShardFacetCount {
//   public String name;
//   // the indexed form of the name... used for comparisons
//   public BytesRef indexed; 
//   public long count;
//   public Object val;
//   public int termNum; // term number starting at 0 (used in bit arrays)
//     
//   @Override
//   public String toString() {
//     return "{term=" + name + ",termNum=" + termNum + ",count=" + count + ",val=" + val + "}";
//   }
// }
// 
// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static interface FacetKey<K extends FacetKey<K>> extends Comparable<K> {
//     
// }


import java.io.IOException;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Map.Entry;
import java.util.function.Predicate;
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.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.component.FacetComponent.DistribFieldFacet.TermDocEntry;
import org.apache.solr.handler.component.FacetComponent.ShardFacetCount;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.FacetKey;
import org.apache.solr.schema.FieldType;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.SolrIndexSearcher;
      this.res = res;
    }
    
    public abstract K incrementKey(K previousKey);
    
    public abstract K decrementKey(K previousKey);
    
    public abstract void addEntry(LimitMinder<T, K> limitMinder, K facetKey, Deque<Entry<String, Object>> entryBuilder) throws IOException;
    
    public abstract K targetKey() throws IOException;

    public abstract K targetKeyInit(boolean ascending) throws IOException;

    public abstract void initState(K key);

    public NamedList<Object> finalize(NamedList<Object> ret) {
      return ret;
    }

  }
  
  public static class DistribDocEnv<T extends FieldType & FacetPayload> extends DistribEnv<T> {

    public DistribDocEnv(int offset, int limit, int targetIdx, int mincount, String fieldName, T ft, NamedList res, ShardFacetCount[] counts) {
      super(offset, limit, targetIdx, mincount, fieldName, ft, res, counts);
    }

    @Override
    public void addEntry(LimitMinder<T, SimpleTermIndexKey> limitMinder, SimpleTermIndexKey facetKey, Deque<Entry<String, Object>> entryBuilder) throws IOException {
      ShardFacetCount sfc = counts[facetKey.index];
// Path: src/main/java/org/apache/solr/handler/component/FacetComponent.java
// public static class TermDocEntry {
//   public final String term;
//   public final String docId;
//   public final String termDocId;
//   public NamedList<Object> termMetadata;
//   public final SolrDocument doc;
// 
//   public TermDocEntry(String term, String termDocId, String docId, NamedList<Object> termMetadata, SolrDocument doc) {
//     this.term = term;
//     this.docId = docId;
//     this.termDocId = termDocId;
//     this.termMetadata = termMetadata;
//     this.doc = doc;
//   }
// 
// }
// 
// Path: src/main/java/org/apache/solr/handler/component/FacetComponent.java
// public static class ShardFacetCount {
//   public String name;
//   // the indexed form of the name... used for comparisons
//   public BytesRef indexed; 
//   public long count;
//   public Object val;
//   public int termNum; // term number starting at 0 (used in bit arrays)
//     
//   @Override
//   public String toString() {
//     return "{term=" + name + ",termNum=" + termNum + ",count=" + count + ",val=" + val + "}";
//   }
// }
// 
// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
// public static interface FacetKey<K extends FacetKey<K>> extends Comparable<K> {
//     
// }


// Path: src/main/java/org/apache/solr/request/BidirectionalFacetResponseBuilder.java
import java.io.IOException;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Map.Entry;
import java.util.function.Predicate;
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.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.component.FacetComponent.DistribFieldFacet.TermDocEntry;
import org.apache.solr.handler.component.FacetComponent.ShardFacetCount;
import org.apache.solr.request.BidirectionalFacetResponseBuilder.FacetKey;
import org.apache.solr.schema.FieldType;
import org.apache.solr.search.DocSet;
import org.apache.solr.search.SolrIndexSearcher;

      this.res = res;
    }
    
    public abstract K incrementKey(K previousKey);
    
    public abstract K decrementKey(K previousKey);
    
    public abstract void addEntry(LimitMinder<T, K> limitMinder, K facetKey, Deque<Entry<String, Object>> entryBuilder) throws IOException;
    
    public abstract K targetKey() throws IOException;

    public abstract K targetKeyInit(boolean ascending) throws IOException;

    public abstract void initState(K key);

    public NamedList<Object> finalize(NamedList<Object> ret) {
      return ret;
    }

  }
  
  public static class DistribDocEnv<T extends FieldType & FacetPayload> extends DistribEnv<T> {

    public DistribDocEnv(int offset, int limit, int targetIdx, int mincount, String fieldName, T ft, NamedList res, ShardFacetCount[] counts) {
      super(offset, limit, targetIdx, mincount, fieldName, ft, res, counts);
    }

    @Override
    public void addEntry(LimitMinder<T, SimpleTermIndexKey> limitMinder, SimpleTermIndexKey facetKey, Deque<Entry<String, Object>> entryBuilder) throws IOException {
      ShardFacetCount sfc = counts[facetKey.index];
      TermDocEntry val = (TermDocEntry)sfc.val;