// Path: src/main/java/com/indoqa/solr/spatial/corridor/LineStringUtils.java
// public final class LineStringUtils {
// 
//     static {
//         cache = Caffeine.newBuilder()
//                 .maximumSize(100000)
//                 .expireAfterAccess(24, TimeUnit.HOURS)
//                 .build();
//     }
// 
//     private static Cache<String, LineString> cache;
// 
//     public static LineString parseOrGet(String value, String hash)  {
//         if (value == null) {
//             return null;
//         }
// 
//         if (hash != null) {
//             LineString cached = cache.getIfPresent(hash);
// 
//             if (cached != null) {
//                 return cached;
//             }
//         }
// 
//         String key = calculateHash(value);
//         return cache.get(key, s -> parseWktLinestring(value));
//     }
// 
//     public static HashGeometry cacheLineStringGetHashGeometry(String linestring, int radiusInMeters){
//         if(linestring == null){
//             return null;
//         }
//         String key = calculateHash(linestring);
//         LineString parsedLineString = parseWktLinestring(linestring);
// 
//         cache.put(key, parsedLineString);
//         HashGeometry result = new HashGeometry();
//         // meters /((PI/180)x6378137)
//         result.setGeometry(parsedLineString.buffer(radiusInMeters / (Math.PI / 180 * 6378137)).toText());
//         result.setHash(key);
//         return result;
//     }
// 
//     public static void purgeCache() {
//         cache.invalidateAll();
//         cache.cleanUp();
//     }
// 
//     private static LineString parseWktLinestring(String corridorLineString) {
//         return WktUtils.parseLineString(corridorLineString);
//     }
// 
//     private static String calculateHash(String linestring) {
//         if (linestring == null) {
//             return null;
//         }
// 
//         StringBuilder result = new StringBuilder("hash-");
//         result.append(Hex.encodeHex(DigestUtils.md5(linestring)));
//         return result.toString();
//     }
// }
// 
// Path: src/main/java/com/indoqa/solr/spatial/corridor/debug/DebugValues.java
// public interface DebugValues {
// 
//     void add(String key, String value);
//     void add(String key, boolean value);
//     void add(String key, Number value);
// 
//     void addAngleDifference(String key, String value);
//     void addAngleDifference(String key, Number value);
//     void addAngleDifference(String key, Coordinate coordinate);
// 
//     void addSingleAngleDifference(String key, Number value);
// 
//     String toJson();
// }
// 
// Path: src/main/java/com/indoqa/solr/spatial/corridor/debug/NoOpDebugValues.java
// public class NoOpDebugValues implements DebugValues {
// 
//     public static NoOpDebugValues NOOP_DEBUG_VALUES = new NoOpDebugValues();
// 
//     private NoOpDebugValues() {
//         super();
//     }
// 
//     @Override
//     public void add(String key, String value) {
// 
//     }
// 
//     @Override
//     public void add(String key, boolean value) {
// 
//     }
// 
//     @Override
//     public void add(String key, Number value) {
// 
//     }
// 
//     @Override
//     public void addAngleDifference(String key, String value) {
// 
//     }
// 
//     @Override
//     public void addAngleDifference(String key, Number value) {
// 
//     }
// 
//     @Override
//     public void addAngleDifference(String key, Coordinate coordinate) {
// 
//     }
// 
//     @Override
//     public void addSingleAngleDifference(String distance, Number distance1) {
// 
//     }
// 
//     @Override
//     public String toJson() {
//         return null;
//     }
// }


import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.linearref.LinearLocation;
import org.locationtech.jts.linearref.LocationIndexedLine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.indoqa.solr.spatial.corridor.LineStringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import com.indoqa.solr.spatial.corridor.debug.DebugValues;
import com.indoqa.solr.spatial.corridor.debug.NoOpDebugValues;
import org.locationtech.jts.geom.Coordinate;

    protected final class InverseCorridorDocValues extends DoubleDocValues {

        private FunctionValues routeValues;
        private FunctionValues hashValues;
        private DebugValues debugValues;

        protected InverseCorridorDocValues(ValueSource vs, FunctionValues routeValues, FunctionValues hashValues) {
            this(vs, routeValues, hashValues, NoOpDebugValues.NOOP_DEBUG_VALUES);
        }
        protected InverseCorridorDocValues(ValueSource vs, FunctionValues routeValues, FunctionValues hashValues,
            DebugValues debugValues) {
            super(vs);

            this.routeValues = routeValues;
            this.hashValues = hashValues;
            this.debugValues = debugValues;
        }

        @Override
        public double doubleVal(int docId) throws IOException {
            String routeAsString = this.routeValues.strVal(docId);
            String routeAsHash = this.hashValues.strVal(docId);

            try {
                if (routeAsString == null || routeAsString.isEmpty()) {
                    this.debugValues.add("routeAsString", "empty");
                    return -1;
                }

// Path: src/main/java/com/indoqa/solr/spatial/corridor/LineStringUtils.java
// public final class LineStringUtils {
// 
//     static {
//         cache = Caffeine.newBuilder()
//                 .maximumSize(100000)
//                 .expireAfterAccess(24, TimeUnit.HOURS)
//                 .build();
//     }
// 
//     private static Cache<String, LineString> cache;
// 
//     public static LineString parseOrGet(String value, String hash)  {
//         if (value == null) {
//             return null;
//         }
// 
//         if (hash != null) {
//             LineString cached = cache.getIfPresent(hash);
// 
//             if (cached != null) {
//                 return cached;
//             }
//         }
// 
//         String key = calculateHash(value);
//         return cache.get(key, s -> parseWktLinestring(value));
//     }
// 
//     public static HashGeometry cacheLineStringGetHashGeometry(String linestring, int radiusInMeters){
//         if(linestring == null){
//             return null;
//         }
//         String key = calculateHash(linestring);
//         LineString parsedLineString = parseWktLinestring(linestring);
// 
//         cache.put(key, parsedLineString);
//         HashGeometry result = new HashGeometry();
//         // meters /((PI/180)x6378137)
//         result.setGeometry(parsedLineString.buffer(radiusInMeters / (Math.PI / 180 * 6378137)).toText());
//         result.setHash(key);
//         return result;
//     }
// 
//     public static void purgeCache() {
//         cache.invalidateAll();
//         cache.cleanUp();
//     }
// 
//     private static LineString parseWktLinestring(String corridorLineString) {
//         return WktUtils.parseLineString(corridorLineString);
//     }
// 
//     private static String calculateHash(String linestring) {
//         if (linestring == null) {
//             return null;
//         }
// 
//         StringBuilder result = new StringBuilder("hash-");
//         result.append(Hex.encodeHex(DigestUtils.md5(linestring)));
//         return result.toString();
//     }
// }
// 
// Path: src/main/java/com/indoqa/solr/spatial/corridor/debug/DebugValues.java
// public interface DebugValues {
// 
//     void add(String key, String value);
//     void add(String key, boolean value);
//     void add(String key, Number value);
// 
//     void addAngleDifference(String key, String value);
//     void addAngleDifference(String key, Number value);
//     void addAngleDifference(String key, Coordinate coordinate);
// 
//     void addSingleAngleDifference(String key, Number value);
// 
//     String toJson();
// }
// 
// Path: src/main/java/com/indoqa/solr/spatial/corridor/debug/NoOpDebugValues.java
// public class NoOpDebugValues implements DebugValues {
// 
//     public static NoOpDebugValues NOOP_DEBUG_VALUES = new NoOpDebugValues();
// 
//     private NoOpDebugValues() {
//         super();
//     }
// 
//     @Override
//     public void add(String key, String value) {
// 
//     }
// 
//     @Override
//     public void add(String key, boolean value) {
// 
//     }
// 
//     @Override
//     public void add(String key, Number value) {
// 
//     }
// 
//     @Override
//     public void addAngleDifference(String key, String value) {
// 
//     }
// 
//     @Override
//     public void addAngleDifference(String key, Number value) {
// 
//     }
// 
//     @Override
//     public void addAngleDifference(String key, Coordinate coordinate) {
// 
//     }
// 
//     @Override
//     public void addSingleAngleDifference(String distance, Number distance1) {
// 
//     }
// 
//     @Override
//     public String toJson() {
//         return null;
//     }
// }


// Path: src/main/java/com/indoqa/solr/spatial/corridor/direction/DirectionValueSource.java
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.linearref.LinearLocation;
import org.locationtech.jts.linearref.LocationIndexedLine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import com.indoqa.solr.spatial.corridor.LineStringUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import com.indoqa.solr.spatial.corridor.debug.DebugValues;
import com.indoqa.solr.spatial.corridor.debug.NoOpDebugValues;
import org.locationtech.jts.geom.Coordinate;


    protected final class InverseCorridorDocValues extends DoubleDocValues {

        private FunctionValues routeValues;
        private FunctionValues hashValues;
        private DebugValues debugValues;

        protected InverseCorridorDocValues(ValueSource vs, FunctionValues routeValues, FunctionValues hashValues) {
            this(vs, routeValues, hashValues, NoOpDebugValues.NOOP_DEBUG_VALUES);
        }
        protected InverseCorridorDocValues(ValueSource vs, FunctionValues routeValues, FunctionValues hashValues,
            DebugValues debugValues) {
            super(vs);

            this.routeValues = routeValues;
            this.hashValues = hashValues;
            this.debugValues = debugValues;
        }

        @Override
        public double doubleVal(int docId) throws IOException {
            String routeAsString = this.routeValues.strVal(docId);
            String routeAsHash = this.hashValues.strVal(docId);

            try {
                if (routeAsString == null || routeAsString.isEmpty()) {
                    this.debugValues.add("routeAsString", "empty");
                    return -1;
                }

                LineString route = LineStringUtils.parseOrGet(routeAsString, routeAsHash);