package vismon.data;

import java.util.ArrayList;
import java.util.List;

public class MngOption {

    private String          name;

    private List<Double>    values;
    private int             valueNum;

    private double          min;
    private double          minConstraint;
    private double          max;
    private double          maxConstraint;

    private double          roundFactor;

    public MngOption() {
        values = new ArrayList<Double>();
    }

    public int getValueNum() {
        return valueNum;
    }

    public void setValueNum(int valueNum) {
        this.valueNum = valueNum;
    }

    public void addValue(double v) {
        values.add(v);
    }

    public double getValue(int rank) {
        return values.get(rank);
    }

    public int getRank(double v) {
        return values.indexOf(v);
    }

    public List<Double> getValues() {
        return values;
    }

    public double getPrevValue(double v) {
        int rank = values.indexOf(v);
        if (rank == 0)
            return Double.NaN;
        else
            return values.get(rank - 1);
    }

    public double getNextValue(double v) {
        int rank = values.indexOf(v);
        if (rank == values.size() - 1)
            return Double.NaN;
        else
            return values.get(rank + 1);
    }

    public double getNearestPrevValue(double v) {
        if (v <= min)
            return Double.NaN;
        for (int i = 0; i < values.size(); ++i)
            if (values.get(i) > v)
                return values.get(i - 1);
        return values.get(values.size() - 1);
    }

    public double getNearestNextValue(double v) {
        if (v >= max)
            return Double.NaN;
        for (int i = values.size() - 1; i >= 0; --i)
            if (values.get(i) < v)
                return values.get(i + 1);
        return values.get(0);
    }

    protected void computeMin() {
        min = Double.MAX_VALUE;
        for (double v : values)
            if (v <= min)
                min = v;
    }

    protected void computeMax() {
        max = Double.MIN_VALUE;
        for (double v : values)
            if (v >= max)
                max = v;
    }

    private void computeRoundValue() {
        double range = max - min;
        if (range > 1)
            roundFactor = 1.0;
        else if (0.1 < range && range <= 1)
            roundFactor = 0.01;
        else roundFactor = 0.001 * range;
    }

    public void doComputations() {
        computeMin();
        computeMax();
        computeRoundValue();

        minConstraint = min;
        maxConstraint = max;
    }

    public double getRoundFactor() {
        return roundFactor;
    }

    public int countSamplesBetweenBounds(double lowerBound, double upperBound, boolean last) {
        int count = 0;
        for (double v : values) {
            if (!last) {
                if (lowerBound <= v && v < upperBound)
                    ++count;
            } else {
                if (lowerBound <= v && v <= upperBound)
                    ++count;
            }
        }
        return count;
    }

    public double getMax() {
        return max;
    }

    public void setMax(double max) {
        this.max = max;
    }

    public double getMin() {
        return min;
    }

    public void setMin(double min) {
        this.min = min;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getMaxConstraint() {
        return maxConstraint;
    }

    public void setMaxConstraint(double maxConstraint) {
        this.maxConstraint = (Math.round(maxConstraint / roundFactor)) * roundFactor;
    }

    public double getMinConstraint() {
        return minConstraint;
    }

    public void setMinConstraint(double minConstraint) {
        this.minConstraint = (Math.round(minConstraint / roundFactor)) * roundFactor;
    }

    public void resetConstraints() {
        minConstraint = min;
        maxConstraint = max;
    }

    @Override
    public boolean equals(Object o) {
        return name.equals(((MngOption)o).getName());
    }


}
