package sk.stuba.fiit.perconik.utilities.concurrent;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import static java.lang.Long.compare;
import static java.lang.Long.parseLong;
import static java.util.concurrent.TimeUnit.DAYS;
import static java.util.concurrent.TimeUnit.HOURS;
import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;
import static com.google.common.base.Preconditions.checkNotNull;
public final class TimeValue implements Comparable<TimeValue>, Serializable {
private static final long serialVersionUID = 0L;
final long duration;
final TimeUnit unit;
TimeValue(final long duration, final TimeUnit unit) {
this.duration = duration;
this.unit = unit;
}
public static TimeValue of(final long duration, final TimeUnit unit) {
return new TimeValue(duration, checkNotNull(unit));
}
public static TimeValue fromString(final String value) {
final int length = value.length();
if (length < 2) {
throw new IllegalArgumentException();
}
int index = length - 1;
char last = value.charAt(index);
String part = value.substring(0, index);
if (last == 's') {
index --;
last = value.charAt(index);
part = value.substring(0, index);
if (last == 'n') {
return new TimeValue(parseLong(part), NANOSECONDS);
} else if (last == '\u00b5') {
return new TimeValue(parseLong(part), MILLISECONDS);
} else if (last == 'm') {
return new TimeValue(parseLong(part), MICROSECONDS);
} else {
return new TimeValue(parseLong(part), SECONDS);
}
} else if (last == 'm') {
return new TimeValue(parseLong(part), MINUTES);
} else if (last == 'h') {
return new TimeValue(parseLong(part), HOURS);
} else if (last == 'd') {
return new TimeValue(parseLong(part), DAYS);
}
throw new IllegalArgumentException();
}
public static String toString(final long duration, final TimeUnit unit) {
return duration + TimeUnits.toString(unit);
}
public static String toString(final Number duration, final TimeUnit unit) {
return toString(duration.longValue(), unit);
}
public int compareTo(final long duration, final TimeUnit unit) {
return compare(this.durationToNanos(), unit.toNanos(duration));
}
public int compareTo(final TimeValue value) {
return this.compareTo(this.duration, this.unit);
}
@Override
public boolean equals(@Nullable final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof TimeValue)) {
return false;
}
TimeValue other = (TimeValue) o;
return this.duration == other.duration && this.unit == other.unit;
}
@Override
public int hashCode() {
return 31 * (31 + (int) (this.duration ^ (this.duration >>> 32))) + this.unit.hashCode();
}
public TimeValue convert(final TimeUnit unit) {
return this.unit == unit ? this : new TimeValue(unit.convert(this.duration, this.unit), unit);
}
public void timedWait(final Object o) throws InterruptedException {
this.unit.timedWait(o, this.duration);
}
public void timedJoin(final Thread thread) throws InterruptedException {
this.unit.timedJoin(thread, this.duration);
}
public void sleep() throws InterruptedException {
this.unit.sleep(this.duration);
}
private static final class SerializationProxy implements Serializable {
private static final long serialVersionUID = 0L;
private final long duration;
private final TimeUnit unit;
SerializationProxy(final TimeValue value) {
this.duration = value.duration;
this.unit = value.unit;
}
private Object readResolve() throws InvalidObjectException {
try {
return of(this.duration, this.unit);
} catch (RuntimeException e) {
throw new InvalidObjectException("Unknown deserialization error");
}
}
}
@SuppressWarnings({"static-method", "unused"})
private void readObject(final ObjectInputStream in) throws InvalidObjectException {
throw new InvalidObjectException("Serialization proxy required");
}
private Object writeReplace() {
return new SerializationProxy(this);
}
public long duration() {
return this.duration;
}
public TimeValue duration(final long duration) {
return this.duration == duration ? this : new TimeValue(duration, this.unit);
}
public long durationToNanos() {
return this.unit.toNanos(this.duration);
}
public long durationToMicros() {
return this.unit.toMicros(this.duration);
}
public long durationToMillis() {
return this.unit.toMillis(this.duration);
}
public long durationToSeconds() {
return this.unit.toSeconds(this.duration);
}
public long durationToMinutes() {
return this.unit.toMinutes(this.duration);
}
public long durationToHours() {
return this.unit.toHours(this.duration);
}
public long durationToDays() {
return this.unit.toDays(this.duration);
}
public TimeUnit unit() {
return this.unit;
}
public TimeValue unit(final TimeUnit unit) {
return this.unit == unit ? this : of(this.duration, unit);
}
@Override
public String toString() {
return toString(this.duration, this.unit);
}
public TimeValue toNanos() {
return this.unit == NANOSECONDS ? this : of(this.durationToNanos(), NANOSECONDS);
}
public TimeValue toMicros() {
return this.unit == MICROSECONDS ? this : of(this.durationToMicros(), MICROSECONDS);
}
public TimeValue toMillis() {
return this.unit == MILLISECONDS ? this : of(this.durationToMillis(), MILLISECONDS);
}
public TimeValue toSeconds() {
return this.unit == SECONDS ? this : of(this.durationToSeconds(), SECONDS);
}
public TimeValue toMinutes() {
return this.unit == MINUTES ? this : of(this.durationToMinutes(), MINUTES);
}
public TimeValue toHours() {
return this.unit == HOURS ? this : of(this.durationToHours(), HOURS);
}
public TimeValue toDays() {
return this.unit == DAYS ? this : of(this.durationToDays(), DAYS);
}
}