package mil.nga.giat.mage.observation;
import android.app.FragmentManager;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import org.apache.commons.lang3.StringUtils;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import mil.nga.giat.mage.R;
import mil.nga.giat.mage.form.LayoutBaker;
import mil.nga.giat.mage.form.LayoutBaker.ControlGenerationType;
import mil.nga.giat.mage.map.marker.ObservationBitmapFactory;
import mil.nga.giat.mage.people.PeopleActivity;
import mil.nga.giat.mage.sdk.datastore.observation.Attachment;
import mil.nga.giat.mage.sdk.datastore.observation.Observation;
import mil.nga.giat.mage.sdk.datastore.observation.ObservationFavorite;
import mil.nga.giat.mage.sdk.datastore.observation.ObservationHelper;
import mil.nga.giat.mage.sdk.datastore.observation.ObservationImportant;
import mil.nga.giat.mage.sdk.datastore.observation.ObservationProperty;
import mil.nga.giat.mage.sdk.datastore.user.Event;
import mil.nga.giat.mage.sdk.datastore.user.EventHelper;
import mil.nga.giat.mage.sdk.datastore.user.Permission;
import mil.nga.giat.mage.sdk.datastore.user.User;
import mil.nga.giat.mage.sdk.datastore.user.UserHelper;
import mil.nga.giat.mage.sdk.event.IObservationEventListener;
import mil.nga.giat.mage.sdk.exceptions.ObservationException;
import mil.nga.giat.mage.sdk.exceptions.UserException;
import mil.nga.giat.mage.utils.DateFormatFactory;
public class ObservationViewActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String LOG_NAME = ObservationViewActivity.class.getName();
public static String OBSERVATION_ID = "OBSERVATION_ID";
public static String INITIAL_LOCATION = "INITIAL_LOCATION";
public static String INITIAL_ZOOM = "INITIAL_ZOOM";
private DateFormat dateFormat;
private GoogleMap map;
private AttachmentGallery attachmentGallery;
private IObservationEventListener observationEventListener;
private Observation o;
private User currentUser;
private boolean canEditObservation = false;
private Marker marker;
private DecimalFormat latLngFormat = new DecimalFormat("###.#####");
SharedPreferences preferences;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
dateFormat = DateFormatFactory.format("yyyy-MM-dd HH:mm zz", Locale.getDefault(), getApplicationContext());
setContentView(R.layout.observation_viewer);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Event event = EventHelper.getInstance(getApplicationContext()).getCurrentEvent();
if (event != null) {
getSupportActionBar().setSubtitle(event.getName());
}
try {
LayoutBaker.populateLayoutWithControls((LinearLayout) findViewById(R.id.propertyContainer), LayoutBaker.createControlsFromJson(this, ControlGenerationType.VIEW, ObservationHelper.getInstance(getApplicationContext()).read(getIntent().getLongExtra(OBSERVATION_ID, 0L)).getEvent().getForm()));
} catch(Exception e) {
Log.e(LOG_NAME, "Problem getting observation.", e);
}
try {
User user = UserHelper.getInstance(getApplicationContext()).readCurrentUser();
Collection<Permission> permissions = user.getRole().getPermissions().getPermissions();
canEditObservation = permissions.contains(Permission.UPDATE_OBSERVATION_ALL) || permissions.contains(Permission.UPDATE_OBSERVATION_EVENT);
} catch (UserException e) {
Log.e(LOG_NAME, "Cannot read current user", e);
}
final FloatingActionButton editButton = (FloatingActionButton) findViewById(R.id.edit_button);
editButton.setVisibility(canEditObservation ? View.VISIBLE : View.GONE);
editButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
editObservation();
}
});
observationEventListener = new IObservationEventListener() {
@Override
public void onObservationUpdated(Observation observation) {
updateObservation(Collections.singletonList(observation));
}
@Override
public void onObservationCreated(Collection<Observation> observations, Boolean sendUserNotifications) {
updateObservation(observations);
}
private void updateObservation(Collection<Observation> observations) {
if (map == null) return;
for (Observation observation : observations) {
if (o == null || (observation.getId().equals(o.getId()) && !observation.getLastModified().equals(o.getLastModified()))) {
ObservationViewActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
setupObservation();
}
});
}
}
}
@Override
public void onObservationDeleted(Observation observation) {
}
@Override
public void onError(Throwable error) {
}
};
ObservationHelper.getInstance(getApplicationContext()).addListener(observationEventListener);
((MapFragment) getFragmentManager().findFragmentById(R.id.mini_map)).getMapAsync(this);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
this.finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onDestroy() {
if (observationEventListener != null) {
ObservationHelper.getInstance(getApplicationContext()).removeListener(observationEventListener);
}
super.onDestroy();
}
@Override
public void onMapReady(GoogleMap map) {
this.map = map;
setupObservation();
}
private void setupObservation() {
try {
final ImageView favoriteIcon = (ImageView) findViewById(R.id.favoriteIcon);
if (o == null) {
favoriteIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
toggleFavorite(o, favoriteIcon);
}
});
findViewById(R.id.directions).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getDirections();
}
});
findViewById(R.id.favorites).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onFavoritesClick(o.getFavorites());
}
});
}
o = ObservationHelper.getInstance(getApplicationContext()).read(getIntent().getLongExtra(OBSERVATION_ID, 0L));
Map<String, ObservationProperty> propertiesMap = o.getPropertiesMap();
ObservationProperty observationProperty = propertiesMap.get("type");
if (observationProperty != null) {
this.setTitle(observationProperty.getValue().toString());
}
Geometry geo = o.getGeometry();
if (geo instanceof Point) {
Point pointGeo = (Point) geo;
((TextView) findViewById(R.id.location)).setText(latLngFormat.format(pointGeo.getY()) + ", " + latLngFormat.format(pointGeo.getX()));
if (propertiesMap.containsKey("provider")) {
((TextView) findViewById(R.id.location_provider)).setText("(" + propertiesMap.get("provider").getValue() + ")");
} else {
findViewById(R.id.location_provider).setVisibility(View.GONE);
}
if (propertiesMap.containsKey("accuracy") && Float.parseFloat(propertiesMap.get("accuracy").getValue().toString()) > 0f) {
((TextView) findViewById(R.id.location_accuracy)).setText("\u00B1" + propertiesMap.get("accuracy").getValue().toString() + "m");
} else {
findViewById(R.id.location_accuracy).setVisibility(View.GONE);
}
map.getUiSettings().setZoomControlsEnabled(false);
if (marker == null) {
LatLng latLng = getIntent().getParcelableExtra(INITIAL_LOCATION);
if (latLng == null) {
latLng = new LatLng(0, 0);
}
float zoom = getIntent().getFloatExtra(INITIAL_ZOOM, 0);
map.moveCamera(CameraUpdateFactory.newLatLngZoom(latLng, zoom));
LatLng location = new LatLng(pointGeo.getY(), pointGeo.getX());
map.animateCamera(CameraUpdateFactory.newLatLngZoom(location, 15));
marker = map.addMarker(new MarkerOptions().position(location).icon(ObservationBitmapFactory.bitmapDescriptor(this, o)));
} else {
LatLng location = new LatLng(pointGeo.getY(), pointGeo.getX());
map.moveCamera(CameraUpdateFactory.newLatLngZoom(location, map.getCameraPosition().zoom));
marker.setPosition(location);
}
}
setupImportant(o.getImportant());
setFavorites(o.getFavorites());
setFavoriteImage(favoriteIcon, isFavorite(o));
LayoutBaker.populateLayoutFromMap((LinearLayout) findViewById(R.id.propertyContainer), ControlGenerationType.VIEW, o.getPropertiesMap());
LayoutBaker.populateLayoutFromMap((LinearLayout) findViewById(R.id.topPropertyContainer), ControlGenerationType.VIEW, o.getPropertiesMap());
LinearLayout galleryLayout = (LinearLayout) findViewById(R.id.image_gallery);
galleryLayout.removeAllViews();
if (o.getAttachments().size() == 0) {
findViewById(R.id.gallery_container).setVisibility(View.GONE);
} else {
attachmentGallery = new AttachmentGallery(getApplicationContext(), 150, 150);
attachmentGallery.addOnAttachmentClickListener(new AttachmentGallery.OnAttachmentClickListener() {
@Override
public void onAttachmentClick(Attachment attachment) {
Intent intent = new Intent(getApplicationContext(), AttachmentViewerActivity.class);
intent.putExtra(AttachmentViewerActivity.ATTACHMENT_ID, attachment.getId());
intent.putExtra(AttachmentViewerActivity.EDITABLE, false);
startActivity(intent);
}
});
attachmentGallery.addAttachments(galleryLayout, o.getAttachments());
}
TextView user = (TextView) findViewById(R.id.username);
String userText = "Unknown User";
User u = UserHelper.getInstance(this).read(o.getUserId());
if (u != null) {
userText = u.getDisplayName();
}
user.setText(userText);
FrameLayout fl = (FrameLayout) findViewById(R.id.sync_status);
fl.removeAllViews();
if (o.isDirty()) {
View.inflate(getApplicationContext(), R.layout.saved_locally, fl);
} else {
View status = View.inflate(getApplicationContext(), R.layout.submitted_on, fl);
TextView syncDate = (TextView) status.findViewById(R.id.observation_sync_date);
syncDate.setText(dateFormat.format(o.getLastModified()));
}
} catch (Exception e) {
Log.e(LOG_NAME, e.getMessage(), e);
}
}
private void getDirections() {
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, o.getGoogleMapsUri());
startActivity(intent);
}
private void editObservation() {
if(!UserHelper.getInstance(getApplicationContext()).isCurrentUserPartOfCurrentEvent()) {
new AlertDialog.Builder(this).setTitle("Not a member of this event").setMessage("You are an administrator and not a member of the current event. You can not edit this observation.").setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
}).show();
} else {
Intent intent = new Intent(this, ObservationEditActivity.class);
intent.putExtra(ObservationEditActivity.OBSERVATION_ID, o.getId());
if (map != null) {
intent.putExtra(ObservationViewActivity.INITIAL_LOCATION, map.getCameraPosition().target);
intent.putExtra(ObservationViewActivity.INITIAL_ZOOM, map.getCameraPosition().zoom);
}
startActivityForResult(intent, 2);
}
}
private void setupImportant(ObservationImportant important) {
UserHelper userHelper = UserHelper.getInstance(getApplicationContext());
boolean isImportant = important != null && important.isImportant();
boolean canEdit = false;
try {
currentUser = userHelper.readCurrentUser();
canEdit = currentUser.getRole().getPermissions().getPermissions().contains(Permission.UPDATE_EVENT);
} catch (UserException e) {
Log.e(LOG_NAME, "Could not read current user", e);
}
View imporantView = findViewById(R.id.important);
if (isImportant) {
imporantView.setVisibility(View.VISIBLE);
String displayName = "Unknown user";
try {
User user = userHelper.read(important.getUserId());
displayName = user.getDisplayName();
} catch (UserException e) {
Log.e(LOG_NAME, "Error finding user with remote id: " + important.getUserId());
}
((TextView) findViewById(R.id.importantUser)).setText(String.format(getString(R.string.important_flagged_by), displayName));
DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault());
((TextView) findViewById(R.id.importantDate)).setText(dateFormat.format(important.getTimestamp()));
String description = important.getDescription();
TextView descriptionView = (TextView) findViewById(R.id.importantDescription);
descriptionView.setVisibility(StringUtils.isNoneEmpty(description) ? View.VISIBLE : View.GONE);
descriptionView.setText(description);
findViewById(R.id.addImportant).setVisibility(View.GONE);
findViewById(R.id.importantActions).setVisibility(canEdit ? View.VISIBLE : View.GONE);
} else {
imporantView.setVisibility(View.GONE);
findViewById(R.id.importantActions).setVisibility(View.GONE);
findViewById(R.id.addImportant).setVisibility(canEdit ? View.VISIBLE : View.GONE);
}
}
public void onUpdateImportantClick(View v) {
final ObservationImportant important = o.getImportant();
String description = important != null ? important.getDescription() : null;
ImportantDialog dialog = ImportantDialog.newInstance(description);
dialog.setOnImportantListener(new ImportantDialog.OnImportantListener() {
@Override
public void onImportant(String description) {
ObservationHelper observationHelper = ObservationHelper.getInstance(getApplicationContext());
try {
ObservationImportant important = o.getImportant();
if (important == null) {
important = new ObservationImportant();
o.setImportant(important);
}
if (currentUser != null) {
important.setUserId(currentUser.getRemoteId());
}
important.setTimestamp(new Date());
important.setDescription(description);
observationHelper.addImportant(o);
setupImportant(important);
} catch (ObservationException e) {
Log.e(LOG_NAME, "Error updating important flag for observation: " + o.getRemoteId());
}
}
});
FragmentManager fm = getFragmentManager();
dialog.show(fm, "important");
}
public void onRemoveImportantClick(View v) {
ImportantRemoveDialog dialog = new ImportantRemoveDialog();
dialog.setOnRemoveImportantListener(new ImportantRemoveDialog.OnRemoveImportantListener() {
@Override
public void onRemoveImportant() {
ObservationHelper observationHelper = ObservationHelper.getInstance(getApplicationContext());
try {
observationHelper.removeImportant(o);
setupImportant(o.getImportant());
} catch (ObservationException e) {
Log.e(LOG_NAME, "Error removing important flag for observation: " + o.getRemoteId());
}
}
});
FragmentManager fm = getFragmentManager();
dialog.show(fm, "remove_important");
}
private void onFavoritesClick(Collection<ObservationFavorite> favorites) {
Collection<String> userIds = Collections2.transform(favorites, new Function<ObservationFavorite, String>() {
@Override
public String apply(ObservationFavorite favorite) {
return favorite.getUserId();
}
});
Intent intent = new Intent(this, PeopleActivity.class);
intent.putStringArrayListExtra(PeopleActivity.USER_REMOTE_IDS, new ArrayList<>(userIds));
startActivity(intent);
}
private void toggleFavorite(Observation observation, ImageView imageView) {
ObservationHelper observationHelper = ObservationHelper.getInstance(getApplicationContext());
boolean isFavorite = isFavorite(observation);
try {
if (isFavorite) {
observationHelper.unfavoriteObservation(observation, currentUser);
} else {
observationHelper.favoriteObservation(observation, currentUser);
}
setFavoriteImage(imageView, !isFavorite);
} catch (ObservationException e) {
String text = isFavorite ? "Problem unfavoriting observation" : "Problem favoriting observation";
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_LONG).show();
Log.e(LOG_NAME, "Could not unfavorite observation", e);
}
}
private boolean isFavorite(Observation observation) {
boolean isFavorite = false;
try {
currentUser = UserHelper.getInstance(getApplicationContext()).readCurrentUser();
if (currentUser != null) {
ObservationFavorite favorite = observation.getFavoritesMap().get(currentUser.getRemoteId());
isFavorite = favorite != null && favorite.isFavorite();
}
} catch (UserException e) {
Log.e(LOG_NAME, "Could not get user", e);
}
return isFavorite;
}
private void setFavorites(Collection<ObservationFavorite> favorites) {
Integer favoritesCount = favorites.size();
findViewById(R.id.favorites).setVisibility(favoritesCount > 0 ? View.VISIBLE : View.GONE) ;
if (favoritesCount > 0) {
TextView favoriteCountView = (TextView) findViewById(R.id.favoritesCount);
favoriteCountView.setText(favoritesCount.toString());
TextView favoritesLabel = (TextView) findViewById(R.id.favoritesLabel);
favoritesLabel.setText(favoritesCount == 1 ? "FAVORITE" : "FAVORITES");
}
}
private void setFavoriteImage(ImageView imageView, boolean isFavorite) {
if (isFavorite) {
imageView.setColorFilter(ContextCompat.getColor(this, R.color.observation_favorite_active));
} else {
imageView.setColorFilter(ContextCompat.getColor(this, R.color.observation_favorite_inactive));
}
}
private void share(final Observation observation) {
new ObservationShareTask(this, observation).execute();
}
}