package org.mtransit.android.task;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.mtransit.android.commons.CollectionUtils;
import org.mtransit.android.commons.MTLog;
import org.mtransit.android.commons.RuntimeUtils;
import org.mtransit.android.commons.data.RouteTripStop;
import org.mtransit.android.commons.provider.POIProviderContract;
import org.mtransit.android.commons.task.MTCallable;
import org.mtransit.android.data.AgencyProperties;
import org.mtransit.android.data.DataSourceManager;
import org.mtransit.android.data.DataSourceProvider;
import org.mtransit.android.data.DataSourceType;
import org.mtransit.android.data.POIManager;
import org.mtransit.android.ui.view.MapViewController;
import android.content.Context;
import android.support.v4.util.ArrayMap;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
public class MapPOILoader extends MTAsyncTaskLoaderV4<Collection<MapViewController.POIMarker>> {
private static final String TAG = MapPOILoader.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private Collection<Integer> filterTypeIds;
private LatLngBounds latLngBounds;
private LatLngBounds loadedLatLngBounds;
private Collection<MapViewController.POIMarker> poiMarkers;
public MapPOILoader(Context context, Collection<Integer> filterTypeIds, LatLngBounds latLngBounds, LatLngBounds loadedLatLngBounds) {
super(context);
this.filterTypeIds = filterTypeIds;
this.latLngBounds = latLngBounds;
this.loadedLatLngBounds = loadedLatLngBounds;
}
@Override
public Collection<MapViewController.POIMarker> loadInBackgroundMT() {
if (this.poiMarkers != null) {
return this.poiMarkers;
}
this.poiMarkers = new HashSet<MapViewController.POIMarker>();
ArrayList<AgencyProperties> agencies = DataSourceProvider.get(getContext()).getAllAgencies(getContext());
if (CollectionUtils.getSize(agencies) == 0) {
return this.poiMarkers;
}
if (this.latLngBounds == null) {
return this.poiMarkers;
}
ThreadPoolExecutor executor = new ThreadPoolExecutor(RuntimeUtils.NUMBER_OF_CORES, RuntimeUtils.NUMBER_OF_CORES, 1, TimeUnit.SECONDS,
new LinkedBlockingDeque<Runnable>(agencies.size()));
ArrayList<Future<ArrayMap<LatLng, MapViewController.POIMarker>>> taskList = new ArrayList<Future<ArrayMap<LatLng, MapViewController.POIMarker>>>();
for (AgencyProperties agency : agencies) {
DataSourceType type = agency.getType();
if (!type.isMapScreen()) {
continue;
}
if (!agency.isInArea(this.latLngBounds)) {
continue;
}
if (agency.isEntirelyInside(this.loadedLatLngBounds)) {
continue;
}
if (CollectionUtils.getSize(this.filterTypeIds) > 0 && !this.filterTypeIds.contains(type.getId())) {
continue;
}
FindAgencyPOIsTask task = new FindAgencyPOIsTask(getContext(), agency, this.latLngBounds, this.loadedLatLngBounds);
taskList.add(executor.submit(task));
}
ArrayMap<LatLng, MapViewController.POIMarker> positionToPoiMarkers = new ArrayMap<LatLng, MapViewController.POIMarker>();
for (Future<ArrayMap<LatLng, MapViewController.POIMarker>> future : taskList) {
try {
ArrayMap<LatLng, MapViewController.POIMarker> agencyPOIs = future.get();
if (agencyPOIs != null) {
for (ArrayMap.Entry<LatLng, MapViewController.POIMarker> agencyMarker : agencyPOIs.entrySet()) {
if (positionToPoiMarkers.containsKey(agencyMarker.getKey())) {
positionToPoiMarkers.get(agencyMarker.getKey()).merge(agencyMarker.getValue());
} else {
positionToPoiMarkers.put(agencyMarker.getKey(), agencyMarker.getValue());
}
}
}
} catch (Exception e) {
MTLog.w(this, e, "Error while loading in background!");
}
}
executor.shutdown();
this.poiMarkers = positionToPoiMarkers.values();
return this.poiMarkers;
}
@Override
protected void onStartLoading() {
super.onStartLoading();
if (this.poiMarkers != null) {
deliverResult(this.poiMarkers);
}
if (this.poiMarkers == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
super.onStopLoading();
cancelLoad();
}
@Override
public void deliverResult(Collection<MapViewController.POIMarker> data) {
this.poiMarkers = data;
if (isStarted()) {
super.deliverResult(data);
}
}
private static class FindAgencyPOIsTask extends MTCallable<ArrayMap<LatLng, MapViewController.POIMarker>> {
private static final String TAG = MapPOILoader.class.getSimpleName() + ">" + FindAgencyPOIsTask.class.getSimpleName();
@Override
public String getLogTag() {
return TAG;
}
private Context context;
private AgencyProperties agency;
private LatLngBounds latLngBounds;
private LatLngBounds loadedLatLngBounds;
public FindAgencyPOIsTask(Context context, AgencyProperties agency, LatLngBounds latLngBounds, LatLngBounds loadedLatLngBounds) {
this.context = context;
this.agency = agency;
this.latLngBounds = latLngBounds;
this.loadedLatLngBounds = loadedLatLngBounds;
}
@Override
public ArrayMap<LatLng, MapViewController.POIMarker> callMT() throws Exception {
double minLat = Math.min(this.latLngBounds.northeast.latitude, this.latLngBounds.southwest.latitude);
double maxLat = Math.max(this.latLngBounds.northeast.latitude, this.latLngBounds.southwest.latitude);
double minLng = Math.min(this.latLngBounds.northeast.longitude, this.latLngBounds.southwest.longitude);
double maxLng = Math.max(this.latLngBounds.northeast.longitude, this.latLngBounds.southwest.longitude);
Double optLoadedMinLat = this.loadedLatLngBounds == null ? null : Math.min(this.loadedLatLngBounds.northeast.latitude,
this.loadedLatLngBounds.southwest.latitude);
Double optLoadedMaxLat = this.loadedLatLngBounds == null ? null : Math.max(this.loadedLatLngBounds.northeast.latitude,
this.loadedLatLngBounds.southwest.latitude);
Double optLoadedMinLng = this.loadedLatLngBounds == null ? null : Math.min(this.loadedLatLngBounds.northeast.longitude,
this.loadedLatLngBounds.southwest.longitude);
Double optLoadedMaxLng = this.loadedLatLngBounds == null ? null : Math.max(this.loadedLatLngBounds.northeast.longitude,
this.loadedLatLngBounds.southwest.longitude);
POIProviderContract.Filter poiFilter = POIProviderContract.Filter.getNewAreaFilter(minLat, maxLat, minLng, maxLng, optLoadedMinLat,
optLoadedMaxLat, optLoadedMinLng, optLoadedMaxLng);
ArrayMap<LatLng, MapViewController.POIMarker> clusterItems = new ArrayMap<LatLng, MapViewController.POIMarker>();
ArrayList<POIManager> poims = DataSourceManager.findPOIs(this.context, this.agency.getAuthority(), poiFilter);
String agencyShortName = this.agency.getShortName();
if (poims != null) {
LatLng position;
LatLng positionTrunc;
String name;
String extra;
String uuid;
String authority;
Integer color;
Integer secondaryColor;
for (POIManager poim : poims) {
position = MapViewController.POIMarker.getLatLng(poim);
positionTrunc = MapViewController.POIMarker.getLatLngTrunc(poim);
if (!this.latLngBounds.contains(position)) {
continue;
} else if (this.loadedLatLngBounds != null && this.loadedLatLngBounds.contains(position)) {
continue;
}
name = poim.poi.getName();
extra = null;
if (poim.poi instanceof RouteTripStop) {
extra = ((RouteTripStop) poim.poi).getRoute().getShortestName();
}
uuid = poim.poi.getUUID();
authority = poim.poi.getAuthority();
color = POIManager.getColor(this.context, poim.poi, null);
secondaryColor = agency.getColorInt();
if (clusterItems.containsKey(positionTrunc)) {
clusterItems.get(positionTrunc).merge(position, name, agencyShortName, extra, color, secondaryColor, uuid, authority);
} else {
clusterItems.put(positionTrunc, new MapViewController.POIMarker(position, name, agencyShortName, extra, color, secondaryColor, uuid,
authority));
}
}
}
return clusterItems;
}
}
}