// Path: src/main/java/org/apache/solr/request/FacetPayload.java
// public interface FacetPayload<T> {
//   long extractCount(T val);
//   boolean addEntry(String termKey, long count, Term term, List<Entry<LeafReader, Bits>> leaves, NamedList<T> res) throws IOException;
//   Entry<String, T> addEntry(String termKey, long count, Term term, List<Entry<LeafReader, Bits>> leaves) throws IOException;
//   T mergePayload(T preExisting, T add, long preExistingCount, long addCount);
//   Object updateValueExternalRepresentation(T internal);
// }
// 
// Path: src/main/java/org/apache/solr/request/MultiSerializable.java
// public interface MultiSerializable {
// 
//   CharsRef readableToDisplay(CharsRef input);
// 
//   String readableToDisplay(String input);
// 
//   CharsRef readableToSerialized(CharsRef input);
// 
//   String readableToSerialized(String input);
// 
//   CharsRef indexedToNormalized(BytesRef input, CharsRefBuilder output);
// 
//   String indexedToNormalized(String indexedForm);
// 
//   void updateExternalRepresentation(NamedList<Object> nl);
// 
//   BytesRef normalizeQueryTarget(String val, boolean strict, String fieldName) throws IOException;
// 
//   BytesRef normalizeQueryTarget(String val, boolean strict, String fieldName, boolean appendExtraDelim) throws IOException;
// 
//   String getDelim();
// }


import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.CharsRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.request.FacetPayload;
import org.apache.solr.request.MultiSerializable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.TextField;

  private static final String SERIALIZER_ARGNAME = "serializer";
  private static final String DISPLAYIZER_ARGNAME = "displayizer";
  private static final String PAYLOAD_HANDLER_ARGNAME = "payloadHandler";
  private static final String HIERARCHY_LEVEL_ARGNAME = "hierarchyLevel";
  private static final char DELIM_CHAR = '\u0000';
  private static final int DEFAULT_HIERARCHY_LEVEL = 0;

  private int hierarchyLevel = DEFAULT_HIERARCHY_LEVEL;
  private String delim;
  private byte[] delimBytes;
  private TextTransformer serializer;
  private TextTransformer displayizer;
  private FacetPayload payloadHandler;

  private String initDelim(int hierarchyLevel) {
    char[] tmp = new char[hierarchyLevel + 1];
    Arrays.fill(tmp, DELIM_CHAR);
    return new String(tmp);
  }

  @Override
  protected void init(IndexSchema schema, Map<String, String> args) {
    SolrResourceLoader loader = schema.getResourceLoader();
    if (args.containsKey(SERIALIZER_ARGNAME)) {
      serializer = loader.newInstance(args.remove(SERIALIZER_ARGNAME), TextTransformer.class);
    }
    if (args.containsKey(DISPLAYIZER_ARGNAME)) {
      displayizer = loader.newInstance(args.remove(DISPLAYIZER_ARGNAME), TextTransformer.class);
    }
// Path: src/main/java/org/apache/solr/request/FacetPayload.java
// public interface FacetPayload<T> {
//   long extractCount(T val);
//   boolean addEntry(String termKey, long count, Term term, List<Entry<LeafReader, Bits>> leaves, NamedList<T> res) throws IOException;
//   Entry<String, T> addEntry(String termKey, long count, Term term, List<Entry<LeafReader, Bits>> leaves) throws IOException;
//   T mergePayload(T preExisting, T add, long preExistingCount, long addCount);
//   Object updateValueExternalRepresentation(T internal);
// }
// 
// Path: src/main/java/org/apache/solr/request/MultiSerializable.java
// public interface MultiSerializable {
// 
//   CharsRef readableToDisplay(CharsRef input);
// 
//   String readableToDisplay(String input);
// 
//   CharsRef readableToSerialized(CharsRef input);
// 
//   String readableToSerialized(String input);
// 
//   CharsRef indexedToNormalized(BytesRef input, CharsRefBuilder output);
// 
//   String indexedToNormalized(String indexedForm);
// 
//   void updateExternalRepresentation(NamedList<Object> nl);
// 
//   BytesRef normalizeQueryTarget(String val, boolean strict, String fieldName) throws IOException;
// 
//   BytesRef normalizeQueryTarget(String val, boolean strict, String fieldName, boolean appendExtraDelim) throws IOException;
// 
//   String getDelim();
// }


// Path: src/main/java/edu/upenn/library/solrplugins/CaseInsensitiveSortingTextField.java
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
import org.apache.lucene.analysis.tokenattributes.TypeAttribute;
import org.apache.lucene.index.LeafReader;
import org.apache.lucene.index.Term;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.CharsRef;
import org.apache.lucene.util.CharsRefBuilder;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.request.FacetPayload;
import org.apache.solr.request.MultiSerializable;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.TextField;


  private static final String SERIALIZER_ARGNAME = "serializer";
  private static final String DISPLAYIZER_ARGNAME = "displayizer";
  private static final String PAYLOAD_HANDLER_ARGNAME = "payloadHandler";
  private static final String HIERARCHY_LEVEL_ARGNAME = "hierarchyLevel";
  private static final char DELIM_CHAR = '\u0000';
  private static final int DEFAULT_HIERARCHY_LEVEL = 0;

  private int hierarchyLevel = DEFAULT_HIERARCHY_LEVEL;
  private String delim;
  private byte[] delimBytes;
  private TextTransformer serializer;
  private TextTransformer displayizer;
  private FacetPayload payloadHandler;

  private String initDelim(int hierarchyLevel) {
    char[] tmp = new char[hierarchyLevel + 1];
    Arrays.fill(tmp, DELIM_CHAR);
    return new String(tmp);
  }

  @Override
  protected void init(IndexSchema schema, Map<String, String> args) {
    SolrResourceLoader loader = schema.getResourceLoader();
    if (args.containsKey(SERIALIZER_ARGNAME)) {
      serializer = loader.newInstance(args.remove(SERIALIZER_ARGNAME), TextTransformer.class);
    }
    if (args.containsKey(DISPLAYIZER_ARGNAME)) {
      displayizer = loader.newInstance(args.remove(DISPLAYIZER_ARGNAME), TextTransformer.class);
    }
    if (args.containsKey(PAYLOAD_HANDLER_ARGNAME)) {