001package org.gbif.api.vocabulary;
002
003import java.util.Optional;
004import java.util.regex.Matcher;
005import java.util.regex.Pattern;
006import lombok.AllArgsConstructor;
007import lombok.EqualsAndHashCode;
008import lombok.Getter;
009
010@Getter
011public enum DurationUnit {
012  SECONDS(0.0166667, "seconds", "second", "s", "sec", "secs"),
013  MINUTES(1, "minutes", "minute", "m", "min", "mins"),
014  HOURS(60, "hours", "hour", "h", "hr", "hrs"),
015  DAYS(1440, "days", "day", "d"),
016  WEEKS(10080, "weeks", "week", "wk", "wks"),
017  MONTHS(43800, "months", "month", "mo", "mos"),
018  YEARS(525600, "years", "year", "yr", "yrs", "y");
019
020  public static final DurationUnit DEFAULT = MINUTES;
021
022  private final double durationInMinutes;
023  private final String[] names;
024
025  DurationUnit(double durationInMinutes, String... names) {
026    this.durationInMinutes = durationInMinutes;
027    this.names = names;
028  }
029
030  public static Optional<DurationUnit> parseDurationUnit(String duration) {
031    if (duration != null && !duration.isEmpty()) {
032      String normalizedDuration = duration.trim().toLowerCase();
033      for (DurationUnit unit : DurationUnit.values()) {
034        for (String name : unit.getNames()) {
035          if (normalizedDuration.equals(name)) {
036            return Optional.of(unit);
037          }
038        }
039      }
040    }
041    return Optional.empty();
042  }
043
044  @AllArgsConstructor
045  @Getter
046  @EqualsAndHashCode
047  public static class Duration {
048
049    private static final Pattern DURATION_PATTERN =
050        Pattern.compile("(\\d*\\.?\\d+)\\s*([a-zA-Z]*)");
051
052    private final double value;
053    private final DurationUnit unit;
054
055    public static Optional<Duration> parse(String duration) {
056      if (duration != null && !duration.isEmpty()) {
057        Matcher matcher = DURATION_PATTERN.matcher(duration);
058        if (matcher.matches()) {
059          String rawUnit = matcher.group(2);
060          if (rawUnit != null && !rawUnit.isEmpty()) {
061            DurationUnit unit = DurationUnit.parseDurationUnit(matcher.group(2)).orElse(null);
062
063            if (unit == null) {
064              return Optional.empty();
065            }
066
067            return Optional.of(new Duration(Double.parseDouble(matcher.group(1)), unit));
068          } else {
069            return Optional.of(new Duration(Double.parseDouble(duration), DEFAULT));
070          }
071        }
072      }
073      return Optional.empty();
074    }
075
076    public double toMinutes() {
077      return value * unit.getDurationInMinutes();
078    }
079  }
080}