package de.ugoe.cs.eventbench.swing;

import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import de.ugoe.cs.eventbench.assertions.AssertEvent;
import de.ugoe.cs.eventbench.assertions.FileEqualsReplay;
import de.ugoe.cs.eventbench.assertions.TextEqualsReplay;
import de.ugoe.cs.eventbench.data.Event;
import de.ugoe.cs.eventbench.data.GlobalDataContainer;
import de.ugoe.cs.util.console.Console;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JOptionPane;
import javax.swing.JFileChooser;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;
import javax.swing.JList;
import javax.swing.border.EtchedBorder;
import javax.swing.JTree;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import javax.swing.event.TreeSelectionListener;
import javax.swing.event.TreeSelectionEvent;

public class DlgInsert extends JDialog {

	/**
	 * Id for object serialization.
	 */
	private static final long serialVersionUID = 1L;

	private final JPanel contentPanel = new JPanel();
	private JTextField textFieldExpectedValue;
	private JTextField textFieldActualFile;
	private JTextField textFieldExpectedFile;

	/**
	 * Launch the application.
	 */
	public static void showDialog(List<Event<?>> sequences, int selectedIndex,
			final boolean insertBefore) {
		try {
			DlgInsert dialog = new DlgInsert(sequences, selectedIndex,
					insertBefore);
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			dialog.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Create the dialog.
	 */
	@SuppressWarnings("unchecked")
	public DlgInsert(final List<Event<?>> sequences, final int selectedIndex,
			final boolean insertBefore) {

		final javax.swing.DefaultListModel modelListTargets = new javax.swing.DefaultListModel();

		setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		setTitle("Insert testcase");

		setModal(true);
		setBounds(100, 100, 530, 631);
		getContentPane().setLayout(new BorderLayout());
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		getContentPane().add(contentPanel, BorderLayout.CENTER);
		contentPanel.setLayout(null);
		final JComboBox comboBoxTestcase = new JComboBox();
		final JPanel panelTextEquals = new JPanel();
		panelTextEquals.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null,
				null));
		final JPanel panelFileEquals = new JPanel();
		panelFileEquals.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null,
				null));

		// JComboBox: comboBoxTestcase
		comboBoxTestcase.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if ("comboBoxChanged".equals(arg0.getActionCommand())) {

					// TextEquals
					if (comboBoxTestcase.getSelectedIndex() == 0) {
						panelTextEquals.setVisible(true);
						panelFileEquals.setVisible(false);
					}
					// FileEquals
					else if (comboBoxTestcase.getSelectedIndex() == 1) {
						panelTextEquals.setVisible(false);
						panelFileEquals.setVisible(true);
					}
				}
			}
		});
		comboBoxTestcase.setModel(new DefaultComboBoxModel(new String[] {
				"TextEquals", "OutputFileEquals" }));
		comboBoxTestcase.setSelectedIndex(0);
		comboBoxTestcase.setBounds(91, 11, 178, 20);
		contentPanel.add(comboBoxTestcase);
		// ***

		// JLabel
		JLabel label = new JLabel("Testcase:");
		label.setBounds(12, 14, 86, 14);
		contentPanel.add(label);

		JLabel label_1 = new JLabel("Expected value:");
		label_1.setBounds(10, 11, 96, 14);

		JLabel label_2 = new JLabel("Target:");
		label_2.setBounds(10, 38, 86, 14);
		// ***

		// JTextField: textFieldExpectedValue
		textFieldExpectedValue = new JTextField();
		textFieldExpectedValue.setColumns(10);
		textFieldExpectedValue.setBounds(116, 8, 368, 20);
		// ***

		// JPanel: panel
		panelTextEquals.setLayout(null);
		panelTextEquals.setBounds(10, 39, 494, 350);
		contentPanel.add(panelTextEquals);
		panelTextEquals.add(label_1);
		panelTextEquals.add(label_2);
		panelTextEquals.add(textFieldExpectedValue);

		JScrollPane scrollPane = new JScrollPane();
		scrollPane.setBounds(421, 36, 63, 14);
		panelTextEquals.add(scrollPane);

		final JList listTargets = new JList(modelListTargets);
		scrollPane.setViewportView(listTargets);

		JScrollPane scrollPane_1 = new JScrollPane();
		scrollPane_1.setBounds(10, 63, 474, 276);
		panelTextEquals.add(scrollPane_1);

		// JTree to hold the targets
		final JTree tree = new JTree();
		tree.addTreeSelectionListener(new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent arg0) {
				TreePath path = tree.getSelectionPath();
				textFieldExpectedValue.setText(path.toString());
			}
		});
		DefaultTreeModel treeModel = new DefaultTreeModel(null);
		DefaultMutableTreeNode root = new DefaultMutableTreeNode("Targets");
		treeModel.setRoot(root);
		tree.setModel(treeModel);

		// List<DefaultMutableTreeNode> nodes = new
		// ArrayList<DefaultMutableTreeNode>();
		List<String> listTargets1 = new ArrayList<String>(); // targets out of
																// GlobalDataContainer
		List<String> sortedTargets = new ArrayList<String>(); // targets will be
																// sorted by
																// number of
																// parts,
																// splitted at
																// "/>"

		try {
			listTargets1 = (List<String>) GlobalDataContainer.getInstance()
					.getData("ListTargets");
		} catch (ClassCastException e) {
			Console.println("Not able to cast data in GlobalDataContainer to List of Strings");
		}

		int parts = 1;
		while (sortedTargets.size() < listTargets1.size()) {
			for (int i = 0; i < listTargets1.size(); i++) {
				String splitted[] = listTargets1.get(i).split("/>");

				// sort targets by number of parts
				if (splitted.length != parts)
					continue;

				sortedTargets.add(listTargets1.get(i));

				// insert in tree
				DefaultMutableTreeNode node = compareTargetWithNode(root,
						listTargets1.get(i));

				if (node == null) {
					DefaultMutableTreeNode newNode[] = new DefaultMutableTreeNode[splitted.length];

					for (int j = 0; j < splitted.length; j++) {
						newNode[j] = new DefaultMutableTreeNode(splitted[j]
								+ "/>");

						if (j == 0) {
							root.add(newNode[0]);
						} else {
							newNode[j - 1].add(newNode[j]);
						}
					}
				} else {
					for (int j = 0; j < splitted.length; j++) {
						if (node.toString().compareTo(splitted[j] + "/>") != 0)
							continue;

						DefaultMutableTreeNode newNode[] = new DefaultMutableTreeNode[splitted.length
								- j - 1];
						for (int k = 0; k < newNode.length; k++) {
							newNode[k] = new DefaultMutableTreeNode(splitted[j
									+ k + 1]
									+ "/>");

							if (k == 0) {
								node.add(newNode[0]);
							} else {
								newNode[k - 1].add(newNode[k]);
							}
						}
					}
				}
			}
			parts++;
		}
		scrollPane_1.setViewportView(tree);

		if (listTargets.getComponentCount() > 0)
			listTargets.setSelectedIndex(0);

		panelFileEquals.setBounds(12, 400, 494, 120);
		contentPanel.add(panelFileEquals);
		panelFileEquals.setLayout(null);
		panelFileEquals.setVisible(false);

		JLabel lblNewLabel = new JLabel("Actual file:");
		lblNewLabel.setBounds(10, 11, 89, 14);
		panelFileEquals.add(lblNewLabel);

		textFieldActualFile = new JTextField();
		textFieldActualFile.setBounds(10, 30, 474, 20);
		panelFileEquals.add(textFieldActualFile);
		textFieldActualFile.setColumns(10);

		JButton btnNewButton = new JButton("Search file");
		btnNewButton.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent arg0) {
				final JFileChooser fc = new JFileChooser();
				if (fc.showOpenDialog(contentPanel) == 0) {
					textFieldExpectedFile.setText(fc.getSelectedFile()
							.getAbsolutePath());
				}
			}
		});
		btnNewButton.setBounds(93, 61, 89, 23);
		panelFileEquals.add(btnNewButton);

		JLabel lblNewLabel_1 = new JLabel("Expected file:");
		lblNewLabel_1.setBounds(10, 70, 89, 14);
		panelFileEquals.add(lblNewLabel_1);

		textFieldExpectedFile = new JTextField();
		textFieldExpectedFile.setColumns(10);
		textFieldExpectedFile.setBounds(10, 88, 474, 20);
		panelFileEquals.add(textFieldExpectedFile);
		{
			JPanel buttonPane = new JPanel();
			buttonPane.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null,
					null));
			buttonPane.setBounds(12, 531, 494, 51);
			contentPanel.add(buttonPane);
			{
				// JButton: okButton
				JButton okButton = new JButton("Insert");
				okButton.setBounds(349, 11, 135, 31);
				okButton.addMouseListener(new MouseAdapter() {
					public void mouseClicked(MouseEvent arg0) {

						// FileEquals
						if (panelFileEquals.isVisible()) {
							if (textFieldActualFile.getText().length() == 0)
								JOptionPane.showMessageDialog(null,
										"Please declare an actual file.",
										"No actual file declared",
										JOptionPane.OK_OPTION);
							else if (!new File(textFieldExpectedFile.getText())
									.exists()) {
								if (textFieldExpectedFile.getText().length() == 0)
									JOptionPane.showMessageDialog(null,
											"Please choose an expected file.",
											"No expected file chosen",
											JOptionPane.OK_OPTION);
								else
									JOptionPane.showMessageDialog(
											null,
											"The expected file \""
													+ textFieldActualFile
															.getText()
													+ "\" does not exist.",
											"Expected file does not exist",
											JOptionPane.OK_OPTION);
								return;
							} else {
								FileEqualsReplay file = new FileEqualsReplay();
								file.setActualFile(textFieldActualFile
										.getText());
								file.setExpectedFile(textFieldExpectedFile
										.getText());

								AssertEvent<FileEqualsReplay> e = new AssertEvent<FileEqualsReplay>(
										"FileEquals");
								e.addReplayEvent(file);
								e.setTarget(" ");
								if (insertBefore)
									sequences.add(selectedIndex, e);
								else
									sequences.add(selectedIndex + 1, e);
							}
						}
						// TextEquals
						else {
							if (textFieldExpectedValue.getText().length() == 0) {
								JOptionPane
										.showMessageDialog(
												null,
												"\"Expected value\" is missing.",
												"Expected value",
												JOptionPane.OK_OPTION);
								return;
							} else if (listTargets.getSelectedIndex() == -1) {
								JOptionPane.showMessageDialog(null,
										"Please select a target.",
										"No target selected",
										JOptionPane.OK_OPTION);
								return;
							} else {
								TextEqualsReplay text = new TextEqualsReplay();
								text.setExpectedValue(textFieldExpectedValue
										.getText());
								text.setTarget(modelListTargets.get(
										listTargets.getSelectedIndex())
										.toString());

								AssertEvent<TextEqualsReplay> e = new AssertEvent<TextEqualsReplay>(
										"TextEquals");
								e.addReplayEvent(text);
								e.setTarget(" ");
								if (insertBefore)
									sequences.add(selectedIndex, e);
								else
									sequences.add(selectedIndex + 1, e);
							}
						}

						dispose();
					}
				});
				buttonPane.setLayout(null);
				okButton.setActionCommand("OK");
				buttonPane.add(okButton);
				getRootPane().setDefaultButton(okButton);
				// ***
			}

			{
				// JButton: cancelButton
				JButton cancelButton = new JButton("Cancel");
				cancelButton.setBounds(10, 11, 135, 31);
				cancelButton.addMouseListener(new MouseAdapter() {

					public void mouseClicked(MouseEvent arg0) {
						dispose();
					}
				});
				cancelButton.setActionCommand("Cancel");
				buttonPane.add(cancelButton);
				// ***
			}
		}
		// ***
	}

	DefaultMutableTreeNode compareTargetWithNode(DefaultMutableTreeNode node,
			String target) {

		if (node.isLeaf()) {
			if (target.contains(node.toString()))
				return node;
			else
				return null;
		} else {
			for (@SuppressWarnings("unchecked")
			Enumeration<DefaultMutableTreeNode> e = node.children(); e
					.hasMoreElements();) {
				DefaultMutableTreeNode nodeReturn = compareTargetWithNode(
						e.nextElement(), target);
				if (nodeReturn == null) {
					if (target.contains(node.toString()))
						return node;
				} else
					return nodeReturn;
			}
		}

		return null;
	}
}