package cgeo.geocaching.ui;
import cgeo.geocaching.R;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.location.Units;
import cgeo.geocaching.log.LogEntry;
import cgeo.geocaching.log.LogType;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.models.ICoordinates;
import cgeo.geocaching.models.Waypoint;
import cgeo.geocaching.sensors.Sensors;
import cgeo.geocaching.utils.Formatter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import android.support.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.Resources;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RatingBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import butterknife.ButterKnife;
// TODO The suppression of this lint finding is bad. But to fix it, someone needs to rework the layout of the cache
// details also, not just only change the code here.
@SuppressLint("InflateParams")
public final class CacheDetailsCreator {
private final Activity activity;
private final ViewGroup parentView;
private final Resources res;
public CacheDetailsCreator(final Activity activity, final ViewGroup parentView) {
this.activity = activity;
this.res = activity.getResources();
this.parentView = parentView;
parentView.removeAllViews();
}
/**
* Create a "name: value" line.
*
* @param nameId the resource of the name field
* @param value the initial value
* @return a pair made of the whole "name: value" line (to be able to hide it for example) and of the value (to update it)
*/
public ImmutablePair<RelativeLayout, TextView> add(final int nameId, final CharSequence value) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null, false);
final TextView nameView = ButterKnife.findById(layout, R.id.name);
nameView.setText(res.getString(nameId));
final TextView valueView = ButterKnife.findById(layout, R.id.value);
valueView.setText(value);
parentView.addView(layout);
return ImmutablePair.of(layout, valueView);
}
public RelativeLayout addStars(final int nameId, final float value) {
return addStars(nameId, value, 5);
}
private RelativeLayout addStars(final int nameId, final float value, final int max) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null, false);
final TextView nameView = ButterKnife.findById(layout, R.id.name);
final TextView valueView = ButterKnife.findById(layout, R.id.value);
nameView.setText(activity.getString(nameId));
valueView.setText(String.format(Locale.getDefault(), "%.1f", value) + ' ' + activity.getString(R.string.cache_rating_of) + ' ' + String.format(Locale.getDefault(), "%d", max));
final RatingBar layoutStars = ButterKnife.findById(layout, R.id.stars);
layoutStars.setNumStars(max);
layoutStars.setRating(value);
layoutStars.setVisibility(View.VISIBLE);
parentView.addView(layout);
return layout;
}
public void addCacheState(final Geocache cache) {
final List<String> states = new ArrayList<>(5);
String date = getVisitedDate(cache);
if (cache.isLogOffline()) {
states.add(res.getString(R.string.cache_status_offline_log) + date);
// reset the found date, to avoid showing it twice
date = "";
}
if (cache.isFound()) {
states.add(res.getString(R.string.cache_status_found) + date);
}
if (cache.isEventCache() && states.isEmpty()) {
for (final LogEntry log : cache.getLogs()) {
if (log.getType() == LogType.WILL_ATTEND && log.isOwn()) {
states.add(LogType.WILL_ATTEND.getL10n());
}
}
}
if (cache.isArchived()) {
states.add(res.getString(R.string.cache_status_archived));
}
if (cache.isDisabled()) {
states.add(res.getString(R.string.cache_status_disabled));
}
if (cache.isPremiumMembersOnly()) {
states.add(res.getString(R.string.cache_status_premium));
}
if (!states.isEmpty()) {
add(R.string.cache_status, StringUtils.join(states, ", "));
}
}
private static String getVisitedDate(final Geocache cache) {
final long visited = cache.getVisitedDate();
return visited != 0 ? " (" + Formatter.formatShortDate(visited) + ")" : "";
}
private static Float distanceNonBlocking(final ICoordinates target) {
if (target.getCoords() == null) {
return null;
}
return Sensors.getInstance().currentGeo().getCoords().distanceTo(target);
}
public void addRating(final Geocache cache) {
if (cache.getRating() > 0) {
final RelativeLayout itemLayout = addStars(R.string.cache_rating, cache.getRating());
if (cache.getVotes() > 0) {
final TextView itemAddition = ButterKnife.findById(itemLayout, R.id.addition);
itemAddition.setText(" (" + cache.getVotes() + ')');
itemAddition.setVisibility(View.VISIBLE);
}
}
}
public void addSize(final Geocache cache) {
if (cache.showSize()) {
add(R.string.cache_size, cache.getSize().getL10n());
}
}
public void addDifficulty(final Geocache cache) {
if (cache.getDifficulty() > 0) {
addStars(R.string.cache_difficulty, cache.getDifficulty());
}
}
public void addTerrain(final Geocache cache) {
if (cache.getTerrain() > 0) {
addStars(R.string.cache_terrain, cache.getTerrain(), ConnectorFactory.getConnector(cache).getMaxTerrain());
}
}
public TextView addDistance(final Geocache cache, final TextView cacheDistanceView) {
Float distance = distanceNonBlocking(cache);
if (distance == null && cache.getDistance() != null) {
distance = cache.getDistance();
}
String text = "--";
if (distance != null) {
text = Units.getDistanceFromKilometers(distance);
} else if (cacheDistanceView != null) {
// if there is already a distance in cacheDistance, use it instead of resetting to default.
// this prevents displaying "--" while waiting for a new position update (See bug #1468)
text = cacheDistanceView.getText().toString();
}
return add(R.string.cache_distance, text).right;
}
public TextView addDistance(final Waypoint wpt, final TextView waypointDistanceView) {
final Float distance = distanceNonBlocking(wpt);
String text = "--";
if (distance != null) {
text = Units.getDistanceFromKilometers(distance);
} else if (waypointDistanceView != null) {
// if there is already a distance in waypointDistance, use it instead of resetting to default.
// this prevents displaying "--" while waiting for a new position update (See bug #1468)
text = waypointDistanceView.getText().toString();
}
return add(R.string.cache_distance, text).right;
}
public void addEventDate(@NonNull final Geocache cache) {
if (!cache.isEventCache()) {
return;
}
addHiddenDate(cache);
}
public TextView addHiddenDate(@NonNull final Geocache cache) {
final String dateString = Formatter.formatHiddenDate(cache);
if (StringUtils.isEmpty(dateString)) {
return null;
}
final TextView view = add(cache.isEventCache() ? R.string.cache_event : R.string.cache_hidden, dateString).right;
view.setId(R.id.date);
return view;
}
}