/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Text; using Spatial4n.Core.Context; using Spatial4n.Core.Io; using Spatial4n.Core.Shapes; namespace Lucene.Net.Spatial.Queries { public class SpatialArgsParser { public const String DIST_ERR_PCT = "distErrPct"; public const String DIST_ERR = "distErr"; /// /// Writes a close approximation to the parsed input format. /// /// /// public static String WriteSpatialArgs(SpatialArgs args) { var str = new StringBuilder(); str.Append(args.Operation.GetName()); str.Append('('); str.Append(args.Shape); if (args.DistErrPct != null) str.Append(" distErrPct=").Append(String.Format("{0:0.00}%", args.DistErrPct*100d)); if (args.DistErr != null) str.Append(" distErr=").Append(args.DistErr); str.Append(')'); return str.ToString(); } /// /// Parses a string such as "Intersects(-10,20,-8,22) distErrPct=0.025". /// /// /// /// public SpatialArgs Parse(String v, SpatialContext ctx) { int idx = v.IndexOf('('); int edx = v.LastIndexOf(')'); if (idx < 0 || idx > edx) { throw new ArgumentException("missing parens: " + v); } SpatialOperation op = SpatialOperation.Get(v.Substring(0, idx).Trim()); //Substring in .NET is (startPosn, length), But in Java it's (startPosn, endPosn) //see http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#substring(int, int) String body = v.Substring(idx + 1, edx - (idx + 1)).Trim(); if (body.Length < 1) { throw new ArgumentException("missing body : " + v); } var shape = ctx.ReadShape(body); var args = new SpatialArgs(op, shape); if (v.Length > (edx + 1)) { body = v.Substring(edx + 1).Trim(); if (body.Length > 0) { Dictionary aa = ParseMap(body); args.DistErrPct = ReadDouble(aa["distErrPct"]); aa.Remove(DIST_ERR_PCT); args.DistErr = ReadDouble(aa["distErr"]); aa.Remove(DIST_ERR); if (aa.Count != 0) { throw new ArgumentException("unused parameters: " + aa); } } } args.Validate(); return args; } protected static double? ReadDouble(String v) { double val; return double.TryParse(v, out val) ? val : (double?)null; } protected static bool ReadBool(String v, bool defaultValue) { bool ret; return bool.TryParse(v, out ret) ? ret : defaultValue; } /// /// Parses "a=b c=d f" (whitespace separated) into name-value pairs. If there /// is no '=' as in 'f' above then it's short for f=f. /// /// /// protected static Dictionary ParseMap(String body) { var map = new Dictionary(); int tokenPos = 0; var st = body.Split(new[] {' ', '\n', '\t'}, StringSplitOptions.RemoveEmptyEntries); while (tokenPos < st.Length) { String a = st[tokenPos++]; int idx = a.IndexOf('='); if (idx > 0) { String k = a.Substring(0, idx); String v = a.Substring(idx + 1); map[k] = v; } else { map[a] = a; } } return map; } } }