package cgeo.geocaching.staticmaps;
import cgeo.geocaching.Intents;
import cgeo.geocaching.R;
import cgeo.geocaching.activity.AbstractListActivity;
import cgeo.geocaching.enumerations.LoadFlags;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.models.Waypoint;
import cgeo.geocaching.storage.DataStore;
import cgeo.geocaching.ui.dialog.Dialogs;
import cgeo.geocaching.utils.Log;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.view.Menu;
import android.view.MenuItem;
import java.util.concurrent.Callable;
import io.reactivex.Maybe;
import io.reactivex.Observable;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Action;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.Extra;
import org.androidannotations.annotations.OptionsItem;
@EActivity
public class StaticMapsActivity extends AbstractListActivity {
@Extra(Intents.EXTRA_DOWNLOAD)
boolean download = false;
@Extra(Intents.EXTRA_WAYPOINT_ID)
Integer waypointId = null;
@Extra(Intents.EXTRA_GEOCODE)
String geocode = null;
private Geocache cache;
private ProgressDialog waitDialog = null;
private StaticMapsAdapter adapter;
private MenuItem menuRefresh;
private CompositeDisposable resumeDisposables = new CompositeDisposable();
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState, R.layout.staticmaps_activity);
}
@Override
public void onStart() {
super.onStart();
cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB);
if (cache == null) {
Log.e("StaticMapsActivity.onCreate: cannot find the cache " + geocode);
finish();
return;
}
setCacheTitleBar(cache);
adapter = new StaticMapsAdapter(this);
setListAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(final Menu menu) {
getMenuInflater().inflate(R.menu.static_maps_activity_options, menu);
menuRefresh = menu.findItem(R.id.menu_refresh);
return super.onCreateOptionsMenu(menu);
}
@Override
public void onResume() {
super.onResume();
adapter.clear();
final Disposable load = loadAndDisplay();
resumeDisposables.add(load);
waitDialog = ProgressDialog.show(this, null, res.getString(R.string.map_static_loading), true);
waitDialog.setCancelable(true);
waitDialog.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(final DialogInterface dialog) {
load.dispose();
}
});
}
@Override
public void onPause() {
resumeDisposables.clear();
super.onPause();
}
@NonNull
private Disposable loadAndDisplay() {
return loadMaps().observeOn(AndroidSchedulers.mainThread()).map(new Function<Bitmap, Bitmap>() {
@Override
public Bitmap apply(final Bitmap bitmap) throws Exception {
adapter.add(bitmap);
return bitmap;
}
}).ignoreElements().subscribe(new Action() {
@Override
public void run() {
Dialogs.dismiss(waitDialog);
if (adapter.isEmpty()) {
if (download) {
resumeDisposables.add(downloadStaticMaps().subscribe(new Consumer<Boolean>() {
@Override
public void accept(final Boolean succeeded) throws Exception {
if (succeeded) {
// Loading from disk will succeed this time
AndroidSchedulers.mainThread().scheduleDirect(new Runnable() {
@Override
public void run() {
adapter.clear();
resumeDisposables.add(loadAndDisplay());
}
});
} else {
showToast(res.getString(R.string.err_detail_google_maps_limit_reached));
}
}
}));
} else {
showToast(res.getString(R.string.err_detail_not_load_map_static));
finish();
}
} else if (menuRefresh != null) {
menuRefresh.setEnabled(true);
}
}
});
}
private Observable<Bitmap> loadMaps() {
return Observable.range(1, StaticMapsProvider.MAPS_LEVEL_MAX).concatMap(new Function<Integer, Observable<Bitmap>>() {
@Override
public Observable<Bitmap> apply(final Integer zoomLevel) throws Exception {
return Maybe.fromCallable(new Callable<Bitmap>() {
@Override
public Bitmap call() throws Exception {
return waypointId != null ?
StaticMapsProvider.getWaypointMap(geocode, cache.getWaypointById(waypointId), zoomLevel) :
StaticMapsProvider.getCacheMap(geocode, zoomLevel);
}
}).toObservable().subscribeOn(Schedulers.io());
}
});
}
@OptionsItem(R.id.menu_refresh)
void refreshMaps() {
menuRefresh.setEnabled(false);
downloadStaticMaps().toCompletable().observeOn(AndroidSchedulers.mainThread()).subscribe(new Action() {
@Override
public void run() throws Exception {
menuRefresh.setEnabled(true);
loadMaps();
}
});
}
private Single<Boolean> downloadStaticMaps() {
if (waypointId == null) {
showToast(res.getString(R.string.info_storing_static_maps));
return StaticMapsProvider.storeCacheStaticMap(cache).andThen(Single.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return cache.hasStaticMap();
}
}));
}
final Waypoint waypoint = cache.getWaypointById(waypointId);
if (waypoint != null) {
showToast(res.getString(R.string.info_storing_static_maps));
// refresh always removes old waypoint files
StaticMapsProvider.removeWpStaticMaps(waypoint, geocode);
return StaticMapsProvider.storeWaypointStaticMap(cache, waypoint).andThen(Single.fromCallable(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
return StaticMapsProvider.hasStaticMapForWaypoint(geocode, waypoint);
}
}));
}
showToast(res.getString(R.string.err_detail_not_load_map_static));
return Single.just(false);
}
@Override
public void finish() {
Dialogs.dismiss(waitDialog);
super.finish();
}
}