Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
36622 ranu 1
package com.spice.profitmandi.service;
2
 
3
import com.fasterxml.jackson.databind.JsonNode;
4
import com.fasterxml.jackson.databind.ObjectMapper;
5
import org.apache.logging.log4j.LogManager;
6
import org.apache.logging.log4j.Logger;
7
import org.springframework.cache.annotation.Cacheable;
8
import org.springframework.stereotype.Service;
9
 
10
import java.io.BufferedReader;
11
import java.io.InputStreamReader;
12
import java.net.HttpURLConnection;
13
import java.net.URL;
14
import java.net.URLEncoder;
15
import java.nio.charset.StandardCharsets;
16
 
17
@Service
18
public class GeocodingService {
19
 
20
	private static final Logger LOGGER = LogManager.getLogger(GeocodingService.class);
21
	private static final String GOOGLE_GEOCODE_URL = "https://maps.googleapis.com/maps/api/geocode/json";
22
	private static final String API_KEY = "AIzaSyAckO0y4Z6WhBOuMjNjioWLSYZDhGEvGBc";
23
 
24
	private final ObjectMapper objectMapper = new ObjectMapper();
25
 
26
	/**
27
	 * Build a clean geocoding query from address parts.
28
	 * Only includes: line1, city, state, pincode — no phone, no landmark prefix, no shop numbers.
29
	 */
30
	public static String buildGeoAddress(String line1, String city, String state, String pinCode) {
31
		StringBuilder sb = new StringBuilder();
32
		if (city != null && !city.isEmpty()) sb.append(city).append(", ");
33
		if (state != null && !state.isEmpty()) sb.append(state).append(", ");
34
		if (pinCode != null && !pinCode.isEmpty()) sb.append(pinCode).append(", ");
35
		sb.append("India");
36
		return sb.toString().trim();
37
	}
38
 
39
	/**
40
	 * Geocode an address string to [latitude, longitude].
41
	 * Cached in Redis forever to avoid repeated API calls.
42
	 * Returns null if geocoding fails.
43
	 */
44
	@Cacheable(value = "partnerGeocode", key = "#address", cacheManager = "redisEternalCacheManager")
45
	public double[] geocodeAddress(String address) {
46
		if (address == null || address.trim().isEmpty()) {
47
			return null;
48
		}
49
		try {
50
			String cleanAddress = sanitizeForGeocoding(address);
51
			String encodedAddress = URLEncoder.encode(cleanAddress, StandardCharsets.UTF_8.toString());
52
			String urlStr = GOOGLE_GEOCODE_URL + "?address=" + encodedAddress
53
					+ "&key=" + API_KEY + "&components=country:IN";
54
 
55
			URL url = new URL(urlStr);
56
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
57
			conn.setRequestMethod("GET");
58
			conn.setConnectTimeout(5000);
59
			conn.setReadTimeout(5000);
60
 
61
			int responseCode = conn.getResponseCode();
62
			if (responseCode != 200) {
63
				LOGGER.warn("Geocoding HTTP error for '{}': {}", address, responseCode);
64
				return null;
65
			}
66
 
67
			BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
68
			StringBuilder sb = new StringBuilder();
69
			String line;
70
			while ((line = reader.readLine()) != null) {
71
				sb.append(line);
72
			}
73
			reader.close();
74
			conn.disconnect();
75
 
76
			JsonNode root = objectMapper.readTree(sb.toString());
77
			String status = root.path("status").asText();
78
 
79
			if (!"OK".equals(status)) {
80
				LOGGER.warn("Geocoding failed for '{}': status={}", address, status);
81
				return null;
82
			}
83
 
84
			JsonNode location = root.path("results").get(0).path("geometry").path("location");
85
			double lat = location.path("lat").asDouble();
86
			double lng = location.path("lng").asDouble();
87
 
88
			LOGGER.info("Geocoded '{}' -> [{}, {}]", address, lat, lng);
89
			return new double[]{lat, lng};
90
 
91
		} catch (Exception e) {
92
			LOGGER.error("Geocoding error for '{}': {}", address, e.getMessage());
93
			return null;
94
		}
95
	}
96
 
97
	/**
98
	 * Remove noise from address: phone numbers, PIN- prefix, Landmark:, Shop No. etc.
99
	 * Keep only location-relevant parts for better geocoding accuracy.
100
	 */
101
	private String sanitizeForGeocoding(String address) {
102
		String clean = address;
103
		// Remove phone numbers (Ph: XXXXXXXXXX)
104
		clean = clean.replaceAll("(?i),?\\s*Ph:\\s*\\d+", "");
105
		// Remove PIN- prefix but keep the number
106
		clean = clean.replaceAll("(?i)PIN-", "");
107
		// Remove Landmark: prefix
108
		clean = clean.replaceAll("(?i)Landmark:\\s*", "");
109
		// Remove Shop No. / Ward No. patterns (too specific for geocoding)
110
		clean = clean.replaceAll("(?i)Shop\\s*No\\.?\\s*[\\d/]+,?\\s*", "");
111
		clean = clean.replaceAll("(?i)Ward\\s*No\\.?\\s*[\\d/]+,?\\s*", "");
112
		// Clean up double commas and trailing commas
113
		clean = clean.replaceAll(",\\s*,", ",");
114
		clean = clean.replaceAll("^[,\\s]+|[,\\s]+$", "");
115
		return clean.trim();
116
	}
117
}