diff options
Diffstat (limited to 'main/src/cgeo')
| -rw-r--r-- | main/src/cgeo/geocaching/connector/gc/GCBase.java | 179 |
1 files changed, 144 insertions, 35 deletions
diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java index 439ff7a..b037366 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCBase.java +++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java @@ -1,4 +1,4 @@ -package cgeo.geocaching.connector; +package cgeo.geocaching.connector.gc; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; @@ -19,14 +19,23 @@ import org.json.JSONObject; import android.util.Log; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** + * GC.com/Groundspeak (GS) specific stuff * * @author blafoo * */ -public class GCConnectorImpl { +public class GCBase { + + protected final static String SEQUENCE_GCID = "0123456789ABCDEFGHJKMNPQRTVWXYZ"; + protected final static String SEQUENCE_NEWID = "tHpXJR8gyfzCrdV5G0Kb3Y92N47lTBPAhWnvLZkaexmSwq6sojDcEQMFO"; + protected final static long GC_BASE57 = 57; + protected final static long GC_BASE31 = 31; + protected final static long GC_BASE16 = 16; // TODO Valentine remove before merge /** go online or use mocked data ? */ @@ -60,11 +69,11 @@ public class GCConnectorImpl { "55_54\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"17_25\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"55_53\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"17_27\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"17_26\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"57_53\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"57_55\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"3_62\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"3_61\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"57_54\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"3_60\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"15_27\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"15_26\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"15_25\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"4_60\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"4_61\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"4_62\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"16_25\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"16_26\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"16_27\":[{\"i\":\"Rkzt\",\"n\":\"EDSSW: Rathaus \"}],\"2_62\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"2_60\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"2_61\":[{\"i\":\"gOWz\",\"n\":\"Baumarktserie - Wer Wo Was -\"}],\"56_53\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"56_54\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}],\"56_55\":[{\"i\":\"gEaR\",\"n\":\"Spiel & Sport\"}]}}"; } if (StringUtils.isBlank(page)) { - Log.e(Settings.tag, "GCConnectImpl.searchByViewport: No data from server for tile (" + tile.left + "/" + tile.right + ")"); + Log.e(Settings.tag, "GCBase.searchByViewport: No data from server for tile (" + tile.left + "/" + tile.right + ")"); } final SearchResult search = parseMapJSON(url, page); if (search == null || CollectionUtils.isEmpty(search.getGeocodes())) { - Log.e(Settings.tag, "GCConnectImpl.searchByViewport: No cache parsed for viewport " + viewport); + Log.e(Settings.tag, "GCBase.searchByViewport: No cache parsed for viewport " + viewport); } searchResult.addGeocodes(search.getGeocodes()); } @@ -112,49 +121,65 @@ public class GCConnectorImpl { throw new JSONException("No data inside JSON"); } + // attach all keys with the cache positions in the tile + Map<String, ImmutablePair<Integer, Integer>> keyPositions = new HashMap<String, ImmutablePair<Integer, Integer>>(); // JSON key, (x/y) in grid for (int y = 0; y < grid.length(); y++) { byte[] row = grid.getString(y).getBytes(); for (int x = 0; x < row.length; x++) { - byte id = getUTFGridId(row[x]); - if (id > 0) { - Log.d(Settings.tag, "(" + x + "/" + y + ") =" + String.valueOf(id)); + if (row[x] != 32) { + byte id = UTFGrid.getUTFGridId(row[x]); + keyPositions.put(keys.getString(id), new ImmutablePair<Integer, Integer>(x, y)); } } } - //Map<String, Integer> keyIds = new HashMap<String, Integer>(); // key (55_55), index - //Map<String, cgCache> caches = new HashMap<String, cgCache>(); // name, cache - //Map<String, List<String>> positions = new HashMap<String, List<String>>(); // name, keys - + // iterate over the data and construct all caches in this tile + Map<String, cgCache> caches = new HashMap<String, cgCache>(); // JSON id, cache + Map<String, List<ImmutablePair<Integer, Integer>>> positions = new HashMap<String, List<ImmutablePair<Integer, Integer>>>(); // JSON id as key for (int i = 0; i < keys.length(); i++) { String key = keys.getString(i); - Log.d(Settings.tag, "Key #" + i + "=" + key); if (StringUtils.isNotBlank(key)) { JSONArray dataForKey = dataObject.getJSONArray(key); for (int j = 0; j < dataForKey.length(); j++) { JSONObject cacheInfo = dataForKey.getJSONObject(j); - // TODO Valentine How to convert to a geocode ? Or is an extra request needed ? String id = cacheInfo.getString("i"); - String name = cacheInfo.getString("n"); - - final cgCache cacheToAdd = new cgCache(); - cacheToAdd.setDetailed(false); - cacheToAdd.setReliableLatLon(false); - cacheToAdd.setGeocode(id); - cacheToAdd.setCoords(getCoordsForUTFGrid(key)); - cacheToAdd.setName(name); - cacheToAdd.setType(CacheType.GC_LIVE_MAP); + cgCache cache = caches.get(id); + if (cache == null) { + cache = new cgCache(); + cache.setDetailed(false); + cache.setReliableLatLon(false); + cache.setGeocode(newidToGeocode(id)); + cache.setName(cacheInfo.getString("n")); + cache.setType(CacheType.GC_LIVE_MAP); - Log.d(Settings.tag, "key=" + key + " id=" + id + " name=" + name); + caches.put(id, cache); + } - //caches.put(id, cacheToAdd); - searchResult.addCache(cacheToAdd); + List<ImmutablePair<Integer, Integer>> pos = positions.get(id); + if (pos == null) { + pos = new ArrayList<ImmutablePair<Integer, Integer>>(); + } + pos.add(keyPositions.get(key)); + positions.put(id, pos); } } } + for (String id : positions.keySet()) { + List<ImmutablePair<Integer, Integer>> pos = positions.get(id); + cgCache cache = caches.get(id); + cache.setCoords(getCoordsForUTFGrid(pos)); + + Log.d(Settings.tag, "id= " + id + " geocode= " + cache.getGeocode()); + for (ImmutablePair<Integer, Integer> ImmutablePair : pos) { + Log.d(Settings.tag, "(" + ImmutablePair.left + "," + ImmutablePair.right + ")"); + } + + searchResult.addCache(cache); + } + } catch (Exception e) { - Log.e(Settings.tag, "cgBase.parseMapJSON", e); + Log.e(Settings.tag, "GCBase.parseMapJSON", e); } return searchResult; @@ -175,21 +200,105 @@ public class GCConnectorImpl { } - protected static Geopoint getCoordsForUTFGrid(String key) { + /** Calculate from a list of positions (x/y) the coords */ + protected static Geopoint getCoordsForUTFGrid(List<ImmutablePair<Integer, Integer>> positions) { // TODO Valentine Calculate coords return new Geopoint("N 52° 24,516 E 009° 42,592"); } - /** @see https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md */ - protected static byte getUTFGridId(final byte value) { - byte result = value; - if (result >= 93) { - result--; + /** + * Convert GCCode (geocode) to (old) GCIds + * + * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 + * see http://support.groundspeak.com/index.php?pg=kb.printer.friendly&id=1#p221 + */ + public static long gccodeToGCId(final String gccode) { + long gcid = 0; + long base = GC_BASE31; + String geocodeWO = gccode.substring(2).toUpperCase(); + + if ((geocodeWO.length() < 4) || (geocodeWO.length() == 4 && SEQUENCE_GCID.indexOf(geocodeWO.charAt(0)) < 16)) { + base = GC_BASE16; + } + + for (int p = 0; p < geocodeWO.length(); p++) { + gcid = base * gcid + SEQUENCE_GCID.indexOf(geocodeWO.charAt(p)); + } + + if (base == GC_BASE31) { + gcid += Math.pow(16, 4) - 16 * Math.pow(31, 3); + } + return gcid; + } + + private static String modulo(final long value, final long base, final String sequence) { + String result = ""; + long rest = 0; + long divResult = value; + do + { + rest = divResult % base; + divResult = (int) Math.floor(divResult / base); + result = sequence.charAt((int) rest) + result; + } while (divResult != 0); + return result; + } + + /** + * Convert (old) GCIds to GCCode (geocode) + * + * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 + */ + public static String gcidToGCCode(final long gcid) { + String gccode = modulo(gcid + 411120, GC_BASE31, SEQUENCE_GCID); + if ((gccode.length() < 4) || (gccode.length() == 4 && SEQUENCE_GCID.indexOf(gccode.charAt(0)) < 16)) { + gccode = modulo(gcid, GC_BASE16, SEQUENCE_GCID); } - if (result >= 35) { - result--; + return "GC" + gccode; + } + + /** + * Convert ids from the live map to (old) GCIds + * + * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 + */ + public static long newidToGCId(final String newid) { + long gcid = 0; + for (int p = 0; p < newid.length(); p++) { + gcid = GC_BASE57 * gcid + SEQUENCE_NEWID.indexOf(newid.charAt(p)); } - return (byte) (result - 32); + return gcid; + } + + /** + * Convert (old) GCIds to ids used in the live map + * + * Based on http://www.geoclub.de/viewtopic.php?f=111&t=54859&start=40 + */ + public static String gcidToNewId(final long gcid) { + return modulo(gcid, GC_BASE57, SEQUENCE_NEWID); + } + + /** + * Convert ids from the live map into GCCode (geocode) + */ + public static String newidToGeocode(final String newid) { + long gcid = GCBase.newidToGCId(newid); + return GCBase.gcidToGCCode(gcid); + } + + /** Request further details in the live mapa for a given id */ + public void requestDetailsFromMap(@SuppressWarnings("unused") String id) { + /** + * URL http://www.geocaching.com/map/map.details?i=gEaR + * Response: {"status":"success","data":[{"name":"Spiel & Sport","gc":"GC211WG","g": + * "872d7eda-7cb9-40d5-890d-5b344bce7302" + * ,"disabled":false,"subrOnly":false,"li":false,"fp":"0","difficulty":{"text" + * :3.0,"value":"3"},"terrain":{"text" + * :2.0,"value":"2"},"hidden":"11/15/2009","container":{"text":"Regular","value" + * :"regular.gif"},"type":{"text":"Multi-cache" + * ,"value":3},"owner":{"text":"kai2707","value":"5c4b0915-5cec-4fa1-8afd-4b3ca67e004e"}}]} + */ } } |
