package org.pmdreports.manager;

import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

import org.apache.log4j.Logger;
import org.pmdreports.model.Component;
import org.pmdreports.model.Ruleset;
import org.pmdreports.model.Statistics;

/**
 * ComponentStatisticsCalculator.java<br>
 * 
 * Given a ComponentStatisticsVO, calculate some basic stats (mean, max, min,
 * average, standard dev, etc.).
 * 
 * Copyright Summa Technologies 2007
 * 
 * @author Ben Northrop
 */
public final class ComponentStatisticsCalculator {
	// DATA MEMBER
	private final Collection<Statistics> componentStatistics;

	private final static Logger LOG = Logger
			.getLogger(ComponentStatisticsCalculator.class);

	// CONSTRUCTOR
	/**
	 * Default constructor - pass in ComponentStatisticsVO that this calculator
	 * will use for all calculations.
	 */
	public ComponentStatisticsCalculator(
			Collection<Statistics> componentStatistics) {
		this.componentStatistics = componentStatistics;
	}

	// METHODS
	/**
	 * Helper method to calculate what the high 10% of values is for the
	 * collection.
	 */
	public Statistics calculateStandardDeviation(Statistics average, int size,
			boolean isPerLine) {
		Statistics sDev = new Statistics(new Component("sDev"));

		Set<Ruleset> rulesets = average.getRulesets();
		for (Ruleset ruleset : rulesets) {
			double totalSquareVariance = 0d;
			for (Statistics comp : componentStatistics) {
				final double variance = comp.getStatistic(ruleset, isPerLine)
						.doubleValue()
						- average.getStatistic(ruleset, isPerLine).doubleValue();
				final double squareVariance = Math.abs(variance);
				totalSquareVariance += squareVariance;
			}
			double standardDeviation = totalSquareVariance / (size - 1);
			sDev.addStatistic(ruleset, standardDeviation);
		}

		return sDev;
	}

	/**
	 * Helper method to calculate what the high 10% of values is for the
	 * collection.
	 */
	public Statistics calculateAverage(Statistics sum, int size) {
		Statistics averageStats = new Statistics(new Component("average"));

		Set<Ruleset> rulesets = sum.getRulesets();
		for (Ruleset ruleset : rulesets) {
			Double statValue = (Double) sum.getStatistic(ruleset, false);
			Double average = statValue.doubleValue() / size;
			averageStats.addStatistic(ruleset, average);
		}

		return averageStats;
	}

	/**
	 * Helper method to calculate what the high 10% of values is for the
	 * collection.
	 */
	public Statistics calculateSum(boolean isPerLine) {
		Statistics sum = new Statistics(new Component("sum"));
		for (Statistics stats : componentStatistics) {
			sum.setLinesOfCode(stats.getLinesOfCode() + sum.getLinesOfCode());

			Set<Ruleset> rulesets = stats.getRulesets();
			for (Ruleset ruleset : rulesets) {
				Double statValue = (Double) stats.getStatistic(ruleset, false);
				Double sumValue = sum.getStatistic(ruleset);
				if (sumValue == null) {
					sumValue = 0d;
				}
				sum.addStatistic(ruleset, statValue.doubleValue()
						+ sumValue.doubleValue());
			}
		}

		return sum;
	}
}
