

package gov.va.med.cds.monitor.util;


import java.util.Collections;
import java.util.List;


/**
 * Static utilty that calculates metrics given a set of measurements
 * 
 * @author vhaisltalbom
 * 
 */
public class MetricsCalculator
{
    /**
     * Calculates the standard deviation of a set of measurments applying a basic standard deviation algorithm.
     * 
     * @param measurements
     * @param count
     * @param mean
     * @return square root value of the variance sums divided by the count
     */
    public static double calcStandardDeviation( List<Long> measurements, int count, double mean )
    {

        // first sum the squares of the variances between the measurement and the mean (average)
        Double sqSum = 0.0;
        for ( Long measurement : measurements )
        {
            double variance = measurement - mean;
            sqSum += variance * variance;
        }

        // now return the square root of the variance sums divided by the count
        return Math.sqrt( sqSum / count );

    }


    /**
     * Calculates the median value of a set of measurments by sorting the collection of measurements - determining if
     * the number of measurements is odd or even, when even the two values on each side of center are averaged and
     * returned, when odd the center value is returned.
     * 
     * @param measurements
     * @return median value
     */
    public static double calcMedian( List<Long> measurements )
    {
        // first order measurements - determine if Odd or even number - find median - center for odd - average of two
        // center for even
        double median = 0;
        Collections.sort( measurements );
        int size = measurements.size();

        // when even number of measurements average measurements splitting center
        if ( size % 2 == 0 )
        {
            // center indexes for 0 based collection
            int mid = size / 2;
            Long middle2 = measurements.get( mid );
            Long middle1 = measurements.get( --mid );
            // average both center points/measurements
            median = ( middle1 + middle2 ) / ( double )2; // cast to double so result has correct precision.
        }
        else if ( size > 1 )
        {
            // when odd number of measurements - find index of center measurement
            int mid = size % 2 + size / 2;
            Long middle = measurements.get( mid );
            median = middle.doubleValue();
        }
        else
        {
            // there was only one measurement in list - median is equal to measurement
            median = measurements.get( 0 );
        }

        return median;
    }


    public static double getTransactionsPerSecond( long count, long elapsedTime )
    {
        return getTransactionsPerSecond( count, ( double )elapsedTime );
    }


    public static double getTransactionsPerSecond( long count, double elapsedTime )
    {
        return ( ( double )count * 1000.0 ) / elapsedTime;
    }
}
