/*
 * Copyright 2016 Palantir Technologies, Inc. All rights reserved.
 *
 * Included from Dropwizard's https://github.com/dropwizard/dropwizard/blob/b9e9e835fd5be10180a839a3f38ca93b9c8e0652/dropwizard-util/src/main/java/io/dropwizard/util/Duration.java
 * under Apache2 license.
 */

package com.palantir.config.service;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.ImmutableMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public final class Duration implements Comparable<Duration> {
    private static final Pattern DURATION_PATTERN = Pattern.compile("(\\d+)\\s*(\\S+)");

    private static final Map<String, TimeUnit> SUFFIXES = new ImmutableMap.Builder<String, TimeUnit>()
            .put("ns", TimeUnit.NANOSECONDS)
            .put("nanosecond", TimeUnit.NANOSECONDS)
            .put("nanoseconds", TimeUnit.NANOSECONDS)
            .put("us", TimeUnit.MICROSECONDS)
            .put("microsecond", TimeUnit.MICROSECONDS)
            .put("microseconds", TimeUnit.MICROSECONDS)
            .put("ms", TimeUnit.MILLISECONDS)
            .put("millisecond", TimeUnit.MILLISECONDS)
            .put("milliseconds", TimeUnit.MILLISECONDS)
            .put("s", TimeUnit.SECONDS)
            .put("second", TimeUnit.SECONDS)
            .put("seconds", TimeUnit.SECONDS)
            .put("m", TimeUnit.MINUTES)
            .put("minute", TimeUnit.MINUTES)
            .put("minutes", TimeUnit.MINUTES)
            .put("h", TimeUnit.HOURS)
            .put("hour", TimeUnit.HOURS)
            .put("hours", TimeUnit.HOURS)
            .put("d", TimeUnit.DAYS)
            .put("day", TimeUnit.DAYS)
            .put("days", TimeUnit.DAYS)
            .build();

    public static Duration nanoseconds(long count) {
        return new Duration(count, TimeUnit.NANOSECONDS);
    }

    public static Duration microseconds(long count) {
        return new Duration(count, TimeUnit.MICROSECONDS);
    }

    public static Duration milliseconds(long count) {
        return new Duration(count, TimeUnit.MILLISECONDS);
    }

    public static Duration seconds(long count) {
        return new Duration(count, TimeUnit.SECONDS);
    }

    public static Duration minutes(long count) {
        return new Duration(count, TimeUnit.MINUTES);
    }

    public static Duration hours(long count) {
        return new Duration(count, TimeUnit.HOURS);
    }

    public static Duration days(long count) {
        return new Duration(count, TimeUnit.DAYS);
    }

    @JsonCreator
    public static Duration parse(String duration) {
        final Matcher matcher = DURATION_PATTERN.matcher(duration);
        checkArgument(matcher.matches(), "Invalid duration: " + duration);

        final long count = Long.parseLong(matcher.group(1));
        final TimeUnit unit = SUFFIXES.get(matcher.group(2));
        if (unit == null) {
            throw new IllegalArgumentException("Invalid duration: " + duration + ". Wrong time unit");
        }

        return new Duration(count, unit);
    }

    private final long count;
    private final TimeUnit unit;

    private Duration(long count, TimeUnit unit) {
        this.count = count;
        this.unit = checkNotNull(unit);
    }

    public long getQuantity() {
        return count;
    }

    public TimeUnit getUnit() {
        return unit;
    }

    public long toNanoseconds() {
        return TimeUnit.NANOSECONDS.convert(count, unit);
    }

    public long toMicroseconds() {
        return TimeUnit.MICROSECONDS.convert(count, unit);
    }

    public long toMilliseconds() {
        return TimeUnit.MILLISECONDS.convert(count, unit);
    }

    public long toSeconds() {
        return TimeUnit.SECONDS.convert(count, unit);
    }

    public long toMinutes() {
        return TimeUnit.MINUTES.convert(count, unit);
    }

    public long toHours() {
        return TimeUnit.HOURS.convert(count, unit);
    }

    public long toDays() {
        return TimeUnit.DAYS.convert(count, unit);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if ((obj == null) || (getClass() != obj.getClass())) {
            return false;
        }
        final Duration duration = (Duration) obj;
        return (count == duration.count) && (unit == duration.unit);

    }

    @Override
    public int hashCode() {
        return (31 * (int) (count ^ (count >>> 32))) + unit.hashCode();
    }

    @Override
    @JsonValue
    public String toString() {
        String units = unit.toString().toLowerCase(Locale.ENGLISH);
        if (count == 1) {
            units = units.substring(0, units.length() - 1);
        }
        return Long.toString(count) + ' ' + units;
    }

    @Override
    public int compareTo(Duration other) {
        if (unit == other.unit) {
            return Long.compare(count, other.count);
        }

        return Long.compare(toNanoseconds(), other.toNanoseconds());
    }
}

@@ -66,16 +66,574 @@
 ved.%0A *%0A
+ * Licensed under the Apache License, Version 2.0 (the %22License%22);%0A * you may not use this file except in compliance with the License.%0A * You may obtain a copy of the License at%0A *%0A *     http://www.apache.org/licenses/LICENSE-2.0%0A *%0A * Unless required by applicable law or agreed to in writing, software%0A * distributed under the License is distributed on an %22AS IS%22 BASIS,%0A * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A * See the License for the specific language governing permissions and%0A * limitations under the License.%0A *%0A
  * Inclu

fix copyright in Duration.java (#184)