package leaf.ui;

import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstraints;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import com.evolute.utils.images.ImageException;
import com.evolute.utils.images.ImageIconLoader;



public class TreeInserterDialog extends JDialog
{

	private static final long serialVersionUID = 1L;
	
	private static final Dimension ALL_DIMENSION = new Dimension(300,500);
	
	private static final Dimension NEW_DIMENSION = new Dimension(300,400);
	
	private static final String ICON_NAME_ADD = "leaf/ui/icons/add.png";
	
	private static final String ICON_NAME_REM = "leaf/ui/icons/rem.png";
	
	private final DefaultMutableTreeNode newRoot = new DefaultMutableTreeNode();
	
	private final DefaultTreeModel newModel = new DefaultTreeModel( newRoot );
	
	private final JTree newTree = new JTree(newModel);
	
	private final JScrollPane newScroll = new JScrollPane( newTree );
	
	private final DefaultMutableTreeNode allRoot;
	
	private final DefaultTreeModel allModel;
	
	private final JTree allTree;
	
	private final JScrollPane allScroll;
	
	private LeafButton buttonAdd = null;
	
	private LeafButton buttonRemove = null;
	
	private final LeafButton buttonOK = new LeafButton( "OK" );
	
	private final LeafButton buttonCancel = new LeafButton( "Cancelar" );
	
	public TreeInserterDialog( Component relativeTo, String title, DefaultMutableTreeNode root )
	{
		this.allRoot = root;
		this.allModel = new DefaultTreeModel( allRoot );
		this.allTree = new JTree(allModel);
		this.allScroll =  new JScrollPane( allTree );
		this.setTitle( title );
		try
		{
			buttonAdd = new LeafButton( ImageIconLoader.loadImageIcon( ICON_NAME_ADD ) );
			buttonRemove = new LeafButton( ImageIconLoader.loadImageIcon( ICON_NAME_REM ) );
		} catch( ImageException e )
		{
			e.printStackTrace();
		}
		startupComponents();
		setupLayout();
		placeComponents();
		startupListeners();
		TreeTools.refreshTree(allTree, allRoot);
		setEnabled();
		this.setLocationRelativeTo( relativeTo );
		this.setSize( 680, 400 );
		this.setModal( true );
		this.setVisible( true );
	}
	
	private void startupComponents()
	{
		newTree.setRootVisible( false );
		newTree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
		allTree.setRootVisible( false );
		allTree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
		allScroll.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS );
		allScroll.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
		newScroll.setVerticalScrollBarPolicy( JScrollPane.VERTICAL_SCROLLBAR_ALWAYS );
		newScroll.setHorizontalScrollBarPolicy( JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
		allScroll.setPreferredSize( ALL_DIMENSION );
		newScroll.setPreferredSize( NEW_DIMENSION );
		buttonAdd.setToolTipText( "Adicionar" );
		buttonRemove.setToolTipText( "Remover" );
		buttonAdd.setMargin( new Insets(0,0,0,0) );
		buttonRemove.setMargin( new Insets(0,0,0,0) );
	}
	
	private void setupLayout()
	{
		TableLayout layout = new TableLayout(
				new double[]{ TableLayout.FILL, TableLayout.MINIMUM, TableLayout.PREFERRED, TableLayout.MINIMUM, TableLayout.MINIMUM },
				new double[]{ TableLayout.MINIMUM, TableLayout.MINIMUM, TableLayout.FILL, TableLayout.MINIMUM, TableLayout.MINIMUM }
				);
		layout.setHGap( 5 );
		layout.setVGap( 5 );
		getContentPane().setLayout( layout );
	}
	
	private void placeComponents()
	{
		getContentPane().add( new JLabel("Todos"), new TableLayoutConstraints( 0,0 ) );
		getContentPane().add( new JLabel("a adicionar..."), new TableLayoutConstraints( 2,0,4,0 ) );
		getContentPane().add( allScroll, new TableLayoutConstraints( 0,1,0,4 ) );
		getContentPane().add( buttonAdd, new TableLayoutConstraints( 1,1 ) );
		getContentPane().add( buttonRemove, new TableLayoutConstraints( 1,3 ) );
		getContentPane().add( newScroll, new TableLayoutConstraints( 2,1,4,3 ) );
		getContentPane().add( buttonOK, new TableLayoutConstraints( 3,4 ) );
		getContentPane().add( buttonCancel, new TableLayoutConstraints( 4,4 ) );
	}
	
	private void startupListeners()
	{
		buttonAdd.addActionListener( new ActionListener()
		{
			@Override
			public void actionPerformed( ActionEvent e )
			{
				move( allTree, newTree );
			}
		} );
		buttonRemove.addActionListener( new ActionListener()
		{
			@Override
			public void actionPerformed( ActionEvent e )
			{
				move( newTree, allTree );
			}
		} );
		buttonOK.addActionListener( new ActionListener()
		{
			@Override
			public void actionPerformed( ActionEvent e )
			{
				ok();
			}
		} );
		buttonCancel.addActionListener( new ActionListener()
		{
			@Override
			public void actionPerformed( ActionEvent e )
			{
				cancel();
			}
		} );
		allTree.getSelectionModel().addTreeSelectionListener( new TreeSelectionListener(){
			@Override
			public void valueChanged( TreeSelectionEvent e )
			{
				setEnabled();
			}
		} );
		newTree.getSelectionModel().addTreeSelectionListener( new TreeSelectionListener(){
			@Override
			public void valueChanged( TreeSelectionEvent e )
			{
				setEnabled();
			}
		} );
	}
	
	private void move( JTree from, JTree to  )
	{
		TreePath [] paths = from.getSelectionPaths();
		if( paths != null )
		{
			DefaultMutableTreeNode fromRoot = (DefaultMutableTreeNode) from.getModel().getRoot();
			DefaultMutableTreeNode toRoot = (DefaultMutableTreeNode) to.getModel().getRoot();
			for( TreePath path : paths )
			{
				for( int i = 1; i < path.getPathCount(); ++i )
				{
					DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getPathComponent( i );
					DefaultMutableTreeNode parent = (DefaultMutableTreeNode) path.getPathComponent( i-1 );
					if( node != null && parent != null )
					{
						DefaultMutableTreeNode exists = TreeTools.findNodeWithUserObject( node.getUserObject(), toRoot );
						if( exists == null )
						{
							add(node, parent.getUserObject(), toRoot, path.getPathCount() == i + 1 );
						}
						else if( i + 1 == path.getPathCount() )
						{
							TreeTools.merge( exists, node );
						}
					}
				}
				removeNode( (DefaultMutableTreeNode) path.getLastPathComponent(), fromRoot );
			}
			TreeTools.refreshTree( from, fromRoot );
			TreeTools.refreshTree( to, toRoot );
		}
	}
	
	private void removeNode( DefaultMutableTreeNode node, DefaultMutableTreeNode root )
	{
		DefaultMutableTreeNode parent = (DefaultMutableTreeNode) node.getParent();
		node.removeFromParent();
		if( parent != null && parent.getChildCount() == 0 )
		{
			removeNode( parent, root );
		}
	}
	
	private void add( DefaultMutableTreeNode node, Object parent, DefaultMutableTreeNode where, boolean fullClone )
	{
		DefaultMutableTreeNode parentNode = TreeTools.findNodeWithUserObject( parent, where );
		if( parentNode == null )
		{
			parentNode = where;
		}
		parentNode.add( fullClone ? TreeTools.cloneFullNode(node) : (DefaultMutableTreeNode) node.clone() );
	}

	private void ok()
	{
		close();
	}
	
	private void cancel()
	{
		newRoot.removeAllChildren();
		close();
	}
	
	private void close()
	{
		setVisible( false );
	}
	
	private void setEnabled()
	{
		boolean allSelected = allTree.getSelectionPath() != null;
		boolean newSelected = newTree.getSelectionPath() != null;
		boolean somethingToAdd = newRoot.getChildCount() > 0;
		buttonAdd.setEnabled( allSelected );
		buttonRemove.setEnabled( newSelected );
		buttonOK.setEnabled( somethingToAdd );
	}
	
	public DefaultMutableTreeNode getResult()
	{
		return newRoot;
	}
	
}
