public FilteredQuery CreateFilteredQuery(ILuceneQueryService builder, LuceneQueryContext context, string type, JToken filter, Query toFilter)
        {
            if (type != "geo_distance")
            {
                return(null);
            }

            if (!(toFilter is BooleanQuery booleanQuery))
            {
                return(null);
            }

            var queryObj = filter as JObject;

            if (queryObj.Properties().Count() != 2)
            {
                return(null);
            }

            var ctx = SpatialContext.GEO;

            var maxLevels = 11; //results in sub-meter precision for geohash

            //  This can also be constructed from SpatialPrefixTreeFactory
            SpatialPrefixTree grid = new GeohashPrefixTree(ctx, maxLevels);

            JProperty distanceProperty = null;
            JProperty geoProperty      = null;

            foreach (var jProperty in queryObj.Properties())
            {
                if (jProperty.Name.Equals("distance", StringComparison.Ordinal))
                {
                    distanceProperty = jProperty;
                }
                else
                {
                    geoProperty = jProperty;
                }
            }

            if (distanceProperty == null || geoProperty == null)
            {
                return(null);
            }

            var strategy = new RecursivePrefixTreeStrategy(grid, geoProperty.Name);

            if (!TryParseDistance((string)distanceProperty.Value, out var distanceDegrees))
            {
                return(null);
            }

            if (!TryGetPointFromJToken(geoProperty.Value, out var point))
            {
                return(null);
            }

            var circle = ctx.MakeCircle(point.X, point.Y, distanceDegrees);

            var args = new SpatialArgs(SpatialOperation.Intersects, circle);

            var spatialQuery      = strategy.MakeQuery(args);
            var valueSource       = strategy.MakeRecipDistanceValueSource(circle);
            var valueSourceFilter = new ValueSourceFilter(new QueryWrapperFilter(spatialQuery), valueSource, 0, 1);

            booleanQuery.Add(new FunctionQuery(valueSource), Occur.MUST);

            return(new FilteredQuery(booleanQuery, valueSourceFilter));
        }
        //TODO this is basically old code that hasn't been verified well and should probably be removed
        public Query MakeQueryDistanceScore(SpatialArgs args)
        {
            // For starters, just limit the bbox
            var shape = args.Shape;

            if (!(shape is Rectangle || shape is Circle))
            {
                throw new InvalidOperationException("Only Rectangles and Circles are currently supported, found ["
                                                    + shape.GetType().Name + "]");//TODO
            }
            Rectangle bbox = shape.GetBoundingBox();

            if (bbox.GetCrossesDateLine())
            {
                throw new InvalidOperationException("Crossing dateline not yet supported");
            }

            ValueSource valueSource = null;

            Query            spatial = null;
            SpatialOperation op      = args.Operation;

            if (SpatialOperation.Is(op,
                                    SpatialOperation.BBoxWithin,
                                    SpatialOperation.BBoxIntersects))
            {
                spatial = MakeWithin(bbox);
            }
            else if (SpatialOperation.Is(op,
                                         SpatialOperation.Intersects,
                                         SpatialOperation.IsWithin))
            {
                spatial = MakeWithin(bbox);
                var circle = args.Shape as Circle;
                if (circle != null)
                {
                    // Make the ValueSource
                    valueSource = MakeDistanceValueSource(shape.GetCenter());

                    var vsf = new ValueSourceFilter(
                        new QueryWrapperFilter(spatial), valueSource, 0, circle.GetRadius());

                    spatial = new FilteredQuery(new MatchAllDocsQuery(), vsf);
                }
            }
            else if (op == SpatialOperation.IsDisjointTo)
            {
                spatial = MakeDisjoint(bbox);
            }

            if (spatial == null)
            {
                throw new UnsupportedSpatialOperation(args.Operation);
            }

            if (valueSource != null)
            {
                valueSource = new CachingDoubleValueSource(valueSource);
            }
            else
            {
                valueSource = MakeDistanceValueSource(shape.GetCenter());
            }
            Query spatialRankingQuery = new FunctionQuery(valueSource);
            var   bq = new BooleanQuery();

            bq.Add(spatial, Occur.MUST);
            bq.Add(spatialRankingQuery, Occur.MUST);
            return(bq);
        }