/* File: EditNodeDialog.java
 * Author: Jason Gookins
 * Description: This class creates the dialog for editing a node.
 */

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyVetoException;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFormattedTextField;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

public class EditNodeDialog extends JInternalFrame implements ActionListener, FocusListener
{
	/************************
	 ** Instance Variables **
	 ************************/

	private Belief belief;
	private NetworkPane networkPane;
	private ArrayList<Node> nodes;
	private Node editNode;

	private View currentView;
	private String originalNodeName;

	private JTabbedPane tabbedPanel;

	private JFormattedTextField nameTextField;
	private JTextField priorityTextField;
	private DefaultComboBoxModel operationList;
	private JComboBox operationComboBox;

	private JCheckBox hasDistCheckBox;
	private ArrayList<JTextField> bins;
	private JLabel minimumLabel;
	private JTextField minimumTextField;
	private JLabel maximumLabel;
	private JTextField maximumTextField;
	private JRadioButton mutableRadioButton;
	private JRadioButton fixedRadioButton;

	private JTextField fullNameTextField;
	private JTextArea descriptionTextArea;

	private JButton okayButton;
	private JButton cancelButton;

	private NodeVerifier nodeVerifier;



	/**********************
	 ** Main Constructor **
	 **********************/

	public EditNodeDialog(Belief belief, NetworkPane networkPane, ArrayList<Node> nodes, Node editNode, View currentView)
	{
		super("Edit Node", false, false, false, false);

		nodeVerifier = new NodeVerifier();

		this.belief = belief;
		this.networkPane = networkPane;
		this.nodes = nodes;
		this.editNode = editNode;
		this.currentView = currentView;
		this.originalNodeName = editNode.getName();

		setPreferredSize(new Dimension(320, 250));

		JPanel dialogPanel = new JPanel(null);

		tabbedPanel = new JTabbedPane();
		tabbedPanel.setBounds(0, 0, 314, 177);

		JPanel dataPanel = new JPanel(null);

		JLabel nameLabel = new JLabel("Name:");
		nameLabel.setBounds(50, 25, 75, 25);
		dataPanel.add(nameLabel);
		nameTextField = new JFormattedTextField();
		nameTextField.setBounds(126, 25, 150, 25);
		nameTextField.setInputVerifier(nodeVerifier);
		nameTextField.addFocusListener(this);
		dataPanel.add(nameTextField);

		JLabel priorityLabel = new JLabel("Priority:");
		priorityLabel.setBounds(50, 63, 75, 25);
		dataPanel.add(priorityLabel);
		priorityTextField = new JTextField();
		priorityTextField.setBounds(126, 63, 150, 25);
		priorityTextField.setInputVerifier(nodeVerifier);
		priorityTextField.addFocusListener(this);
		dataPanel.add(priorityTextField);

		JLabel operationLabel = new JLabel("Operation:");
		operationLabel.setBounds(50, 101, 75, 25);
		dataPanel.add(operationLabel);
		operationList = new DefaultComboBoxModel();
		operationList.addElement("null");
		operationComboBox = new JComboBox(operationList);
		operationComboBox.setBounds(126, 101, 149, 25);
		dataPanel.add(operationComboBox);

		JPanel distributionPanel = new JPanel(null);

		hasDistCheckBox = new JCheckBox();
		hasDistCheckBox.setBounds(85, 5, 175, 25);
		hasDistCheckBox.addActionListener(this);
		distributionPanel.add(hasDistCheckBox);

		bins = new ArrayList<JTextField>();
		for (int i = 0; i < 10; i++)
		{
			JTextField bin = new JTextField();
			bin.setBounds(10 + (i * 29), 40, 30, 30);
			bin.setBorder(BorderFactory.createLineBorder(new Color(184, 207, 229)));
			bin.setHorizontalAlignment(JLabel.CENTER);
			bin.setEnabled(false);
			bin.setText("0");
			bin.setInputVerifier(nodeVerifier);
			bin.addFocusListener(this);
			distributionPanel.add(bin);
			bins.add(bin);
		}

		minimumLabel = new JLabel("Minimum:");
		minimumLabel.setBounds(15, 85, 75, 25);
		minimumLabel.setEnabled(false);
		distributionPanel.add(minimumLabel);
		minimumTextField = new JTextField();
		minimumTextField.setBounds(85, 85, 75, 25);
		minimumTextField.setEnabled(false);
		minimumTextField.setInputVerifier(nodeVerifier);
		minimumTextField.addFocusListener(this);
		distributionPanel.add(minimumTextField);

		maximumLabel = new JLabel("Maximum:");
		maximumLabel.setBounds(15, 115, 75, 25);
		maximumLabel.setEnabled(false);
		distributionPanel.add(maximumLabel);
		maximumTextField = new JTextField();
		maximumTextField.setBounds(85, 115, 75, 25);
		maximumTextField.setEnabled(false);
		maximumTextField.setInputVerifier(nodeVerifier);
		maximumTextField.addFocusListener(this);
		distributionPanel.add(maximumTextField);

		mutableRadioButton = new JRadioButton("Mutable");
		mutableRadioButton.setBounds(200, 85, 75, 25);
		mutableRadioButton.setEnabled(false);
		distributionPanel.add(mutableRadioButton);
		fixedRadioButton = new JRadioButton("Fixed");
		fixedRadioButton.setBounds(200, 115, 75, 25);
		fixedRadioButton.setEnabled(false);
		distributionPanel.add(fixedRadioButton);

		ButtonGroup mutabilityGroup = new ButtonGroup();
		mutabilityGroup.add(mutableRadioButton);
		mutabilityGroup.add(fixedRadioButton);

		JPanel descriptionPanel = new JPanel(null);

		JLabel fullNameLabel = new JLabel("Full Name:");
		fullNameLabel.setBounds(7, 7, 75, 20);
		descriptionPanel.add(fullNameLabel);
		fullNameTextField = new JTextField();
		fullNameTextField.setBounds(83, 7, 220, 20);
		descriptionPanel.add(fullNameTextField);

		JLabel descriptionLabel = new JLabel("Description:");
		descriptionLabel.setBounds(7, 30, 75, 20);
		descriptionPanel.add(descriptionLabel);
		descriptionTextArea = new JTextArea();
		descriptionTextArea.setBorder(BorderFactory.createEmptyBorder(1, 3, 3, 3));
		descriptionTextArea.setLineWrap(true);
		descriptionTextArea.setWrapStyleWord(true);
		JScrollPane descriptionScrollPane = new JScrollPane(descriptionTextArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		descriptionScrollPane.setBounds(5, 50, 300, 95);
		descriptionPanel.add(descriptionScrollPane);

		tabbedPanel.addTab("Data", dataPanel);
		tabbedPanel.addTab("Distribution", distributionPanel);
		tabbedPanel.addTab("Description", descriptionPanel);

		dialogPanel.add(tabbedPanel);

		okayButton = new JButton("Okay");
		okayButton.setBounds(80, 185, 75, 25);
		okayButton.addActionListener(this);
		dialogPanel.add(okayButton);
		cancelButton = new JButton("Cancel");
		cancelButton.setBounds(165, 185, 75, 25);
		cancelButton.addActionListener(this);
		dialogPanel.add(cancelButton);

		setContentPane(dialogPanel);

		putClientProperty("JInternalFrame.frameType", "optionDialog");

		Dimension size = getPreferredSize();
		Dimension rootSize = belief.getRootPane().getSize();

		setBounds((rootSize.width - size.width) / 2, (rootSize.height - size.height) / 2, size.width, size.height);

		loadNodeInfo();

		pack();
		belief.getFirstEventPane().setVisible(true);
		setVisible(true);
		belief.getLayeredPane().add(this, new Integer(1));

		try
		{
			setSelected(true);
		}
		catch (PropertyVetoException ignored) { }
	}



	/*******************
	 ** Action Events **
	 *******************/

	public void actionPerformed(ActionEvent evt)
	{
		if (evt.getSource().equals(hasDistCheckBox))
		{
			toggleDistPanel();
		}
		else if (evt.getSource().equals(okayButton))
		{
			modifyNodeData();
			dispose();
			belief.getFirstEventPane().setVisible(false);
		}
		else if (evt.getSource().equals(cancelButton))
		{
			dispose();
			belief.getFirstEventPane().setVisible(false);
		}
	}



	/******************
	 ** Focus Events **
	 ******************/

	public void focusGained(FocusEvent evt)
	{
		final JTextField source = (JTextField)evt.getSource();

		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				source.selectAll();
			}
		});
	}

	public void focusLost(FocusEvent evt) { }



	/**********************
	 ** Instance Methods **
	 **********************/

	private void loadNodeInfo()
	{
		nameTextField.setText(editNode.getName());

		priorityTextField.setText(Integer.toString(editNode.getPriority()));

		if (editNode.getChildren().size() == 1)
		{
			operationList.addElement("not");
		}
		else if (editNode.getChildren().size() > 1)
		{
			operationList.addElement("and");
			operationList.addElement("or");
		}
		operationComboBox.setSelectedItem(editNode.getOperation());

		if (editNode.getChildren().size() > 0)
		{
			hasDistCheckBox.setText("Has GOAL Distribution");

			if (editNode.getHasGoal() == 1)
			{
				hasDistCheckBox.setSelected(true);
				toggleDistPanel();

				for (int i = 0; i < bins.size(); i++)
				{
					JTextField bin = bins.get(i);

					bin.setText(Integer.toString(currentView.getGoalDistributions().get(currentView.getGoalDistNodes().indexOf(editNode)).get(i)));
				}
			}
		}
		else
		{
			hasDistCheckBox.setText("Has GIVEN Distribution");

			if (editNode.getHasGiven() == 1)
			{
				hasDistCheckBox.setSelected(true);
				toggleDistPanel();

				for (int i = 0; i < bins.size(); i++)
				{
					JTextField bin = bins.get(i);

					bin.setText(Integer.toString(currentView.getGivenDistributions().get(currentView.getGivenDistNodes().indexOf(editNode)).get(i)));
				}
			}
		}

		minimumTextField.setText(Integer.toString(editNode.getMinimumBound()));
		maximumTextField.setText(Integer.toString(editNode.getMaximumBound()));

		if (editNode.getGivenDistMutability().equals("opt"))
		{
			mutableRadioButton.setSelected(true);
		}
		else
		{
			fixedRadioButton.setSelected(true);
		}

		if (editNode.getDescription().length() > 0)
		{
			fullNameTextField.setText(editNode.getDescription().substring(9, editNode.getDescription().indexOf("</b>")));
			descriptionTextArea.setText(editNode.getDescription().substring(editNode.getDescription().indexOf("</b>") + 7, editNode.getDescription().indexOf("</html>")));
		}
	}

	private void toggleDistPanel()
	{
		if (hasDistCheckBox.isSelected())
		{
			for (JTextField bin : bins)
			{
				bin.setEnabled(true);
				bin.setBorder(BorderFactory.createLineBorder(Color.BLACK));
			}

			minimumLabel.setEnabled(true);
			minimumTextField.setEnabled(true);
			maximumLabel.setEnabled(true);
			maximumTextField.setEnabled(true);

			if (editNode.getChildren().size() == 0)
			{
				mutableRadioButton.setEnabled(true);
				fixedRadioButton.setEnabled(true);
			}
		}
		else
		{
			for (JTextField bin : bins)
			{
				bin.setEnabled(false);
				bin.setBorder(BorderFactory.createLineBorder(new Color(184, 207, 229)));
			}
			minimumLabel.setEnabled(false);
			minimumTextField.setEnabled(false);
			maximumLabel.setEnabled(false);
			maximumTextField.setEnabled(false);
			mutableRadioButton.setEnabled(false);
			fixedRadioButton.setEnabled(false);
		}
	}

	private void modifyNodeData()
	{
		if (nameTextField.getText().compareTo(editNode.getName()) != 0)
		{
			editNode.setName(nameTextField.getText());
		}

		if (priorityTextField.getText().compareTo(Integer.toString(editNode.getPriority())) != 0)
		{
			editNode.setPriority(Integer.parseInt(priorityTextField.getText()));
		}

		if (((String)operationComboBox.getSelectedItem()).compareTo(editNode.getOperation()) != 0)
		{
			editNode.setOperation((String)operationComboBox.getSelectedItem());
		}

		if (hasDistCheckBox.isSelected())
		{
			if (editNode.getChildren().size() > 0)
			{
				editNode.setHasGoal(1);
			}
			else
			{
				editNode.setHasGiven(1);
			}

			ArrayList<Integer> distribution = new ArrayList<Integer>();

			for (JTextField bin : bins)
			{
				distribution.add(Integer.parseInt(bin.getText()));
			}

			if (editNode.getHasGiven() == 1)
			{
				if (currentView.getGivenDistNodes().contains(editNode))
				{
					currentView.getGivenDistributions().set(currentView.getGivenDistNodes().indexOf(editNode), distribution);
				}
				else
				{
					currentView.getGivenDistNodes().add(editNode);
					currentView.getGivenDistributions().add(distribution);
				}

				if (mutableRadioButton.isSelected())
				{
					editNode.setGivenDistMutability("opt");
				}
				else
				{
					editNode.setGivenDistMutability("fixed");
				}
			}
			else if (editNode.getHasGoal() == 1)
			{

				if (currentView.getGoalDistNodes().contains(editNode))
				{
					currentView.getGoalDistributions().set(currentView.getGoalDistNodes().indexOf(editNode), distribution);
				}
				else
				{
					currentView.getGoalDistNodes().add(editNode);

					currentView.getGoalDistributions().add(distribution);
				}
			}

			if (minimumTextField.getText().compareTo(Integer.toString(editNode.getMinimumBound())) != 0)
			{
				editNode.setMinimumBound(Integer.parseInt(minimumTextField.getText()));
			}

			if (maximumTextField.getText().compareTo(Integer.toString(editNode.getMaximumBound())) != 0)
			{
				editNode.setMaximumBound(Integer.parseInt(maximumTextField.getText()));
			}
		}
		else
		{
			if (editNode.getChildren().size() > 0)
			{
				editNode.setHasGoal(0);
				editNode.setGoalDistribution(new ArrayList<Integer>());
			}
			else
			{
				editNode.setHasGiven(0);
				editNode.setGivenDistribution(new ArrayList<Integer>());
			}

			editNode.setGivenDistMutability("opt");
		}

		if (fullNameTextField.getText().length() > 0 && descriptionTextArea.getText().length() > 0)
		{
			editNode.setDescription("<html><b>" + fullNameTextField.getText() + "</b> - " + descriptionTextArea.getText() + "</html>");
		}
		else if (fullNameTextField.getText().length() > 0 && descriptionTextArea.getText().length() == 0)
		{
			editNode.setDescription("<html><b>" + fullNameTextField.getText() + "</b></html>");
		}
		else if (fullNameTextField.getText().length() == 0 && descriptionTextArea.getText().length() > 0)
		{
			editNode.setDescription("<html>" + descriptionTextArea.getText() + "</html>");
		}

		networkPane.editNode(originalNodeName);
	}



	/**********************
	 ** Internal Classes **
	 **********************/

	private class NodeVerifier extends InputVerifier
	{
		private NumberFormat numberFormat = NumberFormat.getIntegerInstance();

		public boolean verify(JComponent input)
		{
			int value = 0;

			if (input.equals(nameTextField))
			{
				if (nameTextField.getText().length() < 1)
				{
					nameTextField.setText(editNode.getName());
				}
				else
				{
					boolean nameExists = false;

					for (Node node : nodes)
					{
						if (nameTextField.getText().compareToIgnoreCase(node.getName()) == 0)
						{
							nameExists = true;

							break;
						}
					}

					if (nameTextField.getText().compareToIgnoreCase(originalNodeName) == 0)
					{
						nameExists = false;
					}

					if (nameExists)
					{
						ErrorDialog errorDialog = new ErrorDialog("Node Name Error", new JOptionPane("A node with that name already exists.", JOptionPane.ERROR_MESSAGE));
					}
				}
			}
			else if (input.equals(priorityTextField))
			{
				try
				{
					value = numberFormat.parse(priorityTextField.getText()).intValue();

					if (value < 0)
					{
						priorityTextField.setText(Integer.toString(0));
					}
					else if (value > 999)
					{
						priorityTextField.setText(Integer.toString(999));
					}
				}
				catch (ParseException pe)
				{
					priorityTextField.setText(Integer.toString(editNode.getPriority()));
				}
			}
			else if (bins.contains(input))
			{
				try
				{
					value = numberFormat.parse(((JTextField)input).getText()).intValue();

					if (value < 0)
					{
						((JTextField)input).setText(Integer.toString(0));
					}
					else if (value > 999)
					{
						((JTextField)input).setText(Integer.toString(999));
					}
				}
				catch (ParseException pe)
				{
					((JTextField)input).setText(Integer.toString(0));
				}
			}
			else if (input.equals(minimumTextField))
			{
				try
				{
					value = numberFormat.parse(minimumTextField.getText()).intValue();

					if (value >= Integer.parseInt(maximumTextField.getText()))
					{
						minimumTextField.setText(Integer.toString(editNode.getMinimumBound()));
					}
					else if (value < -999)
					{
						minimumTextField.setText(Integer.toString(-999));
					}
				}
				catch (ParseException pe)
				{
					minimumTextField.setText(Integer.toString(editNode.getMinimumBound()));
				}
			}
			else if (input.equals(maximumTextField))
			{
				try
				{
					value = numberFormat.parse(maximumTextField.getText()).intValue();

					if (value <= Integer.parseInt(minimumTextField.getText()))
					{
						maximumTextField.setText(Integer.toString(editNode.getMaximumBound()));
					}
					else if (value > 999)
					{
						maximumTextField.setText(Integer.toString(999));
					}
				}
				catch (ParseException pe)
				{
					maximumTextField.setText(Integer.toString(editNode.getMaximumBound()));
				}
			}

			return true;
		}
	}



	/**********************
	 ** Internal Classes **
	 **********************/

	private class ErrorDialog extends InternalModalDialog
	{
		public ErrorDialog(String title, JOptionPane pane)
		{
			super(title, belief, pane);
		}

		public void cleanUpAfterClosing()
		{
			nameTextField.setText(editNode.getName());
		}
	}
}