// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.flags.custom;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Objects;
import java.util.Optional;

/**
 * @author freva
 */
// @Immutable
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(value = JsonInclude.Include.NON_NULL)
public class ClusterCapacity {
    private final int count;
    private final double vcpu;
    private final double memoryGb;
    private final double diskGb;
    private final Optional<Double> bandwidthGbps;

    @JsonCreator
    public ClusterCapacity(@JsonProperty("count") int count,
                           @JsonProperty("vcpu") double vcpu,
                           @JsonProperty("memoryGb") double memoryGb,
                           @JsonProperty("diskGb") double diskGb,
                           @JsonProperty("bandwidthGbps") Double bandwidthGbps) {
        this.count = (int) requireNonNegative("count", count);
        this.vcpu = requireNonNegative("vcpu", vcpu);
        this.memoryGb = requireNonNegative("memoryGb", memoryGb);
        this.diskGb = requireNonNegative("diskGb", diskGb);
        this.bandwidthGbps = Optional.ofNullable(bandwidthGbps);
    }

    /** Returns a new ClusterCapacity equal to {@code this}, but with the given count. */
    public ClusterCapacity withCount(int count) {
        return new ClusterCapacity(count, vcpu, memoryGb, diskGb, bandwidthGbps.orElse(null));
    }

    @JsonGetter("count") public int count() { return count; }
    @JsonGetter("vcpu") public double vcpu() { return vcpu; }
    @JsonGetter("memoryGb") public double memoryGb() { return memoryGb; }
    @JsonGetter("diskGb") public double diskGb() { return diskGb; }
    @JsonGetter("bandwidthGbps") public Double bandwidthGbpsOrNull() { return bandwidthGbps.orElse(null); }

    @JsonIgnore
    public double bandwidthGbps() { return bandwidthGbps.orElse(1.0); }

    @Override
    public String toString() {
        return "ClusterCapacity{" +
                "count=" + count +
                ", vcpu=" + vcpu +
                ", memoryGb=" + memoryGb +
                ", diskGb=" + diskGb +
                ", bandwidthGbps=" + bandwidthGbps +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ClusterCapacity that = (ClusterCapacity) o;
        return count == that.count &&
                Double.compare(that.vcpu, vcpu) == 0 &&
                Double.compare(that.memoryGb, memoryGb) == 0 &&
                Double.compare(that.diskGb, diskGb) == 0 &&
                ((bandwidthGbps.isEmpty() && that.bandwidthGbps.isEmpty()) ||
                        ((bandwidthGbps.isPresent() && that.bandwidthGbps.isPresent() &&
                                Double.compare(that.bandwidthGbps.get(), bandwidthGbps.get()) == 0)));
    }

    @Override
    public int hashCode() {
        return Objects.hash(count, vcpu, memoryGb, diskGb, bandwidthGbps);
    }

    private static double requireNonNegative(String name, double value) {
        if (value < 0)
            throw new IllegalArgumentException("'" + name + "' must be positive, was " + value);
        return value;
    }
}

@@ -523,18 +523,24 @@
 Optional
+Double
 ;%0A
-
 %0A/**%0A * 
@@ -855,16 +855,14 @@
 onal
-%3C
 Double
-%3E
  ban
@@ -1508,27 +1508,74 @@
 s = 
-Optional.ofNullable
+bandwidthGbps == null ? OptionalDouble.empty() : OptionalDouble.of
 (ban
@@ -1813,28 +1813,23 @@
 idthGbps
-.orElse(n
+OrN
 ull
+(
 ));%0A    
@@ -2163,24 +2163,32 @@
 psOrNull() %7B
+%0A       
  return band
@@ -2201,21 +2201,61 @@
 bps.
-orElse(null);
+isPresent() ? bandwidthGbps.getAsDouble() : null;%0A   
  %7D%0A%0A
@@ -3090,34 +3090,32 @@
                 
-((
 bandwidthGbps.is
@@ -3116,243 +3116,33 @@
 bps.
-isEmpty() && that.bandwidthGbps.isEmpty()) %7C%7C%0A                        ((bandwidthGbps.isPresent() && that.bandwidthGbps.isPresent() &&%0A                                Double.compare(that.bandwidthGbps.get(), bandwidthGbps.get()) == 0))
+equals(that.bandwidthGbps
 );%0A 

Use OptionalDouble