<NME> AbstractLocusApp.java
<BEF> package cgeo.geocaching.apps;

import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.models.Waypoint;
import cgeo.geocaching.enumerations.CacheSize;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.WaypointType;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.Uri;
import org.eclipse.jdt.annotation.Nullable;

import android.app.Activity;
import android.location.Location;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import menion.android.locus.LocusDataStorageProvider;
import menion.android.locus.addon.publiclib.DisplayData;
import menion.android.locus.addon.publiclib.LocusUtils;
import menion.android.locus.addon.publiclib.geoData.Point;
import menion.android.locus.addon.publiclib.geoData.PointGeocachingData;
import menion.android.locus.addon.publiclib.geoData.PointGeocachingDataWaypoint;
import menion.android.locus.addon.publiclib.geoData.PointsData;

/**
 * for the Locus API:
 *
 * @see <a href="http://forum.asamm.cz/viewtopic.php?f=29&t=767">Locus forum</a>
 */
public abstract class AbstractLocusApp extends AbstractApp {
    private static final SynchronizedDateFormat ISO8601DATE = new SynchronizedDateFormat("yyyy-MM-dd'T'", Locale.US);

/**
 * for the Locus API:
 *
 * @see <a href="https://docs.locusmap.eu/doku.php?id=manual:advanced:locus_api:installation">Locus API</a>

    @Override
    public boolean isInstalled() {
        return LocusUtils.isLocusAvailable(CgeoApplication.getInstance());
    }

    /**
    private final LocusVersion lv;

    @SuppressFBWarnings("NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION")
    protected AbstractLocusApp(@NonNull final String text, @NonNull final String intent) {
        super(text, intent);

        try (ContextLogger cLog = new ContextLogger(true, "AbstractLocusApp.init (" + this.getClass().getName() + ")")) {
            lv = LocusUtils.INSTANCE.getActiveVersion(CgeoApplication.getInstance());
            cLog.add("V:" + lv);
            if (lv == null) { // locus not installed
                Log.w("Couldn't get active Locus version");
        }

        final boolean withCacheDetails = objectsToShow.size() < 200;
        final PointsData pd = new PointsData("c:geo");
        for (final Object o : objectsToShow) {
            Point p = null;
            // get icon and Point
            if (o instanceof Geocache) {
                p = getCachePoint((Geocache) o, withCacheWaypoints, withCacheDetails);
            } else if (o instanceof Waypoint) {
                p = getWaypointPoint((Waypoint) o);
            }
            if (p != null) {
                pd.addPoint(p);
            }
        }

        if (pd.getPoints().isEmpty()) {
            return false;
        }

        if (pd.getPoints().size() <= 1000) {
            DisplayData.sendData(activity, pd, export);
        } else {
            final ArrayList<PointsData> data = new ArrayList<>();
            data.add(pd);
            DisplayData.sendDataCursor(activity, data,
                    "content://" + LocusDataStorageProvider.class.getCanonicalName().toLowerCase(Locale.US),
                    export);
        }

        return true;

            final ArrayList<PackPoints> data = new ArrayList<>();
            data.add(pd);

            try {
                if (lv.isVersionValid(VersionCode.UPDATE_15)) {
                    // send file via FileProvider, you don't need WRITE_EXTERNAL_STORAGE permission for this
                    final Uri uri = FileProvider.getUriForFile(context, context.getString(R.string.file_provider_authority), file);
                    ActionDisplayPoints.INSTANCE.sendPacksFile(context, lv, data, file, uri, export ? ActionDisplayVarious.ExtraAction.IMPORT : ActionDisplayVarious.ExtraAction.CENTER);
                } else {
     * @return null, when the {@code Point} could not be constructed
     */
    @Nullable
    private static Point getCachePoint(final Geocache cache, final boolean withWaypoints, final boolean withCacheDetails) {
        if (cache == null || cache.getCoords() == null) {
            return null;
        }
            } catch (final RequiredVersionMissingException e) {
                Log.e("AbstractLocusApp.showInLocus: problem in sendPacksFile", e);
            }
        loc.setLatitude(cache.getCoords().getLatitude());
        loc.setLongitude(cache.getCoords().getLongitude());

        final Point p = new Point(cache.getName(), loc);
        final PointGeocachingData pg = new PointGeocachingData();
        p.setGeocachingData(pg);

        // set data in Locus' cache
        pg.cacheID = cache.getGeocode();
        pg.available = !cache.isDisabled();
        pg.archived = cache.isArchived();
        pg.premiumOnly = cache.isPremiumMembersOnly();
        pg.name = cache.getName();
        pg.placedBy = cache.getOwnerDisplayName();
        final Date hiddenDate = cache.getHiddenDate();
        if (hiddenDate != null) {
            pg.hidden = ISO8601DATE.format(hiddenDate);
        }
        final int type = toLocusType(cache.getType());
        if (type != NO_LOCUS_ID) {
            pg.type = type;
        }
        final int container = toLocusSize(cache.getSize());
        if (container != NO_LOCUS_ID) {
            pg.container = container;
        }
        if (cache.getDifficulty() > 0) {
            pg.difficulty = cache.getDifficulty();
        }
        if (cache.getTerrain() > 0) {
            pg.terrain = cache.getTerrain();
        }
        pg.found = cache.isFound();

        if (withWaypoints && cache.hasWaypoints()) {
            pg.waypoints = new ArrayList<>();
            for (final Waypoint waypoint : cache.getWaypoints()) {
                if (waypoint == null) {
                    continue;
                }

                final PointGeocachingDataWaypoint wp = new PointGeocachingDataWaypoint();
                wp.code = waypoint.getLookup();
                wp.name = waypoint.getName();
                wp.description = waypoint.getNote();
                final String locusWpId = toLocusWaypoint(waypoint.getWaypointType());
                if (locusWpId != null) {
                    wp.type = locusWpId;
                }

                final Geopoint waypointCoords = waypoint.getCoords();
                if (waypointCoords != null) {
                    wp.lat = waypointCoords.getLatitude();
                    wp.lon = waypointCoords.getLongitude();
                }
                pg.waypoints.add(wp);
            }
        }

        // Other properties of caches. When there are many caches to be displayed
        // in Locus, using these properties can lead to Exceptions in Locus.
        // Should not be used if caches count > 200

        if (withCacheDetails) {
            pg.shortDescription = cache.getShortDescription();
            pg.longDescription = cache.getDescription();
            pg.encodedHints = cache.getHint();
        }

        return p;
    }

    /**
        if (withCacheDetails) {
            gcData.setDescriptions(
     * @return null, when the {@code Point} could not be constructed
     */
    @Nullable
    private static Point getWaypointPoint(final Waypoint waypoint) {
        if (waypoint == null) {
            return null;
        }
        return wpt;
    }

    /**
     * This method constructs a {@code Point} for displaying in Locus
     *
     * @return null, when the {@code Point} could not be constructed
        loc.setLatitude(coordinates.getLatitude());
        loc.setLongitude(coordinates.getLongitude());

        final Point p = new Point(waypoint.getName(), loc);
        p.setDescription("<a href=\"" + waypoint.getUrl() + "\">"
                + waypoint.getGeocode() + "</a>");

        return p;
    }
        }

        // create one simple point with location
    private static int toLocusType(final CacheType ct) {
        switch (ct) {
            case TRADITIONAL:
                return PointGeocachingData.CACHE_TYPE_TRADITIONAL;
            case MULTI:
                return PointGeocachingData.CACHE_TYPE_MULTI;
            case MYSTERY:
                return PointGeocachingData.CACHE_TYPE_MYSTERY;
            case LETTERBOX:
                return PointGeocachingData.CACHE_TYPE_LETTERBOX;
            case EVENT:
                return PointGeocachingData.CACHE_TYPE_EVENT;
            case MEGA_EVENT:
                return PointGeocachingData.CACHE_TYPE_MEGA_EVENT;
            case EARTH:
                return PointGeocachingData.CACHE_TYPE_EARTH;
            case CITO:
                return PointGeocachingData.CACHE_TYPE_CACHE_IN_TRASH_OUT;
            case WEBCAM:
                return PointGeocachingData.CACHE_TYPE_WEBCAM;
            case VIRTUAL:
                return PointGeocachingData.CACHE_TYPE_VIRTUAL;
            case WHERIGO:
                return PointGeocachingData.CACHE_TYPE_WHERIGO;
            case PROJECT_APE:
                return PointGeocachingData.CACHE_TYPE_PROJECT_APE;
            case GPS_EXHIBIT:
                return PointGeocachingData.CACHE_TYPE_GPS_ADVENTURE;
            default:
                return NO_LOCUS_ID;
        }
                return GeocachingData.CACHE_TYPE_MEGA_EVENT;
            case GIGA_EVENT:
    private static int toLocusSize(final CacheSize cs) {
        switch (cs) {
            case MICRO:
                return PointGeocachingData.CACHE_SIZE_MICRO;
            case SMALL:
                return PointGeocachingData.CACHE_SIZE_SMALL;
            case REGULAR:
                return PointGeocachingData.CACHE_SIZE_REGULAR;
            case LARGE:
                return PointGeocachingData.CACHE_SIZE_LARGE;
            case NOT_CHOSEN:
                return PointGeocachingData.CACHE_SIZE_NOT_CHOSEN;
            case OTHER:
                return PointGeocachingData.CACHE_SIZE_OTHER;
            default:
                return NO_LOCUS_ID;
        }
            case GCHQ_CELEBRATION:
                return GeocachingData.CACHE_TYPE_GC_HQ_CELEBRATION;
            case GPS_EXHIBIT:
    private static String toLocusWaypoint(final WaypointType wt) {
        switch (wt) {
            case FINAL:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_FINAL;
            case OWN:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_STAGES;
            case PARKING:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_PARKING;
            case PUZZLE:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_QUESTION;
            case STAGE:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_STAGES;
            case TRAILHEAD:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_TRAILHEAD;
            case WAYPOINT:
                return PointGeocachingData.CACHE_WAYPOINT_TYPE_STAGES;
            default:
                return null;
        }
            case UNKNOWN:
            case ALL:
                return GeocachingData.CACHE_TYPE_UNDEFINED;
        }
        // special and unknown cache type
        return GeocachingData.CACHE_TYPE_UNDEFINED;
    }

    @VisibleForTesting
    @SuppressWarnings("DuplicateBranchesInSwitch")
    static int toLocusSize(final CacheSize cs) {
        switch (cs) {
            case NANO:
                return GeocachingData.CACHE_SIZE_MICRO; // used by OC only
            case MICRO:
                return GeocachingData.CACHE_SIZE_MICRO;
            case SMALL:
                return GeocachingData.CACHE_SIZE_SMALL;
            case REGULAR:
                return GeocachingData.CACHE_SIZE_REGULAR;
            case LARGE:
                return GeocachingData.CACHE_SIZE_LARGE;
            case VERY_LARGE:
                return GeocachingData.CACHE_SIZE_HUGE; // used by OC only
            case NOT_CHOSEN:
                return GeocachingData.CACHE_SIZE_NOT_CHOSEN;
            case VIRTUAL:
                return GeocachingData.CACHE_SIZE_OTHER;
            case OTHER:
                return GeocachingData.CACHE_SIZE_OTHER;
            case UNKNOWN:
                return GeocachingData.CACHE_SIZE_NOT_CHOSEN;
        }
        // unknown cache size
        return GeocachingData.CACHE_SIZE_NOT_CHOSEN;
    }

    @NonNull
    @VisibleForTesting
    @SuppressWarnings("DuplicateBranchesInSwitch")
    static String toLocusWaypoint(final WaypointType wt) {
        switch (wt) {
            case FINAL:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_FINAL;
            case OWN:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PHYSICAL_STAGE;
            case PARKING:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PARKING;
            case PUZZLE:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_VIRTUAL_STAGE;
            case STAGE:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PHYSICAL_STAGE;
            case TRAILHEAD:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_TRAILHEAD;
            case WAYPOINT:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_REFERENCE;
            case ORIGINAL:
                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_REFERENCE;
        }
        // unknown waypoint type
        return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_REFERENCE;
    }

    @NonNull
    @VisibleForTesting
    static ArrayList<GeocachingAttribute> toLocusAttributes(final List<String> attributes) {
        final ArrayList<GeocachingAttribute> loAttributes = new ArrayList<>();

        for (String attribute : attributes) {
            String rawAttribute = CacheAttribute.trimAttributeName(attribute);
            if (rawAttribute.equals("")) {
                continue;
            }
            // translate to locus names
            switch (rawAttribute) {
                case "uv":
                    rawAttribute = "UV";
                    break;
                case "dangerousanimals":
                    rawAttribute = "snakes";
                    break;
                case "s_tool":
                    rawAttribute = "s-tool";
                    break;
                case "abandonedbuilding":
                    rawAttribute = "AbandonedBuilding";
                    break;
                case "touristok":
                    rawAttribute = "touristOK";
                    break;
                case "bonuscache":
                    rawAttribute = "bonus";
                    break;
                case "powertrail":
                    rawAttribute = "power";
                    break;
                case "challengecache":
                    rawAttribute = "challenge";
                    break;
                case "hqsolutionchecker":
                    rawAttribute = "checker";
                    break;
                default:
                    // do nothing
                    break;
            }
            final String attributeUrl = "/" + rawAttribute + (CacheAttribute.isEnabled(attribute) ? "-yes." : "-no.");
            final GeocachingAttribute ga = new GeocachingAttribute(attributeUrl);
            // e.g. OC attributes - skip
            if (ga.getId() > 0) {
                loAttributes.add(ga);
            }
        }
        return loAttributes;
    }
}

<MSG> fix #5451: locus export limit, api update

<DFF> @@ -2,7 +2,13 @@ package cgeo.geocaching.apps;
 
 import cgeo.geocaching.CgeoApplication;
 import cgeo.geocaching.models.Geocache;
-import cgeo.geocaching.models.Waypoint;
+import cgeo.geocaching.storage.LocalStorage;
+import cgeo.geocaching.utils.Log;
+import locus.api.android.ActionDisplay;
+import locus.api.android.ActionDisplayPoints;
+import locus.api.android.objects.PackWaypoints;
+import locus.api.android.utils.exceptions.RequiredVersionMissingException;
+import locus.api.objects.extra.Waypoint;
 import cgeo.geocaching.enumerations.CacheSize;
 import cgeo.geocaching.enumerations.CacheType;
 import cgeo.geocaching.enumerations.WaypointType;
@@ -13,26 +19,26 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 
 import android.app.Activity;
-import android.location.Location;
+import android.os.Environment;
 
+import locus.api.objects.extra.Location;
+
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import menion.android.locus.LocusDataStorageProvider;
-import menion.android.locus.addon.publiclib.DisplayData;
-import menion.android.locus.addon.publiclib.LocusUtils;
-import menion.android.locus.addon.publiclib.geoData.Point;
-import menion.android.locus.addon.publiclib.geoData.PointGeocachingData;
-import menion.android.locus.addon.publiclib.geoData.PointGeocachingDataWaypoint;
-import menion.android.locus.addon.publiclib.geoData.PointsData;
+import locus.api.android.utils.LocusUtils;
+import locus.api.objects.geocaching.GeocachingData;
+import locus.api.objects.geocaching.GeocachingWaypoint;
 
 /**
  * for the Locus API:
  *
- * @see <a href="http://forum.asamm.cz/viewtopic.php?f=29&t=767">Locus forum</a>
+ * @see <a href="http://docs.locusmap.eu/doku.php?id=manual:advanced:locus_api:installation">Locus API</a>
+ * @see <a href="https://bitbucket.org/asamm/locus-api-android-sample/src/1fad202e6166239b6e424f03bac79f0000f8eb6d/src/main/java/menion/android/locus/api/utils/SampleCalls.java?at=default&fileviewer=file-view-default">Sample Calls</a>
  */
 public abstract class AbstractLocusApp extends AbstractApp {
     private static final SynchronizedDateFormat ISO8601DATE = new SynchronizedDateFormat("yyyy-MM-dd'T'", Locale.US);
@@ -44,7 +50,7 @@ public abstract class AbstractLocusApp extends AbstractApp {
 
     @Override
     public boolean isInstalled() {
-        return LocusUtils.isLocusAvailable(CgeoApplication.getInstance());
+        return LocusUtils.getActiveVersion(CgeoApplication.getInstance()) != null;
     }
 
     /**
@@ -62,32 +68,53 @@ public abstract class AbstractLocusApp extends AbstractApp {
         }
 
         final boolean withCacheDetails = objectsToShow.size() < 200;
-        final PointsData pd = new PointsData("c:geo");
+        final PackWaypoints pd = new PackWaypoints("c:geo");
         for (final Object o : objectsToShow) {
-            Point p = null;
+            Waypoint p = null;
             // get icon and Point
             if (o instanceof Geocache) {
                 p = getCachePoint((Geocache) o, withCacheWaypoints, withCacheDetails);
-            } else if (o instanceof Waypoint) {
-                p = getWaypointPoint((Waypoint) o);
+            } else if (o instanceof cgeo.geocaching.models.Waypoint) {
+                p = getWaypointPoint((cgeo.geocaching.models.Waypoint) o);
             }
             if (p != null) {
-                pd.addPoint(p);
+                pd.addWaypoint(p);
             }
         }
 
-        if (pd.getPoints().isEmpty()) {
+        if (pd.getWaypoints().isEmpty()) {
             return false;
         }
 
-        if (pd.getPoints().size() <= 1000) {
-            DisplayData.sendData(activity, pd, export);
+        if (pd.getWaypoints().size() <= 1000) {
+            try {
+                ActionDisplayPoints.sendPack(activity, pd, export ? ActionDisplay.ExtraAction.IMPORT : ActionDisplay.ExtraAction.CENTER);
+            } catch (RequiredVersionMissingException e) {
+                Log.e("AbstractLocusApp.showInLocus: problem in sendPack", e);
+                return false;
+            }
         } else {
-            final ArrayList<PointsData> data = new ArrayList<>();
+            final File externalDir = Environment.getExternalStorageDirectory();
+            if (externalDir == null || !externalDir.exists()) {
+                Log.w("AbstractLocusApp.showInLocus: problem with obtain of External dir");
+                return false;
+            }
+
+            String filePath = externalDir.getAbsolutePath();
+            if (!filePath.endsWith("/")) {
+                filePath += "/";
+            }
+            filePath += "Android/data/menion.android.locus.api/files/showIn.locus";
+
+            final ArrayList<PackWaypoints> data = new ArrayList<PackWaypoints>();
             data.add(pd);
-            DisplayData.sendDataCursor(activity, data,
-                    "content://" + LocusDataStorageProvider.class.getCanonicalName().toLowerCase(Locale.US),
-                    export);
+
+            try {
+                ActionDisplayPoints.sendPacksFile(activity, data, filePath, export ? ActionDisplay.ExtraAction.IMPORT : ActionDisplay.ExtraAction.CENTER);
+            } catch (RequiredVersionMissingException e) {
+                Log.e("AbstractLocusApp.showInLocus: problem in sendPacksFile", e);
+                return false;
+            }
         }
 
         return true;
@@ -104,7 +131,7 @@ public abstract class AbstractLocusApp extends AbstractApp {
      * @return null, when the {@code Point} could not be constructed
      */
     @Nullable
-    private static Point getCachePoint(final Geocache cache, final boolean withWaypoints, final boolean withCacheDetails) {
+    private static Waypoint getCachePoint(final Geocache cache, final boolean withWaypoints, final boolean withCacheDetails) {
         if (cache == null || cache.getCoords() == null) {
             return null;
         }
@@ -114,73 +141,81 @@ public abstract class AbstractLocusApp extends AbstractApp {
         loc.setLatitude(cache.getCoords().getLatitude());
         loc.setLongitude(cache.getCoords().getLongitude());
 
-        final Point p = new Point(cache.getName(), loc);
-        final PointGeocachingData pg = new PointGeocachingData();
-        p.setGeocachingData(pg);
-
-        // set data in Locus' cache
-        pg.cacheID = cache.getGeocode();
-        pg.available = !cache.isDisabled();
-        pg.archived = cache.isArchived();
-        pg.premiumOnly = cache.isPremiumMembersOnly();
-        pg.name = cache.getName();
-        pg.placedBy = cache.getOwnerDisplayName();
-        final Date hiddenDate = cache.getHiddenDate();
-        if (hiddenDate != null) {
-            pg.hidden = ISO8601DATE.format(hiddenDate);
+        final Waypoint wpt = new Waypoint(cache.getName(), loc);
+        // generate new data
+        final GeocachingData gcData = new GeocachingData();
+
+        // fill data with variables
+        gcData.setCacheID(cache.getGeocode());
+        gcData.setName(cache.getName());
+
+        // rest is optional so fill as you want - should work
+        gcData.setOwner(cache.getOwnerUserId());
+        gcData.setPlacedBy(cache.getOwnerDisplayName());
+        if (cache.getDifficulty() > 0) {
+            gcData.setDifficulty(cache.getDifficulty());
         }
-        final int type = toLocusType(cache.getType());
-        if (type != NO_LOCUS_ID) {
-            pg.type = type;
+        if (cache.getTerrain() > 0) {
+            gcData.setTerrain(cache.getTerrain());
         }
         final int container = toLocusSize(cache.getSize());
         if (container != NO_LOCUS_ID) {
-            pg.container = container;
+            gcData.setContainer(container);
         }
-        if (cache.getDifficulty() > 0) {
-            pg.difficulty = cache.getDifficulty();
+
+        gcData.setAvailable(!cache.isDisabled());
+        gcData.setArchived(cache.isArchived());
+        gcData.setPremiumOnly(cache.isPremiumMembersOnly());
+        final Date hiddenDate = cache.getHiddenDate();
+        if (hiddenDate != null) {
+            gcData.setDateHidden(hiddenDate.getTime());
         }
-        if (cache.getTerrain() > 0) {
-            pg.terrain = cache.getTerrain();
+        final int type = toLocusType(cache.getType());
+        if (type != NO_LOCUS_ID) {
+            gcData.setType(type);
         }
-        pg.found = cache.isFound();
+        gcData.setFound(cache.isFound());
 
         if (withWaypoints && cache.hasWaypoints()) {
-            pg.waypoints = new ArrayList<>();
-            for (final Waypoint waypoint : cache.getWaypoints()) {
+            for (final cgeo.geocaching.models.Waypoint waypoint : cache.getWaypoints()) {
                 if (waypoint == null) {
                     continue;
                 }
 
-                final PointGeocachingDataWaypoint wp = new PointGeocachingDataWaypoint();
-                wp.code = waypoint.getLookup();
-                wp.name = waypoint.getName();
-                wp.description = waypoint.getNote();
+                GeocachingWaypoint gcWpt = new GeocachingWaypoint();
+                gcWpt.setCode(waypoint.getLookup());
+                gcWpt.setName(waypoint.getName());
+                gcWpt.setDesc(waypoint.getNote());
+                gcWpt.setType(GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PARKING);
+
                 final String locusWpId = toLocusWaypoint(waypoint.getWaypointType());
                 if (locusWpId != null) {
-                    wp.type = locusWpId;
+                    gcWpt.setType(locusWpId);
                 }
 
                 final Geopoint waypointCoords = waypoint.getCoords();
                 if (waypointCoords != null) {
-                    wp.lat = waypointCoords.getLatitude();
-                    wp.lon = waypointCoords.getLongitude();
+                    gcWpt.setLon(waypointCoords.getLongitude());
+                    gcWpt.setLat(waypointCoords.getLatitude());
                 }
-                pg.waypoints.add(wp);
+
+                gcData.waypoints.add(gcWpt);
             }
         }
 
         // Other properties of caches. When there are many caches to be displayed
         // in Locus, using these properties can lead to Exceptions in Locus.
         // Should not be used if caches count > 200
-
         if (withCacheDetails) {
-            pg.shortDescription = cache.getShortDescription();
-            pg.longDescription = cache.getDescription();
-            pg.encodedHints = cache.getHint();
+            gcData.setDescriptions(
+                    cache.getShortDescription(), true,
+                    cache.getDescription(), true);
+            gcData.setEncodedHints(cache.getHint());
         }
 
-        return p;
+        // set data and return point
+        wpt.gcData = gcData;
+        return wpt;
     }
 
     /**
@@ -189,7 +224,7 @@ public abstract class AbstractLocusApp extends AbstractApp {
      * @return null, when the {@code Point} could not be constructed
      */
     @Nullable
-    private static Point getWaypointPoint(final Waypoint waypoint) {
+    private static Waypoint getWaypointPoint(final cgeo.geocaching.models.Waypoint waypoint) {
         if (waypoint == null) {
             return null;
         }
@@ -203,9 +238,9 @@ public abstract class AbstractLocusApp extends AbstractApp {
         loc.setLatitude(coordinates.getLatitude());
         loc.setLongitude(coordinates.getLongitude());
 
-        final Point p = new Point(waypoint.getName(), loc);
-        p.setDescription("<a href=\"" + waypoint.getUrl() + "\">"
-                + waypoint.getGeocode() + "</a>");
+        final Waypoint p = new Waypoint(waypoint.getName(), loc);
+        //TODO: not supported by new Locus API (or I haven't found it yet, pstorch)
+        //p.setDescription("<a href=\"" + waypoint.getUrl() + "\">" + waypoint.getGeocode() + "</a>");
 
         return p;
     }
@@ -215,31 +250,31 @@ public abstract class AbstractLocusApp extends AbstractApp {
     private static int toLocusType(final CacheType ct) {
         switch (ct) {
             case TRADITIONAL:
-                return PointGeocachingData.CACHE_TYPE_TRADITIONAL;
+                return GeocachingData.CACHE_TYPE_TRADITIONAL;
             case MULTI:
-                return PointGeocachingData.CACHE_TYPE_MULTI;
+                return GeocachingData.CACHE_TYPE_MULTI;
             case MYSTERY:
-                return PointGeocachingData.CACHE_TYPE_MYSTERY;
+                return GeocachingData.CACHE_TYPE_MYSTERY;
             case LETTERBOX:
-                return PointGeocachingData.CACHE_TYPE_LETTERBOX;
+                return GeocachingData.CACHE_TYPE_LETTERBOX;
             case EVENT:
-                return PointGeocachingData.CACHE_TYPE_EVENT;
+                return GeocachingData.CACHE_TYPE_EVENT;
             case MEGA_EVENT:
-                return PointGeocachingData.CACHE_TYPE_MEGA_EVENT;
+                return GeocachingData.CACHE_TYPE_MEGA_EVENT;
             case EARTH:
-                return PointGeocachingData.CACHE_TYPE_EARTH;
+                return GeocachingData.CACHE_TYPE_EARTH;
             case CITO:
-                return PointGeocachingData.CACHE_TYPE_CACHE_IN_TRASH_OUT;
+                return GeocachingData.CACHE_TYPE_CACHE_IN_TRASH_OUT;
             case WEBCAM:
-                return PointGeocachingData.CACHE_TYPE_WEBCAM;
+                return GeocachingData.CACHE_TYPE_WEBCAM;
             case VIRTUAL:
-                return PointGeocachingData.CACHE_TYPE_VIRTUAL;
+                return GeocachingData.CACHE_TYPE_VIRTUAL;
             case WHERIGO:
-                return PointGeocachingData.CACHE_TYPE_WHERIGO;
+                return GeocachingData.CACHE_TYPE_WHERIGO;
             case PROJECT_APE:
-                return PointGeocachingData.CACHE_TYPE_PROJECT_APE;
+                return GeocachingData.CACHE_TYPE_PROJECT_APE;
             case GPS_EXHIBIT:
-                return PointGeocachingData.CACHE_TYPE_GPS_ADVENTURE;
+                return GeocachingData.CACHE_TYPE_GPS_ADVENTURE;
             default:
                 return NO_LOCUS_ID;
         }
@@ -248,17 +283,17 @@ public abstract class AbstractLocusApp extends AbstractApp {
     private static int toLocusSize(final CacheSize cs) {
         switch (cs) {
             case MICRO:
-                return PointGeocachingData.CACHE_SIZE_MICRO;
+                return GeocachingData.CACHE_SIZE_MICRO;
             case SMALL:
-                return PointGeocachingData.CACHE_SIZE_SMALL;
+                return GeocachingData.CACHE_SIZE_SMALL;
             case REGULAR:
-                return PointGeocachingData.CACHE_SIZE_REGULAR;
+                return GeocachingData.CACHE_SIZE_REGULAR;
             case LARGE:
-                return PointGeocachingData.CACHE_SIZE_LARGE;
+                return GeocachingData.CACHE_SIZE_LARGE;
             case NOT_CHOSEN:
-                return PointGeocachingData.CACHE_SIZE_NOT_CHOSEN;
+                return GeocachingData.CACHE_SIZE_NOT_CHOSEN;
             case OTHER:
-                return PointGeocachingData.CACHE_SIZE_OTHER;
+                return GeocachingData.CACHE_SIZE_OTHER;
             default:
                 return NO_LOCUS_ID;
         }
@@ -268,19 +303,19 @@ public abstract class AbstractLocusApp extends AbstractApp {
     private static String toLocusWaypoint(final WaypointType wt) {
         switch (wt) {
             case FINAL:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_FINAL;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_FINAL;
             case OWN:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_STAGES;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PHYSICAL_STAGE;
             case PARKING:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_PARKING;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PARKING;
             case PUZZLE:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_QUESTION;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_VIRTUAL_STAGE;
             case STAGE:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_STAGES;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_PHYSICAL_STAGE;
             case TRAILHEAD:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_TRAILHEAD;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_TRAILHEAD;
             case WAYPOINT:
-                return PointGeocachingData.CACHE_WAYPOINT_TYPE_STAGES;
+                return GeocachingWaypoint.CACHE_WAYPOINT_TYPE_REFERENCE;
             default:
                 return null;
         }

fix #5451: locus export limit, api update