package ex1;

/**
 *
 * @author maxerdwien
 */
public class InputLimits {

    private final Double absoluteMinimum;
    private final Boolean absoluteMinimumIncluded;

    private final Double absoluteMaximum;
    private final Boolean absoluteMaximumIncluded;

    private final Double recommendedMinimum;
    private final Boolean recommendedMinimumIncluded;

    private final Double recommendedMaximum;
    private final Boolean recommendedMaximumIncluded;
    
    private final Boolean DEFAULT_INCLUSION = true;

    /**
     * It's important that these be in order of increasing severity
     */
    public enum TableStatus {

        //The OKAY state specifies that the data is within expected ranges.
        OKAY(0), 
        //The WARNSAVE state specifies that the data is outside of the
        //expected range, but should not crash the code.
        WARNSAVE(1), 
        //The NOSAVE state specifies that the data is outside of a range that
        //WEPS is designed to deal with and will probably crash the code.
        NOSAVE(2);
        
        private final int code;
        
        TableStatus(int input)
        {
            code = input;
        }
        
        public boolean lessThan(TableStatus other)
        {
            return this.code < other.code;
        }
    }

    public InputLimits(String aMin, String aMax, String rMin, String rMax, 
            Boolean aMinInc, Boolean aMaxInc, Boolean rMinInc, Boolean rMaxInc) {
        if(!aMin.equals("")) absoluteMinimum = Double.parseDouble(aMin);
        else absoluteMinimum = null;
        if(aMinInc != null) absoluteMinimumIncluded = aMinInc;
        else absoluteMinimumIncluded = DEFAULT_INCLUSION;

        if(!aMax.equals("")) absoluteMaximum = Double.parseDouble(aMax);
        else absoluteMaximum = null;
        if(aMaxInc != null) absoluteMaximumIncluded = aMaxInc;
        else absoluteMaximumIncluded = DEFAULT_INCLUSION;

        if(!rMin.equals("")) recommendedMinimum = Double.parseDouble(rMin);
        else recommendedMinimum = null;
        if(rMinInc != null) recommendedMinimumIncluded = rMinInc;
        else recommendedMinimumIncluded = DEFAULT_INCLUSION;

        if(!rMax.equals("")) recommendedMaximum = Double.parseDouble(rMax);
        else recommendedMaximum = null;
        if(rMaxInc != null) recommendedMaximumIncluded = rMaxInc;
        else recommendedMaximumIncluded = DEFAULT_INCLUSION;
    }

    private Boolean belowAbsolute(double d) {
        if (absoluteMinimum == null) {
            return false;
        }
        if (absoluteMinimumIncluded) {
            return d < absoluteMinimum;
        } else {
            return d <= absoluteMinimum;
        }
    }

    private Boolean aboveAbsolute(double d) {
        if (absoluteMaximum == null) {
            return false;
        }
        if (absoluteMaximumIncluded) {
            return d > absoluteMaximum;
        } else {
            return d >= absoluteMaximum;
        }
    }

    private Boolean belowRecommended(double d) {
        if (recommendedMinimum == null) {
            return false;
        }
        if (recommendedMinimumIncluded) {
            return d < recommendedMinimum;
        } else {
            return d <= recommendedMinimum;
        }
    }

    private Boolean aboveRecommended(double d) {
        if (recommendedMaximum == null) {
            return false;
        }
        if (recommendedMaximumIncluded) {
            return d > recommendedMaximum;
        } else {
            return d >= recommendedMaximum;
        }
    }

    /**
     * 
     * @param d number to evaluate
     * @return whether and how d breaks the bounds
     */
    public TableStatus evaluateInput(double d) {
        if (aboveAbsolute(d) || belowAbsolute(d)) {
            return TableStatus.NOSAVE;
        } else if (belowRecommended(d) && !belowAbsolute(d)) {
            return TableStatus.WARNSAVE;
        } else if (aboveRecommended(d) && !aboveAbsolute(d)) {
            return TableStatus.WARNSAVE;
        } else {
            return TableStatus.OKAY;
        }
    }
}
