package j3deditor.bin.editor;

import j3deditor.bin.editor.tools.NodePanel;

import j3deditor.bin.components.ButtonPanelLayout;
import j3deditor.bin.components.ComponentUtils;

import j3deditor.bin.hierarchy.util.HierarchyEventListener;

import j3deditor.bin.components.MultiPanel;

import j3deditor.bin.editor.util.SELayout;

import j3deditor.bin.components.SimpleButton;
import j3deditor.bin.components.SimpleButtonEvent;
import j3deditor.bin.components.SimpleButtonListener;

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

import j3deditor.bin.util.Utilities;

import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;


/**
 * Panel that contains the 3D scene and
 * various scene-editor components.
 *
 * @author Risto Seene
 */
public class SceneEditor extends JPanel implements SimpleButtonListener{


	/** the scene this editor manipulates */
	private J3DeScene node;

	/** listener that listens hierarchy manipulation events made by components of this panel */
	private HierarchyEventListener listener;

	/** width of the upper left panel */
	private int panelW = 90;

	/** height of the upper left panel */
	private int panelH = 70;


	/** button for switching active panel of multipanel */
	private SimpleButton switchingButton;

	/** infopanel */
	private InfoPanel infoPanel;

	/** multipanel */
	private MultiPanel multiPanel;

	/** camera panel */
	private CameraPanel cameraPanel;

	/** object panel */
	private ObjectPanel objectPanel;

	/** tranform panel */
	private TransformPanel transPanel;


	/** scene visualizer */
	private Scene3D scene;

	/** reference to active tool */
	private JPanel tools;


	/**
	 * Creates an instance of <code>SceneEditor</code>.
	 *
	 * @param node
	 *	root node of the scene this editor manipulates
	 */
	public SceneEditor(J3DeScene node){
		this.node = node;

		scene = new Scene3D(node);

		setLayout(new SELayout(panelW, panelH));
		setOpaque(false);

		add(initInfoPanel());
		add(initMultiPanel());
		cameraPanel = new CameraPanel(node, 70, 70, 10, 5, ButtonPanelLayout.POSITIVE);
		cameraPanel.setInfoListener(infoPanel);
		add(cameraPanel);
		add(scene);
		tools = new JPanel();
		add(tools);

		multiPanel.setActive(0);
	}


	/**
	 * Sets the listener that listens events performed by the components of this panel.
	 *
	 * @param listener
	 *	listener to be set to listen events
	 */
	public void setEditorEventListener(HierarchyEventListener listener){
		this.listener = listener;
		objectPanel.setEditorEventListener(listener);
		transPanel.setEditorEventListener(listener);
	}


	/**
	 * Initializes the content of infopanel
	 */
	private JPanel initInfoPanel(){
		infoPanel = new InfoPanel(panelW, panelH);

		switchingButton = new SimpleButton(SimpleButton.CLICK);
		switchingButton.setButtonInfo(Utilities.translator.translate(this.getClass(), "next"));
		switchingButton.setImage("next.png", SimpleButton.NORMAL_IMAGE);
		switchingButton.setImage("next_1.png", SimpleButton.MOUSE_OVER_IMAGE);
		switchingButton.setImage("next_2.png", SimpleButton.MOUSE_DOWN_IMAGE);

		switchingButton.addSimpleButtonListener(this);
	          switchingButton.setBounds(75, 40, 15, 20);
		infoPanel.add(switchingButton);

		return infoPanel;
	}


	/**
	 * Initializes the content of multipanel
	 */
	private JPanel initMultiPanel(){
		multiPanel = new MultiPanel(this);
		objectPanel = new ObjectPanel(node);
		objectPanel.setInfoListener(infoPanel);
		transPanel = new TransformPanel(node);
		transPanel.setInfoListener(infoPanel);

		multiPanel.addPanel(objectPanel);
		multiPanel.addPanel(transPanel);

		return multiPanel;
	}


	/**
	 * Listens the mouse click events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonClicked(SimpleButtonEvent e){
		if(e.getSource() == switchingButton){
			multiPanel.activateNextPanel();
		}
	}


	/**
	 * Listens the mouse enter events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonEntered(SimpleButtonEvent e){
		infoPanel.setInfo(e.getSource().getButtonInfo());
	}


	/**
	 * Listens the mouse exit events sent by <code>SimpleButton</code> objects.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonExited(SimpleButtonEvent e){
		infoPanel.setInfo(null, null);
	}


	/**
	 * Not in use.
	 * 
	 * @param e
	 * 	doesn't do anything
	 */
	public void buttonDragged(SimpleButtonEvent e){
	}


	/**
	 * Not in use.
	 *
	 * @param e
	 *	event sent by <code>SimpleButton</code>
	 */
	public void buttonDragEnded(SimpleButtonEvent e){
	}


	/**
	 * Returns the <code>Scene3D</code> object attached to this panel.
	 *
	 * @return Returns the <code>Scene3D</code> object attached to this panel
	 */
	public Scene3D getScene(){
		return scene;
	}


	/**
	 * Changes the tool panel
	 * according to selected hierarchy nodes.
	 */
	public void updateTools(){
		HierarchyNode[] objects = node.getSelectedObjects();
		if(objects != null && objects.length == 1){
			HierarchyNode object = objects[0];
			changePanel(new NodePanel(object, listener));
		}
		else {
			changePanel(new JLabel());
		}
	}


	/**
	 * Updates values shown on specific tool panel.
	 * If current tool panel is an instance of <code>NodePanel</code>
	 * calls its <code>updateValues()</code> method
	 */
	public void updateValues(){
		try{
			if(getComponent(4) instanceof NodePanel){
				((NodePanel)getComponent(4)).updateValues();
			}
		} catch(Throwable t){
		}
	}


	/**
	 * Replaces the 4th component of this panel.
	 * Called by <code>updateTools()</code>.
	 *
	 * @param comp
	 *	new component
	 */
	private void changePanel(JComponent comp){
		remove(4);
		add(comp, 4);
		validate();
	}


	/**
	 * Specifies if the buttons on transform panel are enabled or not.
	 *
	 * @param state
	 *	<code>true</code> to enable buttons on transform panel,
	 *	otherwise <code>false</code>
	 */
	public void updateTransformPanel(boolean state){
		transPanel.setEnabled(state);
	}

	/**
	 * Disposes all content.
	 */
	public void cleanUp(){
		ComponentUtils.removeChildren(this);
		this.node = null;
		this.listener = null;
		this.switchingButton = null;
		this.infoPanel = null;
		this.multiPanel = null;
		this.cameraPanel = null;
		this.objectPanel = null;
		this.transPanel = null;
		this.scene.cleanUp();
		this.scene = null;
		this.tools = null;
	}

}
