package j3deditor.bin.hierarchy.view;


import j3deditor.bin.hierarchy.HierarchyManager;
import j3deditor.bin.hierarchy.HierarchyNode;
import j3deditor.bin.hierarchy.J3DeScene;

import java.awt.BorderLayout;

import java.util.ArrayList;

import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.TreePath;


/**
 * Panel that visualizes hierarchy.
 *
 * @author Risto Seene
 */
public class HierarchyViewer extends JPanel implements TreeSelectionListener{

	/** object that visualizes the tree */
	private JTree tree;

	/** root node for the <code>JTree</code> */
	private HierarchyNode node;

	/** listener that listens the action performed on the <code>JTree</code> */
	private TreeSelectionListener listener;


	/**
	 * Creates an instance of <code>HierarchyViewer</code>
	 * with the given root node.
	 *
	 * @param node
	 *	root node for this hierarchy visualizer
	 */
	public HierarchyViewer(HierarchyNode node){
		tree = new JTree(new HTreeModel(node));
		tree.setCellRenderer(new TreeRenderer());
		this.node = node;

		setLayout(new BorderLayout());
		add(new JScrollPane(tree), BorderLayout.CENTER);

		tree.addTreeSelectionListener(this);
	}


	/**
	 * Sets the listener the <code>TreeselectionEvent</code>s will be sent to.
	 *
	 * @param listener
	 *	listener the <code>TreeselectionEvent</code>s will be sent to
	 */
	public void setSelectionListener(TreeSelectionListener listener){
		this.listener = listener;
	}


	/**
	 * Invoked every time a node in the <code>Jtree</code> object is
	 * selected or deselected.
	 *
	 * @param e
	 *	<code>TreeSelectionEvent</code> sent by <code>Jtree</code>
	 */
	public void valueChanged(TreeSelectionEvent e){
		if((node instanceof J3DeScene) || (node instanceof HierarchyManager)){
			TreePath[] paths = tree.getSelectionPaths();
			HierarchyNode[] objects = null;
			try{
				objects = new HierarchyNode[paths.length];
			} catch(Throwable t){
				objects = new HierarchyNode[0];
			}

			for(int i = 0; i < objects.length; i++){
				objects[i] = (HierarchyNode)(paths[i].getLastPathComponent());
			}

			if(node instanceof J3DeScene){
				((J3DeScene)node).setSelectedObjects(objects);
			} else {
				((HierarchyManager)node).setSelectedObjects(objects);
			}

			if(listener != null){
				listener.valueChanged(e);
			}
		}
	}


	/**
	 * Updates the UI of the <code>Jtree</code>.
	 */
	public void updateTree(){
		tree.updateUI();
	}


	/**
	 * Updates the selections and UI.
	 * Gets the selected nodes from the root node
	 */
	public void setSelection(){
		try{
			HierarchyNode[] nodes = null;

			if(node instanceof J3DeScene){
				J3DeScene scene = (J3DeScene)node;
				nodes = scene.getSelectedObjects();
			} else if(node instanceof HierarchyManager){
				HierarchyManager man = (HierarchyManager)node;
				nodes = man.getSelectedObjects();
			}

			TreePath[] paths = new TreePath[nodes.length];

			for(int i = 0; i < nodes.length; i++){
				ArrayList<Object> objects = new ArrayList<Object>();

				boolean hasMore = true;
				Object currentNode = nodes[i];
				while(hasMore){
					objects.add(currentNode);
					if(currentNode == node){
						hasMore = false;
					} else {
						currentNode = (((HierarchyNode)currentNode).getParent());
					}
				}

				Object[] path = new Object[objects.size()];
				for(int j = 0; j < objects.size(); j++){
					path[j] = objects.get(objects.size() - 1 - j);
				}

				paths[i] = new TreePath(path);
			}

			tree.setSelectionPaths(paths);
		} catch(Throwable t){
		}

		updateTree();
	}

}
