/**
 * Copyright (C) 2001-2016 by RapidMiner and the contributors
 *
 * Complete list of developers available at our web site:
 *
 * http://rapidminer.com
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU Affero General Public License as published by the Free Software Foundation, either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License along with this program.
 * If not, see http://www.gnu.org/licenses/.
 */
package com.rapidminer.gui.viewer.metadata.model;

import java.awt.Color;
import java.util.Arrays;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.chart.renderer.xy.XYBarRenderer;
import org.jfree.data.statistics.HistogramDataset;

import com.rapidminer.example.Attribute;
import com.rapidminer.example.Example;
import com.rapidminer.example.ExampleSet;
import com.rapidminer.example.Statistics;
import com.rapidminer.gui.tools.AttributeGuiTools;
import com.rapidminer.gui.viewer.metadata.AttributeStatisticsPanel;
import com.rapidminer.tools.Ontology;


/**
 * Model for {@link AttributeStatisticsPanel}s which are backed by a numerical {@link Attribute}.
 *
 * @author Marco Boeck
 *
 */
public class NumericalAttributeStatisticsModel extends AbstractAttributeStatisticsModel {

	/** the index for the histogram chart */
	private static final int INDEX_HISTOGRAM_CHART = 0;

	/** the max number of bins */
	private static final int MAX_BINS_HISTOGRAM = 10;

	/** used to color the chart background invisible */
	private static final Color COLOR_INVISIBLE = new Color(255, 255, 255, 0);

	/** the average of the numerical values */
	private double average;

	/** the standard deviation of the numerical values */
	private double deviation;

	/** the minimum of the numerical values */
	private double minimum;

	/** the maximum of the numerical values */
	private double maximum;

	/** array of charts for this model */
	private JFreeChart[] chartsArray;

	/**
	 * Creates a new {@link NumericalAttributeStatisticsModel}.
	 *
	 * @param exampleSet
	 * @param attribute
	 */
	public NumericalAttributeStatisticsModel(ExampleSet exampleSet, Attribute attribute) {
		super(exampleSet, attribute);

		chartsArray = new JFreeChart[1];
	}

	@Override
	public void updateStatistics(ExampleSet exampleSet) {
		average = exampleSet.getStatistics(getAttribute(), Statistics.AVERAGE);
		deviation = Math.sqrt(exampleSet.getStatistics(getAttribute(), Statistics.VARIANCE));
		minimum = exampleSet.getStatistics(getAttribute(), Statistics.MINIMUM);
		maximum = exampleSet.getStatistics(getAttribute(), Statistics.MAXIMUM);
		missing = exampleSet.getStatistics(getAttribute(), Statistics.UNKNOWN);

		fireStatisticsChangedEvent();
	}

	/**
	 * Gets the average of the numerical values.
	 *
	 * @return
	 */
	public double getAverage() {
		return average;
	}

	/**
	 * Gets the standard deviation of the numerical values.
	 *
	 * @return
	 */
	public double getDeviation() {
		return deviation;
	}

	/**
	 * Gets the minimum of the numerical values.
	 *
	 * @return
	 */
	public double getMinimum() {
		return minimum;
	}

	/**
	 * Gets the maximum of the numerical values.
	 *
	 * @return
	 */
	public double getMaximum() {
		return maximum;
	}

	@Override
	public JFreeChart getChartOrNull(int index) {
		prepareCharts();
		if (index == INDEX_HISTOGRAM_CHART) {
			return chartsArray[index];
		}

		return null;
	}

	/**
	 * Creates a {@link HistogramDataset} for this {@link Attribute}.
	 *
	 * @param exampleSet
	 * @return
	 */
	private HistogramDataset createHistogramDataset(ExampleSet exampleSet) {
		HistogramDataset dataset = new HistogramDataset();

		double[] array = new double[exampleSet.size()];
		int count = 0;

		for (Example example : exampleSet) {
			double value = example.getDataRow().get(getAttribute());
			// don't use missing values because otherwise JFreeChart tries to plot them too which
			// can lead to false histograms
			if (!Double.isNaN(value)) {
				array[count++] = value;
			}
		}

		// add points to data set (if any)
		if (count > 0) {
			// truncate array if necessary
			if (count < array.length) {
				array = Arrays.copyOf(array, count);
			}
			dataset.addSeries(getAttribute().getName(), array, Math.min(array.length, MAX_BINS_HISTOGRAM));
		}

		return dataset;
	}

	/**
	 * Creates the histogram chart.
	 *
	 * @param exampleSet
	 * @return
	 */
	private JFreeChart createHistogramChart(ExampleSet exampleSet) {
		JFreeChart chart = ChartFactory.createHistogram(null, null, null, createHistogramDataset(exampleSet),
				PlotOrientation.VERTICAL, false, false, false);
		AbstractAttributeStatisticsModel.setDefaultChartFonts(chart);
		chart.setBackgroundPaint(null);
		chart.setBackgroundImageAlpha(0.0f);

		XYPlot plot = (XYPlot) chart.getPlot();
		plot.setRangeGridlinesVisible(false);
		plot.setDomainGridlinesVisible(false);
		plot.setOutlineVisible(false);
		plot.setRangeZeroBaselineVisible(false);
		plot.setDomainZeroBaselineVisible(false);
		plot.setBackgroundPaint(COLOR_INVISIBLE);
		plot.setBackgroundImageAlpha(0.0f);

		XYBarRenderer renderer = (XYBarRenderer) plot.getRenderer();
		renderer.setSeriesPaint(0, AttributeGuiTools.getColorForValueType(Ontology.NUMERICAL));
		renderer.setBarPainter(new StandardXYBarPainter());
		renderer.setDrawBarOutline(true);
		renderer.setShadowVisible(false);

		return chart;
	}

	@Override
	public void prepareCharts() {
		if (chartsArray[INDEX_HISTOGRAM_CHART] == null && getExampleSetOrNull() != null) {
			chartsArray[INDEX_HISTOGRAM_CHART] = createHistogramChart(getExampleSetOrNull());
		}
	}

}
