package tv.porst.swfretools.dissector.gui;

import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;

import net.iharder.dnd.FileDrop;
import tv.porst.swfretools.dissector.gui.main.DetailPanel;
import tv.porst.swfretools.dissector.gui.main.TreePanel;
import tv.porst.swfretools.dissector.gui.main.actions.OpenAction;
import tv.porst.swfretools.dissector.gui.main.flashtree.FlashTree;
import tv.porst.swfretools.dissector.gui.main.flashtree.FlashTreeNodeClickHandler;
import tv.porst.swfretools.dissector.gui.main.flashtree.FlashTreeNodeSelectionHandler;
import tv.porst.swfretools.dissector.gui.main.flashtree.nodes.FlashTreeNode;
import tv.porst.swfretools.dissector.gui.main.implementations.FileActions;
import tv.porst.swfretools.dissector.gui.main.models.FileModel;

/**
 * Main window of Flash Dissector.
 */
public final class MainWindow extends JFrame {

	/**
	 * Tree panel that shows the structures of the loaded SWF files.
	 */
	private final TreePanel panel;

	/**
	 * Selection listener that updates the GUI when a new node in the
	 * tree panel was activated.
	 */
	private final TreeSelectionListener internalTreeSelectionListener = new InternalTreeSelectionListener();

	/**
	 * Mouse listener that handles clicks on nodes.
	 */
	private final MouseListener internalTreeClickListener = new InternalTreeClickListener();

	/**
	 * Panel that is shown on the right-hand side of the window.
	 */
	private final DetailPanel detailPanel = new DetailPanel();

	/**
	 * Creates a new main window object.
	 * 
	 * @param filesToOpen List of SWF files to open initially.
	 */
	public MainWindow(final List<String> filesToOpen) {
		super("Flash Dissector");

		setLayout(new BorderLayout());

		add(detailPanel);

		final FileModel fileModel = new FileModel();

		panel = new TreePanel(fileModel);

		final FlashTree tree = panel.getTree();
		tree.addTreeSelectionListener(internalTreeSelectionListener);
		tree.addMouseListener(internalTreeClickListener);

		add(panel, BorderLayout.WEST);

		// Add Drag & Drop capabilities to the panel to make it easier to open files.
		new FileDrop(panel, new FileDrop.Listener() {
			@Override
			public void filesDropped(final File[] files) {
				for (final File file : files) {
					FileActions.openFile(tree, fileModel, file);
				}
			}
		});

		final JMenuBar menuBar = new JMenuBar();

		final JMenu menu = new JMenu("File");

		menu.add(new OpenAction(tree, fileModel));

		menuBar.add(menu);

		setJMenuBar(menuBar);

		setSize(900, 600);
		setLocationRelativeTo(null);

		for (final String fileName : filesToOpen) {
			FileActions.openFile(tree, fileModel, new File(fileName));
		}
	}

	/**
	 * Handles clicks on tree nodes.
	 */
	private final class InternalTreeClickListener extends MouseAdapter {

		/**
		 * Handles right-clicks on tree nodes.
		 * 
		 * @param e Mouse event created by the right-click.
		 */
		private void handleRightClick(final MouseEvent e) {

			final int x = e.getX();
			final int y = e.getY();

			final JTree tree = (JTree)e.getSource();
			final TreePath path = tree.getPathForLocation(x, y);

			if (path == null) {
				return;
			}

			tree.setSelectionPath(path);

			final FlashTreeNode<?> node = (FlashTreeNode<?>)path.getLastPathComponent();

			FlashTreeNodeClickHandler.handleRightClick(tree, node, x, y);
		}

		@Override
		public void mousePressed(final MouseEvent e) {
			if (e.isPopupTrigger()) {
				handleRightClick(e);
			}
		}
		@Override
		public void mouseReleased(final MouseEvent e) {
			if (e.isPopupTrigger()) {
				handleRightClick(e);
			}
		}
	}

	/**
	 * Selection listener that updates the GUI when a new node in the
	 * tree panel was activated.
	 */
	private class InternalTreeSelectionListener implements TreeSelectionListener {

		@Override
		public void valueChanged(final TreeSelectionEvent e) {

			final FlashTreeNode<?> node = (FlashTreeNode<?>) panel.getTree().getLastSelectedPathComponent();

			FlashTreeNodeSelectionHandler.handleSelection(node, detailPanel);
		}
	}
}