package org.pmdreports.report;

import java.io.IOException;
import java.io.Writer;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.pmdreports.manager.StatisticsManager;
import org.pmdreports.model.Component;
import org.pmdreports.model.Ruleset;
import org.pmdreports.model.Statistics;
import org.pmdreports.util.DateUtil;
import org.pmdreports.util.PMDReportsException;

/**
 * Generate a report that shows each component and stats per day.
 * 
 * @author Ben Northrop Aug 27, 2007
 */
public class ComponentHistoryReport extends AbstractReport {

	// DATA MEMBERS
	private final List<Ruleset> rulesets;

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

	// CONSTRUCTOR
	/**
	 * Default constructor - pass in the component for which the report will be
	 * generated.
	 */
	public ComponentHistoryReport(List<Ruleset> rulesets) {
		this.rulesets = rulesets;
	}

	// OVERRIDDEN METHODS
	/**
	 * @see org.pmdreports.report.AbstractReport#getFileName()
	 */
	public String getFileName() {
		return "ComponentQualityHistory.html";
	}

	public String getReportTitle() {
		return "Trend (Detail)";
	}

	/**
	 * Write out the report.
	 */
	@Override
	protected void writeReport(Writer writer) throws IOException {
		StatisticsManager manager = StatisticsManager.getInstance();
		Map<Component, Collection<Statistics>> map = manager.getAllStatistics();

		writer.write("<b>Components:</b> ");
		for (Component component : map.keySet()) {
			writer.write("<a href='#" + component.getName() + "'>"
					+ component.getName() + "</a>, ");
		}

		for (Component component : map.keySet()) {
			writer.write("<br><br><br>");
			writer.write("<table class='statistics'>");
			writer.write("<tr><th colspan='9' class='componentTitle'>");
			writer.write("<a name='" + component.getName() + "'>"
					+ component.getName() + "</a></th>");
			writer.write("</tr>");
			writer.write("<tr>");
			writer.write("<th style='text-align: left;'>Date</th>");
			writer.write("<th>Num Java Files</th>");
			writer.write("<th>Lines of Code</th>");
			for (Ruleset ruleset : rulesets) {
				writer.write("<th>");
				writer.write(ruleset.getName());
				writer.write("</th>");
			}
			writer.write("</tr>");

			Statistics prevStats = null;
			for (Statistics stats : map.get(component)) {
				writer.write("<tr>");
				writer.write("<td class='normal'>");
				writer.write(DateUtil.formatDate(stats.getDateCalculated(),
						"MMM-dd-yyyy"));
				writer.write("</td>");
				writer.write("<td class='normal'>");
				writer.write(ReportUtilities.DEFAULT_FORMATTER.format(stats
						.getNumberOfFiles()));
				writer.write("</td>");
				writer.write("<td class='normal'>");
				writer.write(ReportUtilities.DEFAULT_FORMATTER.format(stats
						.getLinesOfCode()));
				writer.write("</td>");

				for (Ruleset ruleset : rulesets) {
					writeCell(writer, ruleset, stats, prevStats, true);
				}

				writer.write("</tr>");
				prevStats = stats;
			}
			writer.write("</table>");
		}
	}

	/**
	 * Helper method to write simple integer value.
	 */
	private void writeCell(Writer writer, Ruleset ruleset, Statistics stats,
			Statistics prevStats, boolean isPerLine) throws IOException {
		NumberFormat formatter = ReportUtilities.DEFAULT_FORMATTER;
		if (isPerLine) {
			formatter = ReportUtilities.DECIMAL_FORMATTER;
		}
		double value = stats.getStatistic(ruleset, isPerLine).doubleValue();
		double prevValue = prevStats == null ? -1D : prevStats.getStatistic(
				ruleset, isPerLine).doubleValue();

		if (prevValue == -1d) {
			writer.write("<td class='normal'>&nbsp;");
		} else {
			String formattedValue = formatter.format(value);
			String formattedPrevValue = formatter.format(prevValue);
			double roundedValue = 0d;
			double roundedPrevValue = 0d;
			try {
				roundedValue = Double.parseDouble(formattedValue);
				roundedPrevValue = Double.parseDouble(formattedPrevValue);
			} catch (NumberFormatException nfe) {
				LOG.error("Could not parse formatted value: " + formattedValue
						+ ", " + formattedPrevValue, nfe);
			}

			double diff = roundedValue - roundedPrevValue;
			LOG.debug(diff + " = " + roundedValue + " - " + roundedPrevValue);
			if (diff > .0009D) {
				writer.write(" <td class=\"highValue\">&nbsp;");
			} else if (diff < -.0009D) {
				writer.write(" <td class=\"lowValue\">&nbsp;");
			} else {
				writer.write("<td class='normalValue'>&nbsp;");
			}
		}

		writer.write(formatter.format(value));
		writer.write("&nbsp;</td>");
	}

	// OVERRIDDEN METHODS
	public boolean isComponentReport() {
		return true;
	}

	public boolean isProjectReport() {
		return false;
	}
}
