package org.lucci.madhoc.simulation.measure;

import java.util.List;

import org.lucci.madhoc.network.Network;
import org.lucci.madhoc.simulation.Simulation;
import org.lucci.madhoc.simulation.projection.Projection;
import org.lucci.math.Utilities;

/*
 * Created on Jul 19, 2004
 */

/**
 * @author luc.hogie
 */
public  class NumericalMeasureHistory extends MeasureHistory
{


    /* (non-Javadoc)
     * @see org.lucci.madhoc.simulation.measure.Measure#addValue(java.lang.Object)
     */
    public void addValue(Object value, int iteration)
    {
        if (value != null)
        {
            value = new Double(Utilities.round(((Double) value).doubleValue(), getNumericalSensor().getPrecision()));
        }

        super.addValue(value, iteration);
    }
    

    
    public double getLastDoubleValue()
    {
        return ((Double) getLastValue()).doubleValue();
    }

    public Double getSum()
    {
        if (getNonNullValues().isEmpty())
        {
            return null;
        }
        else
        {
            return new Double(Utilities.round(Utilities.getSum(getNonNullValues()), getNumericalSensor().getPrecision()));
        }
    }
    

    public Double getAverage()
    {
        Double sum = getSum();

        if (sum == null)
        {
            return null;
        }
        else
        {
            return new Double(Utilities.round(Utilities.getAverage(getNonNullValues()), getNumericalSensor().getPrecision()));
        }
    }

    public Double getStandardDeviation()
    {
        Double avg = getAverage();
        
        if (avg == null)
        {
            return null;
        }
        else
        {
            return new Double(Utilities.round(Utilities.getStandardDeviation(getNonNullValues()), getNumericalSensor().getPrecision()));
        }
    }

    public Double getMinimum()
    {
        if (getNonNullValues().isEmpty())
        {
            return null;
        }
        else
        {
            return new Double(Utilities.round(Utilities.getMinimum(getNonNullValues()), getNumericalSensor().getPrecision()));
        }
    }

    
    public Double getMaximum()
    {
        if (getNonNullValues().isEmpty())
        {
            return null;
        }
        else
        {
            return new Double(Utilities.round(Utilities.getMaximum(getNonNullValues()), getNumericalSensor().getPrecision()));
        }
    }


    /**
     * @return
     */
    public NumericalSensor getNumericalSensor()
    {
        return (NumericalSensor) getSensor(); 
    }



    public double getVariationInTheLastIterations(int iterationCount)
    {
        return getVariationSinceIteration(getValues().size() - 1 - iterationCount);
    }

    public double getVariationSinceIteration(int iteration)
    {
        List values = getValues();

        if (iteration < 0)
            throw new IllegalArgumentException("you gave a negative iteration");

        if (iteration > values.size())
            throw new IllegalArgumentException("the iteration you ask has not yet been executed");

        double variation = 0;
        double previousValue = -1;
        
        for (int i = iteration; i < values.size(); ++i)
        {
            double v = ((Double) values.get(i)).doubleValue();
            
            if (previousValue != -1)
            {
                variation += Math.abs(v - previousValue);
            }
            
            previousValue = v;
        }
        
        return variation;
    }

    public double getVariationInTheLastSeconds(double seconds)
    {
        Projection projection = getProjection();
        Network network = getProjection().getNetwork();
        Simulation simulation = getProjection().getNetwork().getSimulation();
        int iterations = (int) (seconds / simulation.getResolution()); 
        return getVariationInTheLastIterations(iterations);
    }

    
    public double getVariationSince(double date)
    {
        Simulation simulation = getProjection().getNetwork().getSimulation();
        int iteration = (int) (date / simulation.getResolution()); 
        return getVariationSinceIteration(iteration);
    }
}