diff options
| author | Bananeweizen <bananeweizen@gmx.de> | 2011-09-20 21:51:07 +0200 |
|---|---|---|
| committer | Bananeweizen <bananeweizen@gmx.de> | 2011-09-20 21:51:07 +0200 |
| commit | b3da6401d9b51c9526c821b0e0907c63f4fddc67 (patch) | |
| tree | b216bc06fdb53a789470973649487115e55ff7b2 | |
| parent | 383e20e40cb6c22d9fc124386abf3d9f83972a66 (diff) | |
| download | cgeo-b3da6401d9b51c9526c821b0e0907c63f4fddc67.zip cgeo-b3da6401d9b51c9526c821b0e0907c63f4fddc67.tar.gz cgeo-b3da6401d9b51c9526c821b0e0907c63f4fddc67.tar.bz2 | |
initial support of OpenCaching.DE/.PL/.US
* search for geocode can fetch online from those sites (but no other
search method!) when testing, search for codes like OU0001, OP0001,
OC0001.
* show CC license for those caches
* disable user actions, disable caches around for non GC caches
open issues:
* other search methods not yet implemented (but available in API)
* CC license and mentioning of the OpenCaching network in about dialog
| -rw-r--r-- | main/res/layout/detail.xml | 20 | ||||
| -rw-r--r-- | main/res/values/strings.xml | 2 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgBase.java | 67 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgCache.java | 8 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgHtmlImg.java | 5 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/cgeodetail.java | 23 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/AbstractConnector.java | 25 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ConnectorFactory.java | 23 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/GCConnector.java | 100 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/IConnector.java | 65 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/OCConnector.java | 21 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/OXConnector.java | 12 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java | 52 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java | 260 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/opencaching/OpenCachingConnector.java | 41 |
15 files changed, 632 insertions, 92 deletions
diff --git a/main/res/layout/detail.xml b/main/res/layout/detail.xml index 2d0e773..7330875 100644 --- a/main/res/layout/detail.xml +++ b/main/res/layout/detail.xml @@ -279,6 +279,26 @@ android:orientation="vertical"> </LinearLayout> </LinearLayout> + <LinearLayout android:id="@+id/license_box" + android:visibility="gone" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" > + <RelativeLayout style="@style/separator_horizontal_layout" > + <View style="@style/separator_horizontal" /> + <TextView style="@style/separator_horizontal_headline" + android:text="@string/cache_license" /> + </RelativeLayout> + <TextView android:id="@+id/license" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_gravity="left" + android:padding="3dip" + android:textSize="14dip" + android:textColor="?text_color" + android:linksClickable="true" + android:textColorLink="?text_color_link" /> + </LinearLayout> </LinearLayout> </ScrollView> </LinearLayout>
\ No newline at end of file diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml index 73cb8cf..8207a77 100644 --- a/main/res/values/strings.xml +++ b/main/res/values/strings.xml @@ -581,6 +581,7 @@ <string name="cache_export_fieldnote">Export as Field Notes</string> <string name="cache_clear_history">Clear history</string> <string name="cache_remove_from_history">Remove from history</string> + <string name="cache_license">License</string> <!-- file list base --> <string name="file_searching_in">Searching for files\nin</string> @@ -951,6 +952,7 @@ <string name="changelog">\n <b>next version</b>\n · new: import of LOC files\n + · new: search for geo code supports OpenCaching.DE/.PL/.US\n \n\n <b>18.09.2011</b>\n · fix: Android 3+ compatibility\n diff --git a/main/src/cgeo/geocaching/cgBase.java b/main/src/cgeo/geocaching/cgBase.java index 1e9eb7a..edccd2c 100644 --- a/main/src/cgeo/geocaching/cgBase.java +++ b/main/src/cgeo/geocaching/cgBase.java @@ -1,6 +1,7 @@ package cgeo.geocaching; import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.WaypointType; @@ -2583,71 +2584,7 @@ public class cgBase { return search.getCurrentId(); } - final String host = "www.geocaching.com"; - final String path = "/seek/cache_details.aspx"; - final String method = "GET"; - final Map<String, String> params = new HashMap<String, String>(); - if (StringUtils.isNotBlank(geocode)) { - params.put("wp", geocode); - } else if (StringUtils.isNotBlank(guid)) { - params.put("guid", guid); - } - params.put("decrypt", "y"); - - String page = requestLogged(false, host, path, method, params, false, false, false); - - if (StringUtils.isEmpty(page)) { - if (app.isThere(geocode, guid, true, false)) { - if (StringUtils.isBlank(geocode) && StringUtils.isNotBlank(guid)) { - Log.i(cgSettings.tag, "Loading old cache from cache."); - - geocode = app.getGeocode(guid); - } - - final List<cgCache> cacheList = new ArrayList<cgCache>(); - cacheList.add(app.getCacheByGeocode(geocode)); - search.addGeocode(geocode); - search.error = null; - - app.addSearch(search, cacheList, false, reason); - - cacheList.clear(); - - return search.getCurrentId(); - } - - Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No data from server"); - return null; - } - - final cgCacheWrap caches = parseCache(page, reason); - if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { - if (caches != null && StringUtils.isNotBlank(caches.error)) { - search.error = caches.error; - } - if (caches != null && StringUtils.isNotBlank(caches.url)) { - search.url = caches.url; - } - - app.addSearch(search, null, true, reason); - - Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No cache parsed"); - return null; - } - - if (app == null) { - Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No application found"); - return null; - } - - List<cgCache> cacheList = processSearchResults(search, caches, 0, 0, null); - - app.addSearch(search, cacheList, true, reason); - - page = null; - cacheList.clear(); - - return search.getCurrentId(); + return ConnectorFactory.getConnector(geocode).searchByGeocode(this, geocode, guid, app, search, reason); } public UUID searchByOffline(Map<String, Object> parameters) { diff --git a/main/src/cgeo/geocaching/cgCache.java b/main/src/cgeo/geocaching/cgCache.java index 68aaf49..a9b41dc 100644 --- a/main/src/cgeo/geocaching/cgCache.java +++ b/main/src/cgeo/geocaching/cgCache.java @@ -458,4 +458,12 @@ public class cgCache implements ICache { return name; } + public boolean supportsUserActions() { + return getConnector().supportsUserActions(); + } + + public boolean supportsCachesAround() { + return getConnector().supportsCachesAround(); + } + } diff --git a/main/src/cgeo/geocaching/cgHtmlImg.java b/main/src/cgeo/geocaching/cgHtmlImg.java index 40575d2..1196598 100644 --- a/main/src/cgeo/geocaching/cgHtmlImg.java +++ b/main/src/cgeo/geocaching/cgHtmlImg.java @@ -1,5 +1,7 @@ package cgeo.geocaching; +import cgeo.geocaching.connector.ConnectorFactory; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.utils.CryptUtils; import org.apache.commons.lang3.StringUtils; @@ -175,7 +177,8 @@ public class cgHtmlImg implements Html.ImageGetter { uri = Uri.parse(url); if (uri.isAbsolute() == false) { - url = "http://www.geocaching.com" + url; + IConnector connector = ConnectorFactory.getConnector(geocode); + url = "http://" + connector.getHost() + url; } } catch (Exception e) { Log.e(cgSettings.tag, "cgHtmlImg.getDrawable (parse URL): " + e.toString()); diff --git a/main/src/cgeo/geocaching/cgeodetail.java b/main/src/cgeo/geocaching/cgeodetail.java index 16af323..0c5a252 100644 --- a/main/src/cgeo/geocaching/cgeodetail.java +++ b/main/src/cgeo/geocaching/cgeodetail.java @@ -4,6 +4,8 @@ import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.apps.cache.GeneralAppsFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.compatibility.Compatibility; +import cgeo.geocaching.connector.ConnectorFactory; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.utils.CollectionUtils; import cgeo.geocaching.utils.CryptUtils; @@ -50,6 +52,7 @@ import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; +import android.widget.TextView.BufferType; import java.net.URLEncoder; import java.util.ArrayList; @@ -512,7 +515,7 @@ public class cgeodetail extends AbstractActivity { menu.add(1, 5, 0, res.getString(R.string.cache_menu_spoilers)).setIcon(android.R.drawable.ic_menu_gallery); // spoiler images } - if (cache != null && cache.coords != null) { + if (cache != null && cache.coords != null && cache.supportsCachesAround()) { menu.add(0, 10, 0, res.getString(R.string.cache_menu_around)).setIcon(android.R.drawable.ic_menu_rotate); // caches around } @@ -1083,6 +1086,21 @@ public class cgeodetail extends AbstractActivity { displayLogs(); + // data license + IConnector connector = ConnectorFactory.getConnector(cache); + if (connector != null) { + String license = connector.getLicenseText(cache); + if (StringUtils.isNotBlank(license)) { + ((LinearLayout) findViewById(R.id.license_box)).setVisibility(View.VISIBLE); + TextView licenseView = ((TextView) findViewById(R.id.license)); + licenseView.setText(Html.fromHtml(license), BufferType.SPANNABLE); + licenseView.setClickable(true); + licenseView.setMovementMethod(LinkMovementMethod.getInstance()); + } else { + ((LinearLayout) findViewById(R.id.license_box)).setVisibility(View.GONE); + } + } + if (geo != null) geoUpdate.updateLoc(geo); } @@ -1904,6 +1922,9 @@ public class cgeodetail extends AbstractActivity { if (view == null) { return; } + if (!cache.supportsUserActions()) { + return; + } try { registerForContextMenu(view); diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index 50a328e..54fab87 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -1,6 +1,11 @@ package cgeo.geocaching.connector; +import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgSearch; +import cgeo.geocaching.cgeoapplication; + +import java.util.UUID; public abstract class AbstractConnector implements IConnector { @@ -23,4 +28,24 @@ public abstract class AbstractConnector implements IConnector { public boolean supportsLogging() { return false; } + + @Override + public String getLicenseText(final cgCache cache) { + return null; + } + + @Override + public boolean supportsUserActions() { + return false; + } + + @Override + public boolean supportsCachesAround() { + return false; + } + + @Override + public UUID searchByGeocode(cgBase base, String geocode, String guid, cgeoapplication app, cgSearch search, int reason) { + return null; + } } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index 867f48d..788df13 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -1,10 +1,25 @@ package cgeo.geocaching.connector; import cgeo.geocaching.cgCache; +import cgeo.geocaching.connector.opencaching.ApiOpenCachingConnector; +import cgeo.geocaching.connector.opencaching.OpenCachingConnector; public final class ConnectorFactory { private static final GCConnector GC_CONNECTOR = new GCConnector(); - private static final IConnector[] connectors = new IConnector[] { GC_CONNECTOR, new OCConnector(), new OXConnector() }; + private static final IConnector[] connectors = new IConnector[] { + GC_CONNECTOR, + new OpenCachingConnector("OpenCaching.DE", "www.opencaching.de", "OC"), + new OpenCachingConnector("OpenCaching.CZ", "www.opencaching.cz", "OZ"), + new ApiOpenCachingConnector("OpenCaching.CO.UK", "www.opencaching.org.uk", "OK", "arU4okouc4GEjMniE2fq"), + new OpenCachingConnector("OpenCaching.ES", "www.opencachingspain.es", "OC"), + new OpenCachingConnector("OpenCaching.IT", "www.opencaching.it", "OC"), + new OpenCachingConnector("OpenCaching.JP", "www.opencaching.jp", "OJ"), + new OpenCachingConnector("OpenCaching.NO/SE", "www.opencaching.no", "OS"), + new OpenCachingConnector("OpenCaching.NL", "www.opencaching.nl", "OB"), + new ApiOpenCachingConnector("OpenCaching.PL", "www.opencaching.pl", "OP", "GkxM47WkUkLQXXsZ9qSh"), + new ApiOpenCachingConnector("OpenCaching.US", "www.opencaching.us", "OU", "pTsYAYSXFcfcRQnYE6uA"), + new OXConnector() + }; public static IConnector[] getConnectors() { return connectors; @@ -20,8 +35,12 @@ public final class ConnectorFactory { } public static IConnector getConnector(cgCache cache) { + return getConnector(cache.geocode); + } + + public static IConnector getConnector(String geocode) { for (IConnector connector : connectors) { - if (connector.canHandle(cache.geocode)) { + if (connector.canHandle(geocode)) { return connector; } } diff --git a/main/src/cgeo/geocaching/connector/GCConnector.java b/main/src/cgeo/geocaching/connector/GCConnector.java index c7db821..2eea539 100644 --- a/main/src/cgeo/geocaching/connector/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/GCConnector.java @@ -1,14 +1,27 @@ package cgeo.geocaching.connector; +import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgCacheWrap; +import cgeo.geocaching.cgSearch; +import cgeo.geocaching.cgSettings; +import cgeo.geocaching.cgeoapplication; import org.apache.commons.lang3.StringUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + public class GCConnector extends AbstractConnector implements IConnector { @Override public boolean canHandle(String geocode) { - return StringUtils.isNotBlank(geocode) && geocode.toUpperCase().startsWith("GC"); + return StringUtils.isNotBlank(geocode) && StringUtils.startsWithIgnoreCase(geocode, "GC"); } @Override @@ -30,4 +43,89 @@ public class GCConnector extends AbstractConnector implements IConnector { public boolean supportsLogging() { return true; } + + @Override + public String getName() { + return "GeoCaching.com"; + } + + @Override + public String getHost() { + return "www.geocaching.com"; + } + + @Override + public boolean supportsUserActions() { + return true; + } + + @Override + public boolean supportsCachesAround() { + return true; + } + + @Override + public UUID searchByGeocode(final cgBase base, String geocode, final String guid, final cgeoapplication app, final cgSearch search, final int reason) { + final String host = "www.geocaching.com"; + final String path = "/seek/cache_details.aspx"; + final String method = "GET"; + final Map<String, String> params = new HashMap<String, String>(); + if (StringUtils.isNotBlank(geocode)) { + params.put("wp", geocode); + } else if (StringUtils.isNotBlank(guid)) { + params.put("guid", guid); + } + params.put("decrypt", "y"); + + String page = base.requestLogged(false, host, path, method, params, false, false, false); + + if (StringUtils.isEmpty(page)) { + if (app.isThere(geocode, guid, true, false)) { + if (StringUtils.isBlank(geocode) && StringUtils.isNotBlank(guid)) { + Log.i(cgSettings.tag, "Loading old cache from cache."); + + geocode = app.getGeocode(guid); + } + + final List<cgCache> cacheList = new ArrayList<cgCache>(); + cacheList.add(app.getCacheByGeocode(geocode)); + search.addGeocode(geocode); + search.error = null; + + app.addSearch(search, cacheList, false, reason); + + cacheList.clear(); + + return search.getCurrentId(); + } + + Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No data from server"); + return null; + } + + final cgCacheWrap caches = base.parseCache(page, reason); + if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { + if (caches != null && StringUtils.isNotBlank(caches.error)) { + search.error = caches.error; + } + if (caches != null && StringUtils.isNotBlank(caches.url)) { + search.url = caches.url; + } + + app.addSearch(search, null, true, reason); + + Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No cache parsed"); + return null; + } + + if (app == null) { + Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No application found"); + return null; + } + + List<cgCache> cacheList = base.processSearchResults(search, caches, 0, 0, null); + app.addSearch(search, cacheList, true, reason); + + return search.getCurrentId(); + } } diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index 66defd6..07ae43e 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -1,15 +1,80 @@ package cgeo.geocaching.connector; +import cgeo.geocaching.cgBase; import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgSearch; +import cgeo.geocaching.cgeoapplication; + +import java.util.UUID; public interface IConnector { + /** + * get name for display (currently only used in links) + * + * @return + */ + public String getName(); + + /** + * return true, if this connector is responsible for the given cache + * + * @param geocode + * @return + */ public boolean canHandle(final String geocode); public boolean supportsRefreshCache(final cgCache cache); + /** + * get browser URL for the given cache + * + * @param cache + * @return + */ public String getCacheUrl(final cgCache cache); + /** + * enable/disable watchlist controls in cache details + * + * @return + */ public boolean supportsWatchList(); + /** + * enable/disable logging controls in cache details + * + * @return + */ public boolean supportsLogging(); + + /** + * get host name of the connector server for dynamic loading of data + * + * @return + */ + public String getHost(); + + /** + * get cache data license text + * + * @param cache + * @return + */ + public String getLicenseText(final cgCache cache); + + /** + * enable/disable user actions in cache details + * + * @return + */ + public boolean supportsUserActions(); + + /** + * enable/disable "caches around" action in cache details + * + * @return + */ + public boolean supportsCachesAround(); + + public UUID searchByGeocode(final cgBase base, final String geocode, final String guid, final cgeoapplication app, final cgSearch search, final int reason); } diff --git a/main/src/cgeo/geocaching/connector/OCConnector.java b/main/src/cgeo/geocaching/connector/OCConnector.java deleted file mode 100644 index ca252ad..0000000 --- a/main/src/cgeo/geocaching/connector/OCConnector.java +++ /dev/null @@ -1,21 +0,0 @@ -package cgeo.geocaching.connector; - -import cgeo.geocaching.cgCache; - -import org.apache.commons.lang3.StringUtils; - -/** - * connector for OpenCaching.de (and several other country domains) - * - */ -public class OCConnector extends AbstractConnector implements IConnector { - @Override - public boolean canHandle(String geocode) { - return StringUtils.isNotBlank(geocode) && geocode.toUpperCase().startsWith("OC"); - } - - @Override - public String getCacheUrl(cgCache cache) { - return "http://www.opencaching.de/viewcache.php?wp=" + cache.geocode; - } -} diff --git a/main/src/cgeo/geocaching/connector/OXConnector.java b/main/src/cgeo/geocaching/connector/OXConnector.java index a1203bc..ca2f4b9 100644 --- a/main/src/cgeo/geocaching/connector/OXConnector.java +++ b/main/src/cgeo/geocaching/connector/OXConnector.java @@ -12,7 +12,7 @@ public class OXConnector extends AbstractConnector implements IConnector { @Override public boolean canHandle(String geocode) { - return StringUtils.isNotBlank(geocode) && geocode.toUpperCase().startsWith("OX"); + return StringUtils.isNotBlank(geocode) && StringUtils.startsWithIgnoreCase(geocode, "OX"); } @Override @@ -20,4 +20,14 @@ public class OXConnector extends AbstractConnector implements IConnector { return "http://www.opencaching.com/#!geocache/" + cache.geocode; } + @Override + public String getName() { + return "OpenCaching.com"; + } + + @Override + public String getHost() { + return "www.opencaching.com"; + } + } diff --git a/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java b/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java new file mode 100644 index 0000000..63c773e --- /dev/null +++ b/main/src/cgeo/geocaching/connector/opencaching/ApiOpenCachingConnector.java @@ -0,0 +1,52 @@ +package cgeo.geocaching.connector.opencaching; + +import cgeo.geocaching.cgBase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgCacheWrap; +import cgeo.geocaching.cgSearch; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.utils.CryptUtils; + +import java.util.List; +import java.util.UUID; + +public class ApiOpenCachingConnector extends OpenCachingConnector implements IConnector { + + private final String cK; + + public ApiOpenCachingConnector(String name, String host, String prefix, String cK) { + super(name, host, prefix); + this.cK = cK; + } + + public String getAuthentication(int level) { + return CryptUtils.rot13("&pbafhzre_xrl=" + cK); + } + + @Override + public String getLicenseText(final cgCache cache) { + // NOT TO BE TRANSLATED + return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License"; + } + + @Override + public boolean supportsRefreshCache(cgCache cache) { + return true; + } + + @Override + public UUID searchByGeocode(final cgBase base, final String geocode, final String guid, final cgeoapplication app, final cgSearch search, final int reason) { + final cgCache cache = OkapiClient.getCache(geocode); + if (cache == null) { + return null; + } + final cgCacheWrap caches = new cgCacheWrap(); + caches.cacheList.add(cache); + + final List<cgCache> cacheList = base.processSearchResults(search, caches, 0, 0, null); + app.addSearch(search, cacheList, true, reason); + + return search.getCurrentId(); + } +} diff --git a/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java new file mode 100644 index 0000000..e9dcded --- /dev/null +++ b/main/src/cgeo/geocaching/connector/opencaching/OkapiClient.java @@ -0,0 +1,260 @@ +package cgeo.geocaching.connector.opencaching; + +import cgeo.geocaching.cgBase; +import cgeo.geocaching.cgCache; +import cgeo.geocaching.cgImage; +import cgeo.geocaching.cgLog; +import cgeo.geocaching.connector.ConnectorFactory; +import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.enumerations.CacheSize; +import cgeo.geocaching.geopoint.GeopointParser; + +import org.apache.commons.lang3.StringUtils; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.net.Uri; +import android.text.Html; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +final public class OkapiClient { + private static final String CACHE_VOTES = "rating_votes"; + private static final String CACHE_NOTFOUNDS = "notfounds"; + private static final String CACHE_FOUNDS = "founds"; + private static final String CACHE_HIDDEN = "date_hidden"; + private static final String CACHE_LATEST_LOGS = "latest_logs"; + private static final String CACHE_IMAGE_URL = "url"; + private static final String CACHE_IMAGE_CAPTION = "caption"; + private static final String CACHE_IMAGE_IS_SPOILER = "is_spoiler"; + private static final String CACHE_IMAGES = "images"; + private static final String CACHE_HINT = "hint"; + private static final String CACHE_DESCRIPTION = "description"; + private static final String CACHE_RECOMMENDATIONS = "recommendations"; + private static final String CACHE_RATING = "rating"; + private static final String CACHE_TERRAIN = "terrain"; + private static final String CACHE_DIFFICULTY = "difficulty"; + private static final String CACHE_OWNER = "owner"; + private static final String CACHE_STATUS = "status"; + private static final String CACHE_TYPE = "type"; + private static final String CACHE_LOCATION = "location"; + private static final String CACHE_NAME = "name"; + private static final String CACHE_CODE = "code"; + + private static final String LOG_TYPE = "type"; + private static final String LOG_COMMENT = "comment"; + private static final String LOG_DATE = "date"; + private static final String LOG_USER = "user"; + + private static final String USER_USERNAME = "username"; + + private static final String SERVICE_CACHE = "/okapi/services/caches/geocache"; + private static final String SERVICE_CACHE_FIELDS = "fields=code|name|location|type|status|owner|founds|notfounds|size|difficulty|terrain|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden"; + + public static cgCache getCache(final String geoCode) { + final String params = "cache_code=" + geoCode + "&" + SERVICE_CACHE_FIELDS; + final String data = request(geoCode, SERVICE_CACHE, params, 1); + + if (StringUtils.isBlank(data)) { + return null; + } + + final cgCache cache = parseCache(data); + + cache.updated = new Date().getTime(); + cache.detailedUpdate = new Date().getTime(); + + return cache; + } + + private static cgCache parseCache(final String data) { + final cgCache cache = new cgCache(); + try { + final JSONObject response = new JSONObject(data); + cache.geocode = response.getString(CACHE_CODE); + cache.name = response.getString(CACHE_NAME); + // not used: names + setLocation(cache, response.getString(CACHE_LOCATION)); + cache.type = getCacheType(response.getString(CACHE_TYPE)); + + final String status = response.getString(CACHE_STATUS); + cache.disabled = status.equalsIgnoreCase("Temporarily unavailable"); + cache.archived = status.equalsIgnoreCase("Archived"); + + // not used: url + final JSONObject owner = response.getJSONObject(CACHE_OWNER); + cache.owner = parseUser(owner); + + cache.logCounts.put(cgBase.LOG_FOUND_IT, response.getInt(CACHE_FOUNDS)); + cache.logCounts.put(cgBase.LOG_DIDNT_FIND_IT, response.getInt(CACHE_NOTFOUNDS)); + cache.size = getCacheSize(response); + cache.difficulty = (float) response.getDouble(CACHE_DIFFICULTY); + cache.terrain = (float) response.getDouble(CACHE_TERRAIN); + if (response.has(CACHE_RATING) && !isNull(response.getString(CACHE_RATING))) { + cache.rating = (float) response.getDouble(CACHE_RATING); + } + cache.votes = response.getInt(CACHE_VOTES); + + cache.favouriteCnt = response.getInt(CACHE_RECOMMENDATIONS); + // not used: req_password + cache.description = response.getString(CACHE_DESCRIPTION); + cache.hint = Html.fromHtml(response.getString(CACHE_HINT)).toString(); + // not used: hints + + final JSONArray images = response.getJSONArray(CACHE_IMAGES); + if (images != null) { + JSONObject imageResponse; + cgImage image; + for (int i = 0; i < images.length(); i++) { + imageResponse = images.getJSONObject(i); + if (imageResponse.getBoolean(CACHE_IMAGE_IS_SPOILER)) { + image = new cgImage(); + image.title = imageResponse.getString(CACHE_IMAGE_CAPTION); + image.url = absoluteUrl(imageResponse.getString(CACHE_IMAGE_URL), cache.geocode); + if (cache.spoilers == null) { + cache.spoilers = new ArrayList<cgImage>(); + } + cache.spoilers.add(image); + } + } + } + + // not used: attrnames + cache.logs = parseLogs(response.getJSONArray(CACHE_LATEST_LOGS)); + cache.hidden = parseDate(response.getString(CACHE_HIDDEN)); + + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return cache; + } + + private static String absoluteUrl(String url, String geocode) { + final Uri uri = Uri.parse(url); + + if (!uri.isAbsolute()) { + final IConnector connector = ConnectorFactory.getConnector(geocode); + return "http://" + connector.getHost() + "/" + url; + } + return url; + } + + private static boolean isNull(String string) { + return string.equalsIgnoreCase("null"); + } + + private static String parseUser(JSONObject user) throws JSONException { + return user.getString(USER_USERNAME); + } + + private static List<cgLog> parseLogs(JSONArray logsJSON) { + List<cgLog> result = null; + for (int i = 0; i < logsJSON.length(); i++) { + try { + JSONObject logResponse = logsJSON.getJSONObject(i); + cgLog log = new cgLog(); + log.date = parseDate(logResponse.getString(LOG_DATE)).getTime(); + log.log = logResponse.getString(LOG_COMMENT).trim(); + log.type = parseLogType(logResponse.getString(LOG_TYPE)); + log.author = parseUser(logResponse.getJSONObject(LOG_USER)); + if (result == null) { + result = new ArrayList<cgLog>(); + } + result.add(log); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + return result; + } + + private static int parseLogType(String logType) { + if ("Found it".equalsIgnoreCase(logType)) { + return cgBase.LOG_FOUND_IT; + } + else if ("Didn't find it".equalsIgnoreCase(logType)) { + return cgBase.LOG_DIDNT_FIND_IT; + } + return cgBase.LOG_NOTE; + } + + private static Date parseDate(final String date) { + final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()); + final String strippedDate = date.replaceAll("\\+0([0-9]){1}\\:00", "+0$100"); + try { + return ISO8601DATEFORMAT.parse(strippedDate); + } catch (ParseException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + private static void setLocation(final cgCache cache, final String location) { + final String latitude = StringUtils.substringBefore(location, "|"); + final String longitude = StringUtils.substringAfter(location, "|"); + // FIXME: the next lines should be a setter at cgCache + cache.coords = GeopointParser.parse(latitude, longitude); + cache.latitudeString = cgBase.formatLatitude(cache.coords.getLatitude(), true); + cache.longitudeString = cgBase.formatLongitude(cache.coords.getLongitude(), true); + } + + private static CacheSize getCacheSize(final JSONObject response) { + double size = 0; + try { + size = response.getDouble("size"); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + switch ((int) Math.round(size)) { + case 1: + return CacheSize.MICRO; + case 2: + return CacheSize.SMALL; + case 3: + return CacheSize.REGULAR; + case 4: + return CacheSize.LARGE; + case 5: + return CacheSize.LARGE; + default: + break; + } + return CacheSize.NOT_CHOSEN; + } + + private static String getCacheType(final String type) { + if (type.equalsIgnoreCase("Traditional")) { + return "traditional"; + } else if (type.equalsIgnoreCase("Multi")) { + return "multi"; + } else if (type.equalsIgnoreCase("Quiz")) { + return "mystery"; + } else if (type.equalsIgnoreCase("Virtual")) { + return "virtual"; + } + return "other"; + } + + private static String request(final String geoCode, final String service, final String params, final int level) { + final IConnector connector = ConnectorFactory.getConnector(geoCode); + if (connector == null) { + return null; + } + if (!(connector instanceof ApiOpenCachingConnector)) { + return null; + } + + return cgBase.requestJSON(connector.getHost(), service, params + ((ApiOpenCachingConnector) connector).getAuthentication(level)); + } +} diff --git a/main/src/cgeo/geocaching/connector/opencaching/OpenCachingConnector.java b/main/src/cgeo/geocaching/connector/opencaching/OpenCachingConnector.java new file mode 100644 index 0000000..0fe69f5 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/opencaching/OpenCachingConnector.java @@ -0,0 +1,41 @@ +package cgeo.geocaching.connector.opencaching; + +import cgeo.geocaching.cgCache; +import cgeo.geocaching.connector.AbstractConnector; +import cgeo.geocaching.connector.IConnector; + +import org.apache.commons.lang3.StringUtils; + +public class OpenCachingConnector extends AbstractConnector implements IConnector { + + private final String host; + private final String name; + private final String prefix; + + public OpenCachingConnector(final String name, final String host, final String prefix) { + this.name = name; + this.host = host; + this.prefix = prefix; + } + + @Override + public boolean canHandle(String geocode) { + return StringUtils.isNotBlank(geocode) && StringUtils.startsWithIgnoreCase(geocode, prefix); + } + + @Override + public String getName() { + return name; + } + + @Override + public String getCacheUrl(cgCache cache) { + return "http://" + host + "/viewcache.php?wp=" + cache.geocode; + } + + @Override + public String getHost() { + return host; + } + +} |
