package org.leumasjaffe.recipe.model; import org.leumasjaffe.container.Either; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Getter; @Data @AllArgsConstructor public class Ingredient { @AllArgsConstructor @Getter public static enum Volume { ml("ml", 1), tsp("tsp", 5), Tbsp("Tbsp", 15), cup("cup", 240); final String displayName; final double atomicUnits; } @AllArgsConstructor @Getter public static enum Weight { g("g", 1), oz("oz", 28.3495), lb("lb", 453.592), kg("kg", 1000), pinch("pinch", 0.36), dash("dash", 0.72); final String displayName; final double atomicUnits; } String name; double value = 0; @JsonIgnore Either measure; Ingredient plus(final Ingredient rhs) { if (!name.equals(rhs.name)) { throw new IllegalArgumentException("Combining ingredients of differing types"); } else if (measure.getState() != rhs.measure.getState()) { throw new IllegalArgumentException("Cannot merge mass and volume together"); } return new Ingredient(name, value + (rhs.value * conversionRatio(rhs.measure)), measure); } private double conversionRatio(Either rhs) { return units(rhs) / units(measure); } private static double units(Either measure) { return measure.unify(Volume::getAtomicUnits, Weight::getAtomicUnits); } @JsonProperty("unit") private String[] measureToString() { String[] rval = {null, null}; return rval; } @JsonProperty("unit") private void measureFromString(String[] s) { if (s[0] != null) { measure = Either.ofLeft(Volume.valueOf(s[0])); } else if (s[1] != null) { measure = Either.ofRight(Weight.valueOf(s[1])); } } }