/* File: BarGraphDialog.java
 * Author: Jason Gookins
 * Description: This class creates the popup dialog that displays a node's histographic distribution after a run.
 */

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class BarGraphDialog extends JDialog implements ActionListener
{
	/************************
	 ** Instance Variables **
	 ************************/

	private BarGraphPanel barGraphPanel;
	private JButton okayButton;



	/**********************
	 ** Main Constructor **
	 **********************/

	public BarGraphDialog(JFrame parent, Node node)
	{
		super(parent, node.getName(), true);

		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setPreferredSize(new Dimension(800, 610));
		setResizable(false);

		barGraphPanel = new BarGraphPanel(node);

		okayButton = new JButton("OK");
		okayButton.setBounds(365, 535, 70, 30);
		okayButton.addActionListener(this);
		barGraphPanel.add(okayButton);

		drawBars(node);

		getContentPane().add(barGraphPanel);

		pack();
		setLocationRelativeTo(parent);
		setVisible(true);
	}



	/*******************
	 ** Action Events **
	 *******************/

	public void actionPerformed(ActionEvent evt)
	{
		if (evt.getSource().equals(okayButton))
		{
			dispose();
		}
	}



	/**********************
 	 ** Instance Methods **
	 **********************/

	private void drawBars(Node node)
	{
		ArrayList<Float> predicted = node.getNormalizedResultDistribution();
		ArrayList<Float> goal = node.getNormalizedGoalDistribution();
		ArrayList<Integer> denormalized = node.getResultDistribution();

		int unit = 350;
		int xInc = 60;
		int x1 = 0;

		if (goal.size() > 0)
		{
			x1 = 100 + (xInc / 2) + 1;

			for (int i = 0; i < goal.size(); i++)
			{
				JLabel bar = new JLabel();
				bar.setBackground(Color.BLUE);
				bar.setOpaque(true);
				bar.setToolTipText("Norm Val: " + Float.toString(goal.get(i)));
				bar.setBounds(x1, (int)(450 - goal.get(i) * unit), 20, (int)(goal.get(i) * unit) + 1);
				barGraphPanel.add(bar);
				x1 += xInc;
			}

			x1 = 100 + (xInc / 6);
		}
		else
		{
			x1 = 100 + (xInc / 3);
		}

		for (int i = 0; i < predicted.size(); i++)
		{
			JLabel bar = new JLabel();
			bar.setBackground(Color.RED);
			bar.setOpaque(true);
			if (node.getHasGiven() == 1 && node.getGivenDistMutability().equals("opt"))
			{
				bar.setToolTipText("Norm Val: " + Float.toString(predicted.get(i)) + ", Bin Val: " + Integer.toString(denormalized.get(i)));
			}
			else
			{
				bar.setToolTipText("Norm Val: " + Float.toString(predicted.get(i)));
			}
			bar.setBounds(x1, (int)(450 - predicted.get(i) * unit), 20, (int)(predicted.get(i) * unit) + 1);
			barGraphPanel.add(bar);
			x1 += xInc;
		}
	}



	/**********************
	 ** Internal Classes **
	 **********************/

	private class BarGraphPanel extends JPanel
	{
		private String title;
		private ArrayList<Float> predicted;
		private ArrayList<Float> goal;
		private Font font = new Font("lucida sans regular", Font.PLAIN, 12);

		public BarGraphPanel(Node node)
		{
			super(null);

			this.title = node.getName();
			this.predicted = node.getNormalizedResultDistribution();
			this.goal = node.getNormalizedGoalDistribution();
		}

		public void paint(Graphics g)
		{
			super.paint(g);

			Graphics2D g2 = (Graphics2D)g;
			RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			RenderingHints hintsNew = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
			hints.add(hintsNew);
			g2.setRenderingHints(hints);
			g2.setFont(font);
			FontRenderContext frc = g2.getFontRenderContext();

			int width = 800;
			int height = 550;
			int hPad = 100;
			int vPad = 100;

			int xInc = (width - (hPad + vPad)) / 10;
			int yInc = (height - (hPad + vPad)) / 10;

			//y axis
			g2.draw(new Line2D.Double(hPad, vPad, hPad, height - vPad));

			int x1 = hPad, y1 = vPad, x2 = hPad - 3, y2;

			//y axis tick marks
			for (int i = 0; i < 11; i++)
			{
				g2.draw(new Line2D.Double(x1, y1, x2, y1));
				y1 += yInc;
			}

			String text;
			LineMetrics lm;
			float xs, ys, textWidth, textHeight;
			int decrementer = 10;

			//y axis labels
			for (int i = 0; i <  11; i++)
			{
				text = String.valueOf((float)decrementer / 10);
				textWidth = (float)font.getStringBounds(text, frc).getWidth();
				lm = font.getLineMetrics(text, frc);
				textHeight = lm.getAscent();
				xs = hPad - textWidth - 7;
				ys = vPad + (i * yInc) + textHeight / 2;
				g2.drawString(text, xs, ys);
				decrementer--;
			}

			//x axis
			g2.draw(new Line2D.Double(hPad, height - vPad, width - hPad, height - vPad));

			x1 = hPad + (xInc / 2) + 1;
			y1 = height - vPad;
			y2 = y1 + 3;

			//x axis tick marks
			for (int i = 0; i < predicted.size(); i++)
			{
				g2.draw(new Line2D.Double(x1, y1, x1, y2));
				x1 += 60;
			}

			ys = height - vPad + 5;

			//x axis labels
			for (int i = 0; i < 10; i++)
			{
				text = String.valueOf(i + 1);
				textWidth = (float)font.getStringBounds(text, frc).getWidth();
				lm = font.getLineMetrics(text, frc);
				textHeight = lm.getHeight();
				xs = hPad + (xInc / 2) + (i * xInc) - (textWidth / 2) + 1;
				g2.drawString(text, xs, ys + textHeight);
			}
			text = "Bins";
			textWidth = (float)font.getStringBounds(text, frc).getWidth();
			lm = font.getLineMetrics(text, frc);
			textHeight = lm.getHeight();
			xs = (width / 2) - (textWidth / 2);
			ys = height - (vPad / 2) + (textHeight / 2) - 10;
			g2.drawString(text, xs, ys);

			//chart keys
			font = font.deriveFont(10f);
			g2.setFont(font);
			text = "Predicted =";
			textWidth = (float)font.getStringBounds(text, frc).getWidth();
			lm = font.getLineMetrics(text, frc);
			textHeight = lm.getHeight();
			xs = (width / 4) - (textWidth / 2);
			ys = height - (vPad / 2) + (textHeight / 2) - 10;
			g2.setColor(Color.black);
			g2.drawString(text, xs, ys);

			g2.setColor(Color.red);
			g2.fill(new Rectangle2D.Double(xs + textWidth + 5, height - (vPad / 2) - textHeight - 2, 33.0, textHeight));

			if (goal.size() > 0)
			{
				text = "Goal =";
				textWidth = (float)font.getStringBounds(text, frc).getWidth();
				lm = font.getLineMetrics(text, frc);
				textHeight = lm.getHeight();
				xs = (width - (width / 3.5f)) - textWidth;
				ys = height - (vPad / 2) + (textHeight / 2) - 10;
				g2.setColor(Color.black);
				g2.drawString(text, xs, ys);

				g2.setColor(Color.blue);
				g2.fill(new Rectangle2D.Double(xs + textWidth + 5, height - (vPad / 2) - textHeight - 2, 33.0, textHeight));
			}

			//chart title
			font = font.deriveFont(18f);
			g2.setFont(font);
			text = title;
			textWidth = (float)font.getStringBounds(text, frc).getWidth();
			lm = font.getLineMetrics(text, frc);
			textHeight = lm.getAscent();
			xs = (width/ 2) - (textWidth / 2);
			ys = (vPad / 2) + (textHeight / 2);
			g2.setFont(font);
			g2.setColor(Color.black);
			g2.drawString(title, xs, ys);

			//y axis label
			font = font.deriveFont(12f);
			g2.setFont(font);
			text = "Value";
			textWidth = (float)font.getStringBounds(text, frc).getWidth();
			lm = font.getLineMetrics(text, frc);
			textHeight = lm.getAscent();
			xs = (hPad / 2) - (textWidth / 2) + 15;
			ys = (height / 2) - (textHeight / 2);
			g2.rotate(-Math.PI/2.0);
			g2.setFont(font);
			g2.drawString(text, -ys, xs);
		}
	}
}