package cgeo.geocaching.log;
import cgeo.geocaching.R;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.capability.ILogin;
import cgeo.geocaching.models.Geocache;
import cgeo.geocaching.models.Trackable;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Formatter;
import org.apache.commons.lang3.StringUtils;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import java.util.ArrayList;
import java.util.List;
/**
* Provides all the available templates for logging.
*
*/
public final class LogTemplateProvider {
private LogTemplateProvider() {
// utility class
}
/**
* Context aware data container for log templates.
* <p>
* Some log templates need additional information. To provide that information, it can be encapsulated in this log
* context.
* </p>
*
*/
public static class LogContext {
private Geocache cache;
private Trackable trackable;
private boolean offline = false;
private final LogEntry logEntry;
public LogContext(final Geocache cache, final LogEntry logEntry) {
this(cache, logEntry, false);
}
public LogContext(final Trackable trackable, final LogEntry logEntry) {
this.trackable = trackable;
this.logEntry = logEntry;
}
public LogContext(final Geocache cache, final LogEntry logEntry, final boolean offline) {
this.cache = cache;
this.offline = offline;
this.logEntry = logEntry;
}
public final Geocache getCache() {
return cache;
}
public final Trackable getTrackable() {
return trackable;
}
public final boolean isOffline() {
return offline;
}
public final LogEntry getLogEntry() {
return logEntry;
}
}
public abstract static class LogTemplate {
private final String template;
@StringRes
private final int resourceId;
protected LogTemplate(final String template, @StringRes final int resourceId) {
this.template = template;
this.resourceId = resourceId;
}
public abstract String getValue(LogContext context);
@StringRes
public final int getResourceId() {
return resourceId;
}
public final int getItemId() {
return template.hashCode();
}
public final String getTemplateString() {
return template;
}
@NonNull
private String apply(@NonNull final String input, final LogContext context) {
final String bracketedTemplate = "[" + template + "]";
// check containment first to not unconditionally call the getValue(...) method
if (input.contains(bracketedTemplate)) {
return StringUtils.replace(input, bracketedTemplate, getValue(context));
}
return input;
}
}
/**
* @return all user-facing templates, but not the signature template itself
*/
@NonNull
public static List<LogTemplate> getTemplatesWithoutSignature() {
final List<LogTemplate> templates = new ArrayList<>();
templates.add(new LogTemplate("DATE", R.string.init_signature_template_date) {
@Override
public String getValue(final LogContext context) {
return Formatter.formatFullDate(System.currentTimeMillis());
}
});
templates.add(new LogTemplate("TIME", R.string.init_signature_template_time) {
@Override
public String getValue(final LogContext context) {
return Formatter.formatTime(System.currentTimeMillis());
}
});
templates.add(new LogTemplate("DATETIME", R.string.init_signature_template_datetime) {
@Override
public String getValue(final LogContext context) {
final long currentTime = System.currentTimeMillis();
return Formatter.formatFullDate(currentTime) + " " + Formatter.formatTime(currentTime);
}
});
templates.add(new LogTemplate("USER", R.string.init_signature_template_user) {
@Override
public String getValue(final LogContext context) {
final Geocache cache = context.getCache();
if (cache != null) {
final IConnector connector = ConnectorFactory.getConnector(cache);
if (connector instanceof ILogin) {
return ((ILogin) connector).getUserName();
}
}
return Settings.getUserName();
}
});
templates.add(new LogTemplate("NUMBER", R.string.init_signature_template_number) {
@Override
public String getValue(final LogContext context) {
return getCounter(context, true);
}
});
templates.add(new LogTemplate("OWNER", R.string.init_signature_template_owner) {
@Override
public String getValue(final LogContext context) {
final Trackable trackable = context.getTrackable();
if (trackable != null) {
return trackable.getOwner();
}
final Geocache cache = context.getCache();
if (cache != null) {
return cache.getOwnerDisplayName();
}
return StringUtils.EMPTY;
}
});
templates.add(new LogTemplate("NAME", R.string.init_signature_template_name) {
@Override
public String getValue(final LogContext context) {
final Trackable trackable = context.getTrackable();
if (trackable != null) {
return trackable.getName();
}
final Geocache cache = context.getCache();
if (cache != null) {
return cache.getName();
}
return StringUtils.EMPTY;
}
});
templates.add(new LogTemplate("URL", R.string.init_signature_template_url) {
@Override
public String getValue(final LogContext context) {
final Trackable trackable = context.getTrackable();
if (trackable != null) {
return trackable.getUrl();
}
final Geocache cache = context.getCache();
if (cache != null) {
return StringUtils.defaultString(cache.getUrl());
}
return StringUtils.EMPTY;
}
});
templates.add(new LogTemplate("LOG", R.string.init_signature_template_log) {
@Override
public String getValue(final LogContext context) {
final LogEntry logEntry = context.getLogEntry();
if (logEntry != null) {
return logEntry.getDisplayText();
}
return StringUtils.EMPTY;
}
});
return templates;
}
@NonNull
private static String getCounter(final LogContext context, final boolean incrementCounter) {
final Geocache cache = context.getCache();
if (cache == null) {
return StringUtils.EMPTY;
}
int current = 0;
final IConnector connector = ConnectorFactory.getConnector(cache);
if (connector instanceof ILogin) {
current = ((ILogin) connector).getCachesFound();
}
// try updating the login information, if the counter is zero
if (current == 0) {
if (context.isOffline()) {
return StringUtils.EMPTY;
}
if (connector instanceof ILogin) {
((ILogin) connector).login(null, null);
current = ((ILogin) connector).getCachesFound();
}
}
if (current >= 0) {
return String.valueOf(incrementCounter ? current + 1 : current);
}
return StringUtils.EMPTY;
}
/**
* @return all user-facing templates, including the signature template
*/
@NonNull
public static List<LogTemplate> getTemplatesWithSignature() {
final List<LogTemplate> templates = getTemplatesWithoutSignature();
templates.add(new LogTemplate("SIGNATURE", R.string.init_signature) {
@Override
public String getValue(final LogContext context) {
final String nestedTemplate = Settings.getSignature();
if (StringUtils.contains(nestedTemplate, "SIGNATURE")) {
return "invalid signature template";
}
return applyTemplates(nestedTemplate, context);
}
});
return templates;
}
@NonNull
private static List<LogTemplate> getAllTemplates() {
final List<LogTemplate> templates = getTemplatesWithSignature();
templates.add(new LogTemplate("NUMBER$NOINC", -1 /* Never user facing */) {
@Override
public String getValue(final LogContext context) {
return getCounter(context, false);
}
});
return templates;
}
@Nullable
public static LogTemplate getTemplate(final int itemId) {
for (final LogTemplate template : getAllTemplates()) {
if (template.getItemId() == itemId) {
return template;
}
}
return null;
}
public static String applyTemplates(@NonNull final String signature, final LogContext context) {
String result = signature;
for (final LogTemplate template : getAllTemplates()) {
result = template.apply(result, context);
}
return result;
}
public static String applyTemplatesNoIncrement(@NonNull final String signature, final LogContext context) {
return applyTemplates(signature.replace("[NUMBER]", "[NUMBER$NOINC]"), context);
}
}