com.esri.android.ecologicalmarineunitexplorer.data.DataManager.java Source code

Java tutorial

Introduction

Here is the source code for com.esri.android.ecologicalmarineunitexplorer.data.DataManager.java

Source

package com.esri.android.ecologicalmarineunitexplorer.data;
/* Copyright 2016 Esri
 *
 * Licensed 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.
 *
 * For additional information, contact:
 * Environmental Systems Research Institute, Inc.
 * Attn: Contracts Dept
 * 380 New York Street
 * Redlands, California, USA 92373
 *
 * email: contracts@esri.com
 *
 */

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import com.esri.android.ecologicalmarineunitexplorer.R;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.Feature;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.data.ServiceFeatureTable;
import com.esri.arcgisruntime.geometry.*;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimaps;

import java.util.*;

public class DataManager {
    private ServiceFeatureTable mMeshClusterTable;

    private ServiceFeatureTable mMeshPointTable;

    private ServiceFeatureTable mClusterPolygonTable;

    private Context mContext;

    private static DataManager instance = null;

    private Map<Point, WaterColumn> cache = new HashMap<>();

    private DataManager(Context applicationContext) {

        mContext = applicationContext;

        mClusterPolygonTable = new ServiceFeatureTable(mContext.getString(R.string.service_emu_polygon));

        mMeshClusterTable = new ServiceFeatureTable(mContext.getString(R.string.service_emu_mesh_cluster));

        mMeshPointTable = new ServiceFeatureTable(mContext.getString(R.string.service_emu_point_mesh));
    }

    /**
     * A singleton that provides access to data services
     * @param applicationContext - Context
     */
    public static DataManager getDataManagerInstance(Context applicationContext) {
        if (instance == null) {
            instance = new DataManager(applicationContext);
        }
        return instance;
    }

    /**
     * Query for water column data at the given geometry
     * @param envelope - represents a buffered geometry around selected point in map
     * @param callback - SummaryCallback used when query is completed
     * @return a WaterColumn at the location within the geometry
     */
    public void queryForEmuAtLocation(Envelope envelope, ServiceApi.SummaryCallback callback) {
        QueryParameters queryParameters = new QueryParameters();
        queryParameters.setGeometry(envelope);
        ListenableFuture<FeatureQueryResult> futureResult = mMeshClusterTable.queryFeaturesAsync(queryParameters,
                ServiceFeatureTable.QueryFeatureFields.LOAD_ALL);
        processQueryForEMuAtLocation(envelope, futureResult, callback);
    }

    /**
     * Process the listenable future by creating a WaterColumn for
     * any returned data.
     * @param envelope - an Envelope representing the search area
     * @param futureResult - a ListenableFuture<FeatureQueryResult> to process
     * @param callback  - a SummaryCallback called when query processing is complete
     * @return - a WaterColumn representing returned features.
     */
    private void processQueryForEMuAtLocation(final Envelope envelope,
            final ListenableFuture<FeatureQueryResult> futureResult, final ServiceApi.SummaryCallback callback) {

        futureResult.addDoneListener(new Runnable() {
            @Override
            public void run() {
                try {
                    Log.i("ProcessQuery", "Query done...");
                    FeatureQueryResult fqr = futureResult.get();

                    Map<Geometry, WaterColumn> pointWaterColumnMap = new HashMap<Geometry, WaterColumn>();

                    if (fqr != null) {
                        Log.i("ProcessQuery", "Processing features...");

                        List<EMUObservation> emuObservations = new ArrayList<EMUObservation>();
                        final Iterator<Feature> iterator = fqr.iterator();
                        while (iterator.hasNext()) {
                            Feature feature = iterator.next();
                            Geometry geometry = feature.getGeometry();
                            Map<String, Object> map = feature.getAttributes();
                            EMUObservation observation = createEMUObservation(map);
                            emuObservations.add(createEMUObservation(map));
                        }
                        // Now we have a list with zero or more EMUObservations
                        // 1.  Create a map of WaterColumn keyed on location
                        // 2.  Determine the closest WaterColumn to the envelope.

                        ImmutableSet<EMUObservation> immutableSet = ImmutableSet.copyOf(emuObservations);
                        Function<EMUObservation, Point> locationFunction = new Function<EMUObservation, Point>() {
                            @Nullable
                            @Override
                            public Point apply(EMUObservation observation) {
                                return observation.getLocation();
                            }
                        };
                        ImmutableListMultimap<Point, EMUObservation> observationsByLocation = Multimaps
                                .index(immutableSet, locationFunction);
                        ImmutableMap<Point, Collection<EMUObservation>> map = observationsByLocation.asMap();
                        Set<Point> keys = map.keySet();
                        Iterator<Point> pointIterator = keys.iterator();
                        while (pointIterator.hasNext()) {
                            Point p = pointIterator.next();
                            WaterColumn waterColumn = new WaterColumn();
                            waterColumn.setLocation(p);
                            ;
                            Collection<EMUObservation> observations = map.get(p);
                            for (EMUObservation o : observations) {
                                waterColumn.addObservation(o);
                            }
                            pointWaterColumnMap.put(p, waterColumn);
                        }
                    }

                    // If there is more than one water column, we only care about the
                    // one closest to the point clicked in the map.
                    WaterColumn closestWaterColumn = findClosestWaterColumn(envelope, pointWaterColumnMap);

                    // Processing is complete, notify the callback
                    callback.onWaterColumnsLoaded(closestWaterColumn);

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void addToWaterColumnCache(WaterColumn waterColumn) {
        cache.put(waterColumn.getLocation(), waterColumn);
    }

    public WaterColumn getFromWaterColumnCache(Point location) {
        WaterColumn waterColumn = null;
        if (cache.containsKey(location)) {
            waterColumn = cache.get(location);
        }
        return waterColumn;
    }

    /**
     * Given a Map containing strings as keys and objects as values,
     * create an EMUObservation
     * @param map Map<String,Object> representing field values indexed by field names
     * @return an EMUObservation for map.
     */
    private EMUObservation createEMUObservation(Map<String, Object> map) {
        EMUObservation observation = new EMUObservation();

        EMU emu = new EMU();
        observation.setEmu(emu);

        // Set emu number
        Integer emuNumber = Integer.parseInt(extractValueFromMap(mContext.getString(R.string.emu_number), map));
        emu.setName(emuNumber);

        // Set descriptive name
        String emuName = extractValueFromMap(mContext.getString(R.string.name_emu), map);

        // Get the physical and nutrient summaries which are concatenated in the emuName
        String[] results = emuName.split(" with ");
        if (results.length == 2) {
            emu.setPhysicalSummary(results[0]);
            emu.setNutrientSummary(results[1]);
        } else {
            emu.setPhysicalSummary("not found");
            emu.setNutrientSummary("not found");
        }

        // Set geomorphology base for emu
        String geoBase = extractValueFromMap(mContext.getString(R.string.geo_base), map);
        emu.setGeomorphologyBase(geoBase);

        // Set geomorphology features
        String geoFeatures = extractValueFromMap(mContext.getString(R.string.geo_features), map);
        emu.setGeomorphologyFeatures(geoFeatures);

        // Set the top
        String tString = extractValueFromMap("UnitTop", map);
        observation.setTop(Integer.parseInt(tString));

        // Set the geoLocation
        double x = Double.parseDouble(extractValueFromMap(mContext.getString(R.string.point_x), map));
        double y = Double.parseDouble(extractValueFromMap(mContext.getString(R.string.point_y), map));
        Point point = new Point(x, y);
        observation.setLocation(point);

        // Set the thickness
        observation
                .setThickness(Integer.parseInt(extractValueFromMap(mContext.getString(R.string.thickness), map)));

        // Log.i("Observation", "observation: " + observation.toString());
        return observation;
    }

    /**
     * Get the string value from the map given the column name
     * @param columnName - a non-null String representing the name of the column in the map
     * @param map - a map of objects indexed by string
     * @return  - the string value, may be empty but not null.
     */
    private String extractValueFromMap(@NonNull String columnName, @NonNull Map<String, Object> map) {
        String value = "";
        if (map.containsKey(columnName) && map.get(columnName) != null) {
            value = map.get(columnName).toString();
        }
        return value;
    }

    private WaterColumn findClosestWaterColumn(final Envelope envelope,
            final Map<Geometry, WaterColumn> waterColumnMap) {
        WaterColumn closestWaterColumn = null;
        if (waterColumnMap.size() == 1) {
            WaterColumn[] columns = waterColumnMap.values().toArray(new WaterColumn[1]);
            closestWaterColumn = columns[0];
        }
        if (waterColumnMap.size() > 1) {
            Point center = envelope.getCenter();
            LinearUnit linearUnit = new LinearUnit(LinearUnitId.METERS);
            AngularUnit angularUnit = new AngularUnit(AngularUnitId.DEGREES);
            Set<Geometry> geometries = waterColumnMap.keySet();
            Iterator<Geometry> iterator = geometries.iterator();
            double distance = 0;
            List<WaterColumn> waterColumnList = new ArrayList<>();
            while (iterator.hasNext()) {
                Geometry geo = iterator.next();
                WaterColumn waterColumn = waterColumnMap.get(geo);
                Point point = (Point) geo;
                Point waterColumnPoint = new Point(point.getX(), point.getY(), center.getSpatialReference());
                GeodeticDistanceResult geodeticDistanceResult = GeometryEngine.distanceGeodetic(center,
                        waterColumnPoint, linearUnit, angularUnit, GeodeticCurveType.GEODESIC);
                double calculatedDistance = geodeticDistanceResult.getDistance();
                waterColumn.setDistanceFrom(calculatedDistance);
                waterColumnList.add(waterColumn);
                //  Log.i("DistanceFrom", "Distance = " + calculatedDistance);
            }
            // Sort water columns
            Collections.sort(waterColumnList);
            closestWaterColumn = waterColumnList.get(0);
            WaterColumn furthers = waterColumnList.get(waterColumnList.size() - 1);
            // Log.i("Distances", "Closest = " + closestWaterColumn.getDistanceFrom()+ " furthest =" + furthers.getDistanceFrom() );
        }

        return closestWaterColumn;
    }

}