package net.pterodactylus.rhynodge.states;
+import java.time.Clock;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import net.pterodactylus.rhynodge.Reaction;
import net.pterodactylus.rhynodge.State;
+import net.pterodactylus.rhynodge.output.DefaultOutput;
+import net.pterodactylus.rhynodge.output.Output;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.google.common.escape.Escaper;
+import com.google.common.html.HtmlEscapers;
/**
* Abstract implementation of a {@link State} that knows about the basic
private final long time;
/** Whether the state was successfully retrieved. */
+ @JsonProperty
private final boolean success;
+ private final boolean empty;
/** The optional exception that occured while retrieving the state. */
private final Throwable exception;
* otherwise
*/
protected AbstractState(boolean success) {
- this(success, null);
+ this(Clock.systemUTC(), success);
+ }
+
+ /**
+ * Creates a new state.
+ *
+ * @param clock The clock for generating {@link #time}
+ * @param success {@code true} if the state is successful, {@code false}
+ * otherwise
+ */
+ protected AbstractState(Clock clock, boolean success) {
+ this(clock, success, true, null);
+ }
+
+ protected AbstractState(boolean success, boolean empty) {
+ this(Clock.systemUTC(), success, empty);
+ }
+
+ protected AbstractState(Clock clock, boolean success, boolean empty) {
+ this(clock, success, empty, null);
}
/**
* The exception that occured while retrieving the state
*/
protected AbstractState(Throwable exception) {
- this(false, exception);
+ this(Clock.systemUTC(), exception);
+ }
+
+ /**
+ * Creates a new non-successful state with the given exception.
+ *
+ * @param clock The clock for generating {@link #time}
+ * @param exception The exception that occured while retrieving the state
+ */
+ protected AbstractState(Clock clock, Throwable exception) {
+ this(clock, false, true, exception);
}
/**
* @param exception
* The exception that occured while retrieving the state
*/
- protected AbstractState(boolean success, Throwable exception) {
- this.time = System.currentTimeMillis();
+ protected AbstractState(boolean success, boolean empty, Throwable exception) {
+ this(Clock.systemUTC(), success, empty, exception);
+ }
+
+ /**
+ * Creates a new state.
+ *
+ * @param clock The clock for generating {@link #time}
+ * @param success {@code true} if the state is successful, {@code false}
+ * otherwise
+ * @param exception The exception that occured while retrieving the state
+ */
+ protected AbstractState(Clock clock, boolean success, boolean empty, Throwable exception) {
+ this.time = clock.millis();
this.success = success;
+ this.empty = empty;
this.exception = exception;
}
return success;
}
+ @Override
+ public boolean isEmpty() {
+ return empty;
+ }
+
/**
* {@inheritDoc}
*/
return exception;
}
+ @Nonnull
+ @Override
+ public Output output(Reaction reaction) {
+ return new DefaultOutput(summary(reaction))
+ .addText("text/plain", plainText())
+ .addText("text/html", htmlText());
+ }
+
+ @Nonnull
+ protected String summary(Reaction reaction) {
+ return reaction.name();
+ }
+
+ @Nonnull
+ protected abstract String plainText();
+
+ @Nullable
+ protected String htmlText() {
+ //noinspection UnstableApiUsage
+ return "<div>" + htmlEscaper.escape(plainText()) + "</div>";
+ }
+
+ @SuppressWarnings("UnstableApiUsage")
+ private static final Escaper htmlEscaper = HtmlEscapers.htmlEscaper();
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(success, empty, time, failCount, exception);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof AbstractState)) {
+ return false;
+ }
+ AbstractState abstractState = (AbstractState) object;
+ return (success == abstractState.success) && (empty == abstractState.empty) && (time == abstractState.time) && (failCount == abstractState.failCount) && Objects.equals(exception, abstractState.exception);
+ }
+
}