/**
   * Returns the correct current Lucene field name to use, based on the complex field name, property
   * name and list of alternatives.
   *
   * @param includeAlternative if true, also includes the default alternative at the end of the
   *     field name (alternatives determine stuff like case-/diacritics-sensitivity).
   * @return null if field, property or alternative not found; valid Lucene field name otherwise
   */
  public String luceneField(boolean includeAlternative) {

    // Determine available alternatives based on sensitivity preferences.
    String[] alternatives = includeAlternative ? getAlternatives() : null;

    if (searcher == null) {
      // Mostly for testing. Don't check, just combine field parts.
      if (alternatives == null || alternatives.length == 0)
        return ComplexFieldUtil.propertyField(fieldName, propName);
      return ComplexFieldUtil.propertyField(fieldName, propName, alternatives[0]);
    }

    // Find the field and the property.
    ComplexFieldDesc cfd = searcher.getIndexStructure().getComplexFieldDesc(fieldName);
    if (cfd == null) return null;

    if (ComplexFieldUtil.isBookkeepingSubfield(propName)) {
      // Not a property but a bookkeeping subfield (prob. starttag/endtag); ok, return it
      // (can be removed when old field naming scheme is removed)
      return ComplexFieldUtil.bookkeepingField(fieldName, propName);
    }

    // Find the property
    PropertyDesc pd = cfd.getPropertyDesc(propName);
    if (pd == null)
      return ComplexFieldUtil.propertyField(
          fieldName, propName); // doesn't exist? use plain property name

    if (alternatives == null || alternatives.length == 0) {
      // Don't use any alternatives
      return ComplexFieldUtil.propertyField(fieldName, propName);
    }

    // Find the first available alternative to use
    for (String alt : alternatives) {
      if (pd.hasAlternative(alt)) {
        // NOTE: is this loop necessary at all? getAlternatives() only
        //  returns available alternatives, so the first one should always
        //  be okay, right?
        return ComplexFieldUtil.propertyField(fieldName, propName, alt);
      }
    }

    // No valid alternative found. Use plain property.
    // NOTE: should never happen, and doesn't make sense anymore as there are
    // no 'plain properties' anymore.
    return ComplexFieldUtil.propertyField(fieldName, propName);
  }
  /**
   * Return alternatives for the current field/prop that exist and are appropriate for our current
   * settings.
   *
   * @return the alternatives that exist, in order of appropriateness
   */
  private String[] getAlternatives() {

    if (searcher == null) {
      // Test
      if (caseSensitive) return new String[] {"s", "i"};
      return new String[] {"i", "s"};
    }

    final String s = ComplexFieldUtil.SENSITIVE_ALT_NAME;
    final String i = ComplexFieldUtil.INSENSITIVE_ALT_NAME;
    final String ci = ComplexFieldUtil.CASE_INSENSITIVE_ALT_NAME;
    final String di = ComplexFieldUtil.DIACRITICS_INSENSITIVE_ALT_NAME;

    ComplexFieldDesc cfd = searcher.getIndexStructure().getComplexFieldDesc(fieldName);
    if (cfd == null) return null;

    // Find the property
    PropertyDesc pd = cfd.getPropertyDesc(propName);
    SensitivitySetting sensitivity = pd.getSensitivity();
    //		Collection<String> availableAlternatives = Collections.emptyList();
    //		if (pd != null) {
    //			availableAlternatives = pd.getAlternatives();
    //		}

    // New alternative naming scheme (every alternative has a name)
    List<String> validAlternatives = new ArrayList<>();
    if (!caseSensitive && !diacriticsSensitive) {
      // search insensitive if available
      if (sensitivity != SensitivitySetting.ONLY_SENSITIVE) validAlternatives.add(i);
      if (sensitivity != SensitivitySetting.ONLY_INSENSITIVE) validAlternatives.add(s);
    } else if (caseSensitive && diacriticsSensitive) {
      // search fully-sensitive if available
      if (sensitivity != SensitivitySetting.ONLY_INSENSITIVE) validAlternatives.add(s);
      if (sensitivity != SensitivitySetting.ONLY_SENSITIVE) validAlternatives.add(i);
    } else if (!diacriticsSensitive) {
      // search case-sensitive if available
      if (sensitivity == SensitivitySetting.CASE_AND_DIACRITICS_SEPARATE) validAlternatives.add(di);
      if (sensitivity != SensitivitySetting.ONLY_INSENSITIVE) validAlternatives.add(s);
      if (sensitivity != SensitivitySetting.ONLY_SENSITIVE) validAlternatives.add(i);
    } else {
      // search diacritics-sensitive if available
      if (sensitivity == SensitivitySetting.CASE_AND_DIACRITICS_SEPARATE) validAlternatives.add(ci);
      if (sensitivity != SensitivitySetting.ONLY_SENSITIVE) validAlternatives.add(i);
      if (sensitivity != SensitivitySetting.ONLY_INSENSITIVE) validAlternatives.add(s);
    }
    return validAlternatives.toArray(new String[] {});
  }
 public boolean tagLengthInPayload() {
   return searcher.getIndexStructure().tagLengthInPayload();
 }
 public boolean alwaysHasClosingToken() {
   return searcher.getIndexStructure().alwaysHasClosingToken();
 }