import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import java.awt.*;
import java.util.*;
import java.text.*;

public class StatisticsPanel extends JPanel implements TableModelListener {

	/**
	 * This panel shows the statistic information.
	 */
	private static final long serialVersionUID = -8705632500466390193L;

	/* TextFields to display the statistics. */
	private JTextField averageField, stdDevField, medianField;
	private JTable table;
	private String[][] records;

	/**
	 * Creates a StatisticsPanel object.
	 */
	public StatisticsPanel(JTable table) {
		setupPanel();
		this.table = table;
		repaint();
	}

	/**
	 * Refreshes the statistics displayed by a StatisticsPanel object.
	 */
	public void paintComponent(Graphics g) {
		/*
		 * Calculate the statistics based on the overall marks extracted from
		 * the records object.
		 */

		// Obtain the records object.
		MyTableModel tabMod = (MyTableModel) table.getModel();
		String[][] records = tabMod.getData();

		double stdDev = getStdDev(records);
		double average = getAverage(records);
		int median = getMedian(records);

		/*
		 * Update the textfields with the new statistics values.
		 */
		averageField.setText(formatNumber(average));
		stdDevField.setText(formatNumber(stdDev));
		medianField.setText(formatNumber(median));
		super.paintComponent(g);
	}

	/**
	 * Returns the standard deviation for a series of values.
	 */
	private double getStdDev(String[][] series) {
		double sum = 0.0;
		double average = getAverage(series);

		for (int i = 0; i < series.length; i++) {
			sum += (Integer.parseInt(series[i][1]) - average)
					* (Integer.parseInt(series[i][1]) - average);
		}
		return Math.sqrt(sum / (double) (series.length - 1));
	}

	/**
	 * Returns the average of a series of values.
	 */
	private double getAverage(String[][] series) {
		double total = 0;

		if (series.length == 0) {
			return 0;
		}

		for (int i = 0; i < series.length; i++) {
			total += Integer.parseInt(series[i][1]);
		}
		return total / series.length;
	}

	/**
	 * Returns the median value for a series of values.
	 */
	private int getMedian(String[][] series) {

		int[] temp = new int[20];
		for (int i = 0; i < 20; i++)
			temp[i] = Integer.parseInt(series[i][1]);

		/* Sort the series. */
		Arrays.sort(temp);
		return temp[temp.length / 2];
	}

	/**
	 * Returns a String representation of a decimal number. The representation
	 * is to two decimal places.
	 */
	private String formatNumber(double number) {
		DecimalFormat format = new DecimalFormat("0.##");
		return format.format(number);
	}

	public void tableChanged(TableModelEvent e) {
		repaint();
	}

	/**
	 * Sets up the GUI for this StatisticsView object.
	 */
	private void setupPanel() {
		JLabel averageLabel = new JLabel("Average");
		JLabel stdDevLabel = new JLabel("Standard deviation");
		JLabel medianLabel = new JLabel("Median");

		averageField = new JTextField();
		averageField.setEditable(false);
		stdDevField = new JTextField();
		stdDevField.setEditable(false);
		medianField = new JTextField();
		medianField.setEditable(false);

		JPanel labelPane = new JPanel();
		labelPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
		labelPane.setLayout(new GridLayout(0, 1));
		labelPane.add(averageLabel);
		labelPane.add(stdDevLabel);
		labelPane.add(medianLabel);

		JPanel valuePane = new JPanel();
		valuePane.setLayout(new GridLayout(0, 1));
		valuePane.add(averageField);
		valuePane.add(stdDevField);
		valuePane.add(medianField);

		setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		setLayout(new BorderLayout());
		add(labelPane, BorderLayout.WEST);
		add(valuePane, BorderLayout.CENTER);
	}
}
