package es.moki.ratelimitj.core.limiter.request;

import java.util.OptionalInt;
import java.util.concurrent.TimeUnit;

/**
 * Defines a limit rule that can support regular and token bucket rate limits.
 */
public class RequestLimitRule {

    private final int durationSeconds;
    private final long limit;
    private final OptionalInt precision;
    private final String name;

    private RequestLimitRule(int durationSeconds, long limit) {
        this(durationSeconds, limit, OptionalInt.empty(), null);
    }

    private RequestLimitRule(int durationSeconds, long limit, OptionalInt precision, String name) {
        this.durationSeconds = durationSeconds;
        this.limit = limit;
        this.precision = precision;
        this.name = name;
    }

    /**
     * Initialise a regular rate limit. Imagine the whole duration window as being one large bucket with a single count.
     *
     * @param duration The time the limit will be applied over.
     * @param timeUnit The time unit.
     * @param limit    A number representing the maximum operations that can be performed in the given duration.
     * @return A limit rule.
     */

    public static RequestLimitRule of(int duration, TimeUnit timeUnit, long limit) {
        return new RequestLimitRule((int) timeUnit.toSeconds(duration), limit);
    }

    /**
     * Configures as a sliding window rate limit. Imagine the duration window divided into a number of smaller buckets, each with it's own count.
     * The number of smaller buckets is defined by the precision.
     *
     * @param precision Defines the number of buckets that will be used to approximate the sliding window.
     * @return a limit rule
     */
    public RequestLimitRule withPrecision(int precision) {
        return new RequestLimitRule(this.durationSeconds, this.limit, OptionalInt.of(precision), this.name);
    }

    /**
     * Applies a name to the rate limit that is useful for analysis of limits.
     *
     * @param name Defines a descriptive name for the rule limit.
     * @return a limit rule
     */
    public RequestLimitRule withName(String name) {
        return new RequestLimitRule(this.durationSeconds, this.limit, this.precision, name);
    }

    /**
     * @return The limits duration in seconds.
     */
    public int getDurationSeconds() {
        return durationSeconds;
    }

    /**
     * @return The limits precision.
     */
    public OptionalInt getPrecision() {
        return precision;
    }

    /**
     * @return The name.
     */
    public String getName() {
        return name;
    }

    /**
     * @return The limit.
     */
    public long getLimit() {
        return limit;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        RequestLimitRule that = (RequestLimitRule) o;

        if (durationSeconds != that.durationSeconds) return false;
        if (limit != that.limit) return false;
        if (precision != null ? !precision.equals(that.precision) : that.precision != null) return false;
        return name != null ? name.equals(that.name) : that.name == null;
    }

    @Override
    public int hashCode() {
        int result = durationSeconds;
        result = 31 * result + (int) (limit ^ (limit >>> 32));
        result = 31 * result + (precision != null ? precision.hashCode() : 0);
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }
}

@@ -43,16 +43,42 @@
 quest;%0A%0A
+import java.util.Objects;%0A
 import j
@@ -2694,24 +2694,29 @@
 limit;%0A    %7D
+%0A    
 %0A%0A    @Overr
@@ -2860,17 +2860,16 @@
  false;%0A
-%0A
         
@@ -2914,25 +2914,24 @@
 ule) o;%0A
-%0A
         
 if (dura
@@ -2922,20 +2922,23 @@
         
-if (
+return 
 duration
@@ -2945,17 +2945,17 @@
 Seconds 
-!
+=
 = that.d
@@ -2972,32 +2972,27 @@
 onds
-) return false;%0A
+ &&%0A       
         
 if (
@@ -2991,19 +2991,16 @@
     
-if (
+ 
 limit 
-!
+=
 = th
@@ -3011,74 +3011,43 @@
 imit
-) return false;%0A        if (precision != null ? !precision
+ &&%0A                Objects
 .equals(
 that
@@ -3042,21 +3042,16 @@
 .equals(
-that.
 precisio
@@ -3051,19 +3051,17 @@
 recision
-) :
+,
  that.pr
@@ -3071,74 +3071,44 @@
 sion
- != null) return false;%0A        return name != null ? name
+) &&%0A                Objects
 .equals(
 that
@@ -3107,20 +3107,13 @@
 als(
-that.
 name
-) :
+,
  tha
@@ -3118,24 +3118,17 @@
 hat.name
- == null
+)
 ;%0A    %7D%0A
@@ -3182,270 +3182,68 @@
     
-int result = durationSeconds;%0A        result = 31 * result + (int) (limit %5E (limit %3E%3E%3E 32));%0A        result = 31 * result + (precision != null ? precision.hashCode() : 0);%0A        result = 31 * result + (name != null ? name.hashCode() : 0);%0A        return result
+return Objects.hash(durationSeconds, limit, precision, name)
 ;%0A  

tidy equals/hashcode methods