/*
 *  Licensed to GraphHopper and Peter Karich under one or more contributor
 *  license agreements. See the NOTICE file distributed with this work for 
 *  additional information regarding copyright ownership.
 * 
 *  GraphHopper 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.
 */
package com.graphhopper.http;

import com.graphhopper.GraphHopper;
import com.graphhopper.routing.util.EdgeFilter;
import com.graphhopper.storage.index.LocationIndex;
import com.graphhopper.storage.index.QueryResult;
import com.graphhopper.util.DistanceCalcEarth;
import com.graphhopper.util.shapes.GHPoint;
import com.graphhopper.util.shapes.GHPoint3D;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import org.json.JSONArray;
import org.json.JSONObject;

/**
 * @author svantulden
 */
public class NearestServlet extends GHBaseServlet
{
    @Inject
    private GraphHopper hopper;

    @Override
    public void doGet( HttpServletRequest req, HttpServletResponse res ) throws ServletException, IOException
    {
        try
        {
            writeNearest(req, res);
        } catch (IllegalArgumentException ex)
        {
            writeError(res, SC_BAD_REQUEST, ex.getMessage());
        } catch (Exception ex)
        {
            logger.error("Error while executing request: " + req.getQueryString(), ex);
            writeError(res, SC_INTERNAL_SERVER_ERROR, "Problem occured:" + ex.getMessage());
        }
    }

    void writeNearest( HttpServletRequest req, HttpServletResponse res ) throws Exception
    {
        String pointStr = getParam(req, "point", null);
        boolean enableElevation = getBooleanParam(req, "elevation", false);
        
        JSONObject result = new JSONObject();
        if (pointStr != null && !pointStr.equalsIgnoreCase("")) {
            GHPoint place = GHPoint.parse(pointStr);
            
            LocationIndex index = hopper.getLocationIndex();
            QueryResult qr = index.findClosest( place.lat, place.lon, EdgeFilter.ALL_EDGES );
            
            GHPoint3D snappedPoint = null;
            try {
                snappedPoint = qr.getSnappedPoint();
            } catch (IllegalStateException ex) {
                result.put("error", "Nearest point cannot be found!");
            }
            
            if (snappedPoint != null) {
                result.put("type", "Point");
                
                JSONArray coord = new JSONArray();
                coord.put(snappedPoint.lon);
                coord.put(snappedPoint.lat);
                
                if (hopper.hasElevation() && enableElevation) {
                    coord.put(snappedPoint.ele);
                }

                result.put("coordinates", coord);
                
                DistanceCalcEarth calc = new DistanceCalcEarth();
                double distance = calc.calcDist(place.lat, place.lon, snappedPoint.lat, snappedPoint.lon);
                
                // Distance from input to snapped point in meters
                result.put("distance", distance);
            }
        } else {
            result.put("error", "No lat/lon specified!");
        }  
        
        writeJson(req, res, result);
    }
}

@@ -1068,21 +1068,52 @@
 anceCalc
-Earth
+;%0Aimport com.graphhopper.util.Helper
 ;%0Aimport
@@ -1713,16 +1713,73 @@
  hopper;
+%0A    private final DistanceCalc calc = Helper.DIST_EARTH;
 %0A%0A    @O
@@ -2487,24 +2487,25 @@
 olean enable
+d
 Elevation = 
@@ -2546,24 +2546,16 @@
 false);%0A
-        
 %0A       
@@ -2656,16 +2656,24 @@
 ase(%22%22))
+%0A       
  %7B%0A     
@@ -2720,29 +2720,16 @@
 ntStr);%0A
-            %0A
         
@@ -2828,17 +2828,16 @@
 Closest(
- 
 place.la
@@ -2874,24 +2874,11 @@
 DGES
- 
 );%0A
-            
 %0A   
@@ -2890,109 +2890,26 @@
     
-GHPoint3D snappedPoint = null;%0A            try %7B%0A                snappedPoint = qr.getSnappedPoint();
+if (!qr.isValid())
 %0A   
@@ -2920,43 +2920,8 @@
     
- %7D catch (IllegalStateException ex)
  %7B%0A 
@@ -2995,32 +2995,37 @@
 );%0A            %7D
+ else
 %0A            %0A  
@@ -3013,32 +3013,33 @@
 lse%0A            
+%7B
 %0A            if 
@@ -3035,20 +3035,30 @@
         
-if (
+    GHPoint3D 
 snappedP
@@ -3066,18 +3066,31 @@
 int 
-!
 = 
-null) %7B
+qr.getSnappedPoint();
 %0A   
@@ -3131,32 +3131,16 @@
 oint%22);%0A
-                
 %0A       
@@ -3273,32 +3273,16 @@
 t.lat);%0A
-                
 %0A       
@@ -3325,16 +3325,17 @@
 & enable
+d
 Elevatio
@@ -3336,18 +3336,16 @@
 evation)
- %7B
 %0A       
@@ -3389,26 +3389,8 @@
 le);
-%0A                %7D
 %0A%0A  
@@ -3437,32 +3437,16 @@
 coord);%0A
-                
 %0A       
@@ -3453,16 +3453,19 @@
         
+ //
  Distanc
@@ -3469,49 +3469,46 @@
 ance
-CalcEarth calc = new DistanceCalcEarth();
+ from input to snapped point in meters
 %0A   
@@ -3524,23 +3524,28 @@
     
-double 
+result.put(%22
 distance
  = c
@@ -3540,18 +3540,18 @@
 distance
- =
+%22,
  calc.ca
@@ -3606,32 +3606,33 @@
 nappedPoint.lon)
+)
 ;%0A              
@@ -3625,28 +3625,25 @@
             
-    
+%7D
 %0A           
@@ -3643,144 +3643,22 @@
     
+%7D else%0A
        
- // Distance from input to snapped point in meters%0A                result.put(%22distance%22, distance);%0A            %7D%0A        %7D else
  %7B%0A 
@@ -3723,27 +3723,17 @@
        %7D
-  %0A        
+%0A
 %0A       

make QueryResult check more clear