/**
 *
 */
package de.rico.editor.gui;

import java.awt.Dimension;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;

import de.rico.adventure.entity.AbstractEntity;
import de.rico.adventure.entity.character.NonPlayerCharacter;
import de.rico.adventure.entity.hotspot.AbstractInteractiveHotspot;
import de.rico.adventure.entity.hotspot.CubicalHotpot;
import de.rico.adventure.entity.hotspot.SphericalHotspot;
import de.rico.adventure.entity.item.Item;
import de.rico.adventure.entity.prop.Prop;
import de.rico.adventure.script.trigger.AbstractTrigger;
import de.rico.adventure.script.trigger.CircleTriggerArea;
import de.rico.adventure.script.trigger.RectTriggerArea;
import de.rico.editor.WorldEditor;
import de.rico.engine.camera.Camera;
import de.rico.engine.camera.CameraPerspective;
import de.rico.engine.effect.light.LightIface;
import de.rico.engine.effect.light.ogllight.AbstractLight;
import de.rico.engine.effect.light.ogllight.DirectionalLight;
import de.rico.engine.effect.light.ogllight.PositionalLight;
import de.rico.engine.effect.light.ogllight.SpotLight;
import de.rico.engine.geometry.AbstractMesh;
import de.rico.engine.geometry.GroundPlane;
import de.rico.engine.geometry.Point3D;
import de.rico.engine.geometry.Terrain;
import de.rico.engine.geometry.modelloader.md2.ModelMD2;
import de.rico.engine.geometry.modelloader.ms3d.ModelMS3DAscii;
import de.rico.engine.geometry.modelloader.threeds.Model3DS;
import de.rico.engine.material.Color4f;

/**
 * This class holds the editor menu and its
 * functionality.
 * @author Frank Bruns
 */
public class EditorMenu extends JPanel
{
	private JScrollPane jScrollPaneMeshList = null;
	private static JList listMeshes = null;
	private JScrollPane jScrollPaneLightList = null;
	private static  JList listLights = null;
	private JScrollPane jScrollPaneCamPerspectivesList = null;
	private static  JList listCamPerspectives = null;
	private JScrollPane jScrollPaneTriggersList = null;
	private static JList listTriggers = null;
	private JScrollPane jScrollPaneHotspotList = null;
	private static JList listHotspots = null;
	private JLabel labelHotspots = null;
	private JLabel labelMeshes = null;
	private JLabel labelLights = null;
	private JLabel labelCams = null;
	private JLabel labelTriggers = null;
	private JPanel panelProperties = null;
	private JScrollPane jScrollPaneProperties = null;
	private JTable tableProperties = null;
	private JButton btnApplyChanges = null;

	// constants for defining what was selected in the list menus
	private static final int NOTHING_SELECTED = 0;
	private static final int MESH_SELECTED = 1;
	private static final int LIGHT_SELECTED = 2;
	private static final int CAM_SELECTED = 3;
	private static final int HOTSPOT_SELECTED = 4;
	private static final int TRIGGER_SELECTED = 5;
	private int lastSelectType = NOTHING_SELECTED;
	private Color4f materialBackup = null;
	private String lastSelectedMeshName = null;
	private JButton btnRemove = null;
	private JTabbedPane jTabbedPane = null;
	private JPanel panelMeshes = null;
	private JPanel panelLights = null;
	private JPanel panelCameras = null;
	private JPanel panelHotspots = null;
	private JPanel panelTriggers = null;
	private JPanel panelObjects = null;
	private JLabel labelForGap = null;

	public EditorMenu()
	{
		this.initialize();
	}

	/**
	 * This method initializes the menu components.
	 */
	private void initialize() {
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.setSize(new Dimension(135, 298));
        this.setPreferredSize(new Dimension(150, 488));
        this.add(this.getPanelObjects(), null);
        this.add(this.getPanelProperties(), null);
	}

	/**
	 * Adds a mesh name to the list menu
	 *
	 * @param meshName name of the mesh to add to the list menu
	 */
	public static void addEntityToListMenu(String meshName)
	{
		// get previous list content
		Vector<String> data = new Vector<String>();
		int size = listMeshes.getModel().getSize();
		for(int i=0; i<size; i++)
			data.add((String)listMeshes.getModel().getElementAt(i));

		// add the mesh name to the list data
		data.add(meshName);

		listMeshes.setListData(data);
	}

	/**
	 * Adds a hotspot name to the list menu
	 *
	 * @param hotspotName name of the hotspot to add to the list menu
	 */
	public static void addHotspotToListMenu(String hotspotName)
	{
		// get previous list content
		Vector<String> data = new Vector<String>();
		int size = listHotspots.getModel().getSize();
		for(int i=0; i<size; i++)
			data.add((String)listHotspots.getModel().getElementAt(i));

		// add the hotspot name to the list data
		data.add(hotspotName);

		listHotspots.setListData(data);
	}

	/**
	 * Adds a camera perspective to the list menu
	 *
	 * @param id id of the cam perspective to add to the list menu
	 */
	public static void addCamPerspectiveToListMenu(int id)
	{
		// get previous list content
		Vector<String> data = new Vector<String>();
		int size = listCamPerspectives.getModel().getSize();
		for(int i=0; i<size; i++)
			data.add((String)listCamPerspectives.getModel().getElementAt(i));

		// add the perspective id to the list data
		data.add(""+id);

		listCamPerspectives.setListData(data);
	}

	/**
	 * Adds a trigger to the list menu.
	 *
	 * @param name name (script id) of the trigger to add to the list menu
	 */
	public static void addTriggerToListMenu(String name)
	{
		// get previous list content
		Vector<String> data = new Vector<String>();
		int size = listTriggers.getModel().getSize();
		for(int i=0; i<size; i++)
			data.add((String)listTriggers.getModel().getElementAt(i));

		// add the perspective id to the list data
		data.add(name);

		listTriggers.setListData(data);
	}

	/**
	 * Clears the entries from the mesh list menu.
	 *
	 */
	public static void clearMeshList()
	{
		Object[] emptyData = new Object[0];
		listMeshes.setListData(emptyData);
	}

	/**
	 * Clears the entries from the light list menu.
	 *
	 */
	public static void clearLightList()
	{
		Object[] emptyData = new Object[0];
		listLights.setListData(emptyData);
	}

	/**
	 * Clears the entries from the camera perspective list menu.
	 *
	 */
	public static void clearCamPerspectiveList()
	{
		Object[] emptyData = new Object[0];
		listCamPerspectives.setListData(emptyData);
	}

	/**
	 * Clears the entries from the hotspot list menu.
	 *
	 */
	public static void clearHotspotList()
	{
		Object[] emptyData = new Object[0];
		listHotspots.setListData(emptyData);
	}

	/**
	 * Clears the entries from the camera perspective list menu.
	 *
	 */
	public static void clearTriggersList()
	{
		Object[] emptyData = new Object[0];
		listTriggers.setListData(emptyData);
	}

	/**
	 * Adds a light number to the list menu
	 *
	 * @param nr nr of light
	 */
	public static void addLightToListMenu(int nr)
	{
		// get previous list content
		Vector<String> data = new Vector<String>();
		int size = listLights.getModel().getSize();
		for(int i=0; i<size; i++)
			data.add((String)listLights.getModel().getElementAt(i));

		// add the light number to the list data
		data.add(""+nr);

		listLights.setListData(data);
	}

	/**
	 * Returns the name of the currently seleceted mesh in the
	 * list menu. If none is selected it returns <code>null</code>.
	 * @return name of selected mesh in list menu, else <code>null</code>
	 */
	public static String getSelectedMeshName()
	{
		if(listMeshes.getSelectedIndex() != -1)
		{
			String name = (String)listMeshes.getSelectedValue();
			// clear the value from additions like "(npc), (item), (prop)"
			name = name.substring(0,name.indexOf(" ("));

			return name;
		}
		else return null;
	}

	/**
	 * Returns the name of the currently seleceted hotspot in the
	 * list menu. If none is selected it returns <code>null</code>.
	 * @return name of selected hotspot in list menu, else <code>null</code>
	 */
	public static String getSelectedHotspotName()
	{
		if(listHotspots.getSelectedIndex() != -1)
		{
			return (String)listHotspots.getSelectedValue();
		}
		else return null;
	}

	/**
	 * Returns the name of the currently seleceted trigger in the
	 * list menu. If none is selected it returns <code>null</code>.
	 * @return name of selected trigger in list menu, else <code>null</code>
	 */
	public static String getSelectedTriggerName()
	{
		if(listTriggers.getSelectedIndex() != -1)
		{
			return (String)listTriggers.getSelectedValue();
		}
		else return null;
	}

	/**
	 * This method initializes jScrollPaneMeshList
	 *
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneMeshList()
	{
		if (this.jScrollPaneMeshList == null)
		{
			this.jScrollPaneMeshList = new JScrollPane();
			this.jScrollPaneMeshList.setViewportView(this.getListMeshes());
			this.jScrollPaneMeshList.setViewportView(this.getListMeshes());
		}
		return this.jScrollPaneMeshList;
	}

	/**
	 * This method initializes listMeshes
	 *
	 * @return javax.swing.JList
	 */
	private JList getListMeshes()
	{
		if (listMeshes == null)
		{
			listMeshes = new JList(new DefaultListModel());
			listMeshes.setSize(new Dimension(130, 72));
			listMeshes
					.addListSelectionListener(new javax.swing.event.ListSelectionListener()
					{
						public void valueChanged(javax.swing.event.ListSelectionEvent e)
						{
							EditorMenu.this.lastSelectType = MESH_SELECTED;
							listLights.clearSelection();
							listCamPerspectives.clearSelection();
							listTriggers.clearSelection();
							listHotspots.clearSelection();

							int meshListSelIndex = listMeshes.getSelectedIndex();
							if(meshListSelIndex != -1)
							{
								EditorMenu.this.clearTableData();
								// this table data is always needed
								EditorMenu.this.tableProperties.setValueAt("x:", 0, 0);
								EditorMenu.this.tableProperties.setValueAt("y:", 1, 0);
								EditorMenu.this.tableProperties.setValueAt("z:", 2, 0);
								EditorMenu.this.tableProperties.setValueAt("rot x:", 3, 0);
								EditorMenu.this.tableProperties.setValueAt("rot y:", 4, 0);
								EditorMenu.this.tableProperties.setValueAt("rot z:", 5, 0);
								EditorMenu.this.tableProperties.setValueAt("scale x:", 6, 0);
								EditorMenu.this.tableProperties.setValueAt("scale y:", 7, 0);
								EditorMenu.this.tableProperties.setValueAt("scale z:", 8, 0);
								EditorMenu.this.tableProperties.setValueAt("shadow:", 9, 0);


								// clear blue color of previous selected mesh
								if(EditorMenu.this.lastSelectedMeshName != null
										&& EditorMenu.this.materialBackup != null)
									WorldEditor.room.getMeshes().getMeshByName(EditorMenu.this.lastSelectedMeshName).getMaterial().setDiffuse(EditorMenu.this.materialBackup);

								// add the concrete mesh data

								String name = (String)listMeshes.getSelectedValue();
								// clear the value from additions like "(npc), (item), (prop)"
								name = name.substring(0,name.indexOf(" ("));

								// backup the name of the selected mesh
								EditorMenu.this.lastSelectedMeshName = name;

								AbstractMesh mesh = WorldEditor.room.getMeshes().getMeshByName(name);
								// backup the meshes diffuse material color
								EditorMenu.this.materialBackup = mesh.getMaterial().getDiffuse().clone();

								// set selected mesh to blue diffuse material
								mesh.getMaterial().setDiffuse(0f, 0f, 1f, 1f);
								EditorMenu.this.setTableDataEntity(WorldEditor.room.getEntityByMesh(mesh));
							}
						}
					});
		}
		return listMeshes;
	}

	/**
	 * This method initializes jScrollPaneTriggersList
	 *
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneTriggersList()
	{
		if (this.jScrollPaneTriggersList == null)
		{
			this.jScrollPaneTriggersList = new JScrollPane();
			this.jScrollPaneTriggersList.setViewportView(this.getListTriggers());
			this.jScrollPaneTriggersList.setViewportView(this.getListTriggers());
		}
		return this.jScrollPaneTriggersList;
	}

	/**
	 * This method initializes listTriggers
	 *
	 * @return javax.swing.JList
	 */
	private JList getListTriggers()
	{
		if (listTriggers == null)
		{
			listTriggers = new JList(new DefaultListModel());
			listTriggers.setSize(new Dimension(130, 72));
			listTriggers
					.addListSelectionListener(new javax.swing.event.ListSelectionListener()
					{
						public void valueChanged(javax.swing.event.ListSelectionEvent e)
						{
							EditorMenu.this.lastSelectType = TRIGGER_SELECTED;
							listLights.clearSelection();
							listCamPerspectives.clearSelection();
							listMeshes.clearSelection();
							listHotspots.clearSelection();

							int triggerListSelIndex = listTriggers.getSelectedIndex();
							if(triggerListSelIndex != -1)
							{
								EditorMenu.this.clearTableData();
								// this table data is always needed
								EditorMenu.this.tableProperties.setValueAt("x:", 0, 0);
								EditorMenu.this.tableProperties.setValueAt("z:", 1, 0);
								EditorMenu.this.tableProperties.setValueAt("scriptid:", 2, 0);
								EditorMenu.this.tableProperties.setValueAt("enabled:", 3, 0);


								AbstractTrigger trigger = WorldEditor.room.getTrigger((String)listTriggers.getSelectedValue());

								// change the color of the selected trigger,
								// but reset the color of every other trigger before.
								for(AbstractTrigger t : WorldEditor.room.getTriggers())
									t.setColor(new Color4f(1f,1f,1f,1f));

								trigger.setColor(new Color4f(0f,0f,1f,1f));


								// add the concrete trigger data to the table
								EditorMenu.this.tableProperties.setValueAt(""+trigger.getX(), 0, 1);
								EditorMenu.this.tableProperties.setValueAt(""+trigger.getZ(), 1, 1);
								EditorMenu.this.tableProperties.setValueAt(""+trigger.getScriptId(), 2, 1);
								EditorMenu.this.tableProperties.setValueAt(""+trigger.isEnabled(), 3, 1);

								if(trigger instanceof CircleTriggerArea)
								{
									CircleTriggerArea circle = (CircleTriggerArea)trigger;
									EditorMenu.this.tableProperties.setValueAt("radius:", 4, 0);
									EditorMenu.this.tableProperties.setValueAt(""+circle.getRadius(), 4, 1);

								}
								else if(trigger instanceof RectTriggerArea)
								{
									RectTriggerArea rect = (RectTriggerArea)trigger;
									EditorMenu.this.tableProperties.setValueAt("width:", 4, 0);
									EditorMenu.this.tableProperties.setValueAt("length:", 5, 0);
									EditorMenu.this.tableProperties.setValueAt(""+rect.getWidth(), 4, 1);
									EditorMenu.this.tableProperties.setValueAt(""+rect.getLength(), 5, 1);

								}
							}
						}
					});
		}
		return listTriggers;
	}

	/**
	 * This method initializes jScrollPaneLightList
	 *
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneLightList()
	{
		if (this.jScrollPaneLightList == null)
		{
			this.jScrollPaneLightList = new JScrollPane();
			this.jScrollPaneLightList.setPreferredSize(new Dimension(259, 65));
			this.jScrollPaneLightList.setViewportView(this.getListLights());
		}
		return this.jScrollPaneLightList;
	}

	/**
	 * This method initializes listLights
	 *
	 * @return javax.swing.JList
	 */
	private JList getListLights()
	{
		if (listLights == null)
		{
			listLights = new JList(new DefaultListModel());
			listLights.setSize(new Dimension(130, 72));
			listLights
					.addListSelectionListener(new javax.swing.event.ListSelectionListener()
					{
						public void valueChanged(javax.swing.event.ListSelectionEvent e)
						{
							EditorMenu.this.lastSelectType = LIGHT_SELECTED;
							listMeshes.clearSelection();
							listCamPerspectives.clearSelection();
							listTriggers.clearSelection();
							listHotspots.clearSelection();

							int lightListSelIndex = listLights.getSelectedIndex();
							if(lightListSelIndex != -1)
							{
								// add the concrete light colors to the table
								LightIface light = WorldEditor.room.getLights().get(lightListSelIndex);

								if(light instanceof DirectionalLight)
								{
									EditorMenu.this.setTableDataDirectLight(light);
								}
								if(light instanceof PositionalLight)
								{
									EditorMenu.this.setTableDataPosLight(light);
								}
								if(light instanceof SpotLight)
								{
									EditorMenu.this.setTableDataSpotLight(light);
								}
							}
						}
					});
		}
		return listLights;
	}

	/**
	 * This method initializes listCamPerspectives
	 *
	 * @return javax.swing.JList
	 */
	private JList getListCamPerspectives()
	{
		if (listCamPerspectives == null)
		{
			listCamPerspectives = new JList(new DefaultListModel());
			listCamPerspectives.setSize(new Dimension(130, 72));
			listCamPerspectives
					.addListSelectionListener(new javax.swing.event.ListSelectionListener()
					{
						public void valueChanged(javax.swing.event.ListSelectionEvent e)
						{
							EditorMenu.this.lastSelectType = CAM_SELECTED;
							listMeshes.clearSelection();
							listLights.clearSelection();
							listTriggers.clearSelection();
							listHotspots.clearSelection();

							int camListSelIndex = listCamPerspectives.getSelectedIndex();
							if(camListSelIndex != -1)
							{
								// add the concrete camera perspective to the table
								EditorMenu.this.clearTableData();

								// property name
								EditorMenu.this.tableProperties.setValueAt("x:", 0, 0);
								EditorMenu.this.tableProperties.setValueAt("y:", 1, 0);
								EditorMenu.this.tableProperties.setValueAt("z:", 2, 0);
								EditorMenu.this.tableProperties.setValueAt("rot x:", 3, 0);
								EditorMenu.this.tableProperties.setValueAt("rot y:", 4, 0);
								EditorMenu.this.tableProperties.setValueAt("fov:", 5, 0);
								EditorMenu.this.tableProperties.setValueAt("near:", 6, 0);
								EditorMenu.this.tableProperties.setValueAt("far:", 7, 0);

								// get the perspective to be displayed
								// in the table
								int selId = Integer.parseInt((String)listCamPerspectives.getSelectedValue());
								CameraPerspective p = WorldEditor.room.getCameraPerspectives().get(selId).clone();

								// values
								EditorMenu.this.tableProperties.setValueAt(""+p.getPosition().x, 0, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getPosition().y, 1, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getPosition().z, 2, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getRotX()*-1, 3, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getRotY()*-1, 4, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getFieldOfView(), 5, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getNearPlane(), 6, 1);
								EditorMenu.this.tableProperties.setValueAt(""+p.getFarPlane(), 7, 1);


								// set the editor camera perspective to the selected one
								CameraPerspective cam = new CameraPerspective(
										p.getPosition(),
										p.getRotX(),
										p.getRotY(),
										p.getNearPlane(),
										p.getFarPlane());
								cam.setFieldOfView(p.getFieldOfView());
								Camera.getInstance().addCameraPerspective(cam, 0);
							}
						}
					});
		}
		return listCamPerspectives;
	}

	/**
	 * This method initializes jScrollPaneCamPerspectivesList
	 *
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneCamPerspectivesList()
	{
		if (this.jScrollPaneCamPerspectivesList == null)
		{
			this.jScrollPaneCamPerspectivesList = new JScrollPane();
			this.jScrollPaneCamPerspectivesList.setViewportView(this.getListCamPerspectives());
		}
		return this.jScrollPaneCamPerspectivesList;
	}

	/**
	 * This method initializes panelProperties
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelProperties()
	{
		if (this.panelProperties == null)
		{
			this.panelProperties = new JPanel();
			this.panelProperties.setLayout(new BoxLayout(this.getPanelProperties(), BoxLayout.Y_AXIS));
			this.panelProperties.setPreferredSize(new Dimension(100, 200));
			this.panelProperties.add(this.getJScrollPaneProperties(), null);
			this.panelProperties.add(this.getBtnApplyChanges(), null);
		}
		return this.panelProperties;
	}

	/**
	 * This method initializes jScrollPaneProperties
	 *
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneProperties()
	{
		if (this.jScrollPaneProperties == null)
		{
			this.jScrollPaneProperties = new JScrollPane();
			this.jScrollPaneProperties.setPreferredSize(new Dimension(453, 150));
			this.jScrollPaneProperties.setViewportView(this.getTableProperties());
		}
		return this.jScrollPaneProperties;
	}

	/**
	 * This method initializes tableProperties
	 *
	 * @return javax.swing.JTable
	 */
	private JTable getTableProperties()
	{
		if (this.tableProperties == null)
		{
			String[] colNames = new String[] {"Prop", "Value"};

			this.tableProperties = new JTable();
			this.tableProperties.setModel(new DefaultTableModel(colNames,20));
			this.tableProperties.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
			this.tableProperties.setShowGrid(true);
			this.tableProperties.setRowSelectionAllowed(false);
		}
		return this.tableProperties;
	}

	/**
	 * This method initializes btnApplyChanges
	 *
	 * @return javax.swing.JButton
	 */
	private JButton getBtnApplyChanges()
	{
		if (this.btnApplyChanges == null)
		{
			this.btnApplyChanges = new JButton();
			this.btnApplyChanges.setText("Apply Changes");
			this.btnApplyChanges.addActionListener(new java.awt.event.ActionListener()
			{
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					if(EditorMenu.this.lastSelectType == NOTHING_SELECTED) return;

					if(EditorMenu.this.lastSelectType == MESH_SELECTED)
					{
						// apply the changed mesh properties
						int meshListSelIndex = listMeshes.getSelectedIndex();
						if(meshListSelIndex != -1)
						{
							String name = (String)listMeshes.getSelectedValue();
							// clear the value from additions like "(npc), (item), (prop)"
							name = name.substring(0,name.indexOf(" ("));

							AbstractMesh mesh = WorldEditor.room.getMeshes().getMeshByName(name);
							AbstractEntity entity = WorldEditor.room.getEntityByMesh(mesh);
							EditorMenu.this.saveTableDataEntity(entity);
						}
					}


					if(EditorMenu.this.lastSelectType == LIGHT_SELECTED)
					{
						// apply the changed light properties
						int lightListSelIndex = listLights.getSelectedIndex();
						if(lightListSelIndex != -1)
						{
							LightIface light = WorldEditor.room.getLights().get(lightListSelIndex);

							if(light instanceof DirectionalLight)
							{
								EditorMenu.this.saveTableDataDirectLight(light);
							}
							if(light instanceof PositionalLight)
							{
								EditorMenu.this.saveTableDataPosLight(light);
							}
							if(light instanceof SpotLight)
							{
								EditorMenu.this.saveTableDataSpotLight(light);
							}
						}
					}

					if(EditorMenu.this.lastSelectType == CAM_SELECTED)
					{
						// apply the changed camera perspective properties
						int camListSelIndex = listCamPerspectives.getSelectedIndex();
						if(camListSelIndex != -1)
						{
							int perspId = Integer.parseInt((String)listCamPerspectives.getSelectedValue());
							CameraPerspective persp = WorldEditor.room.getCameraPerspectives().get(perspId);

							EditorMenu.this.saveTableDataCamPerspectives(persp);
						}
					}

					if(EditorMenu.this.lastSelectType == TRIGGER_SELECTED)
					{
						// apply the changed trigger properties
						int triggerListSelIndex = listTriggers.getSelectedIndex();
						if(triggerListSelIndex != -1)
						{
							String scriptId = (String)listTriggers.getSelectedValue();
							AbstractTrigger trigger = WorldEditor.room.getTrigger(scriptId);

							trigger.setX(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(0,1)));
							trigger.setZ(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(1,1)));
							trigger.setScriptId((String)EditorMenu.this.tableProperties.getValueAt(2,1));
							trigger.setEnabled(new Boolean((String)EditorMenu.this.tableProperties.getValueAt(3,1)));

							// change the script id name in the list menu
							// get previous list content
							Vector<String> data = new Vector<String>();
							int size = listTriggers.getModel().getSize();
							for(int i=0; i<size; i++)
							{
								String element = (String)listTriggers.getModel().getElementAt(i);
								if(element.equals(scriptId)) element = trigger.getScriptId();

								data.add(element);
							}
							listTriggers.setListData(data);


							if(trigger instanceof CircleTriggerArea)
							{
								CircleTriggerArea circle = (CircleTriggerArea)trigger;
								circle.setRadius(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(4,1)));
							}
							else if(trigger instanceof RectTriggerArea)
							{
								RectTriggerArea rect = (RectTriggerArea)trigger;
								rect.setWidth(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(4,1)));
								rect.setLength(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(5,1)));
							}
						}
					}


					if(EditorMenu.this.lastSelectType == HOTSPOT_SELECTED)
					{
						// apply the changed hotspot properties
						int hotspotListSelIndex = listHotspots.getSelectedIndex();
						if(hotspotListSelIndex != -1)
						{
							String scriptId = (String)listHotspots.getSelectedValue();
							AbstractInteractiveHotspot hotspot = WorldEditor.room.getHotspot(scriptId);

							float x = Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(0,1));
							float y = Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(1,1));
							float z = Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(2,1));
							Point3D pos = new Point3D(x,y,z);
							hotspot.setPosition(pos);

							hotspot.setScriptId((String)EditorMenu.this.tableProperties.getValueAt(3,1));

							// change the script id name in the list menu
							// get previous list content
							Vector<String> data = new Vector<String>();
							int size = listHotspots.getModel().getSize();
							for(int i=0; i<size; i++)
							{
								String element = (String)listHotspots.getModel().getElementAt(i);
								if(element.equals(scriptId)) element = hotspot.getScriptId();

								data.add(element);
							}
							listHotspots.setListData(data);


							if(hotspot instanceof SphericalHotspot)
							{
								SphericalHotspot sphere = (SphericalHotspot)hotspot;
								sphere.setRadius(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(4,1)));
								sphere.setNeedsItem(new Boolean((String)EditorMenu.this.tableProperties.getValueAt(5,1)));
							}
							else if(hotspot instanceof CubicalHotpot)
							{
								CubicalHotpot box = (CubicalHotpot)hotspot;
								box.setWidth(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(4,1)));
								box.setHeight(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(5,1)));
								box.setLength(Float.parseFloat((String)EditorMenu.this.tableProperties.getValueAt(6,1)));
								box.setNeedsItem(new Boolean((String)EditorMenu.this.tableProperties.getValueAt(7,1)));
							}
						}
					}

					// clear selection
					EditorMenu.this.lastSelectType = NOTHING_SELECTED;
					listMeshes.clearSelection();
					listLights.clearSelection();
					listCamPerspectives.clearSelection();
					listHotspots.clearSelection();
					listTriggers.clearSelection();
					EditorMenu.this.clearTableData();

					// reset mesh diffuse material color to original
					if(EditorMenu.this.lastSelectedMeshName != null)
						WorldEditor.room.getMeshes().getMeshByName(EditorMenu.this.lastSelectedMeshName).getMaterial().setDiffuse(EditorMenu.this.materialBackup);
				}
			});
		}
		return this.btnApplyChanges;
	}

	/**
	 * Convenience method to clear the table data.
	 *
	 */
	private void clearTableData()
	{
		this.tableProperties.clearSelection();
		DefaultTableModel model = (DefaultTableModel)this.tableProperties.getModel();
		int cols = model.getColumnCount();
		int rows = model.getRowCount();

		// clear the values
		for(int i=0; i<cols; i++)
		{
			for(int j=0; j<rows; j++)
			{
				model.setValueAt("", j, i);
			}
		}

	}

	/**
	 * Sets the data of the selected entity to the table.
	 * @param entity selected entity
	 */
	private void setTableDataEntity(AbstractEntity entity)
	{
		if(entity instanceof Prop)
		{
			// just patch the data through, there are no
			// specicial table entries.
			if(entity.getMesh() instanceof Model3DS)
			{
				this.setTableDataModel3DS(entity.getMesh());
			}
			if(entity.getMesh() instanceof ModelMD2)
			{
				this.setTableDataModelMD2(entity.getMesh());
			}
			if(entity.getMesh() instanceof ModelMS3DAscii)
			{
				this.setTableDataModelMS3D(entity.getMesh());
			}
			if(entity.getMesh() instanceof Terrain)
			{
				this.setTableDataTerrain(entity.getMesh());
			}
			if(entity.getMesh() instanceof GroundPlane)
			{
				this.setTableDataGroundPlane(entity.getMesh());
			}
		}
		// set special table data for items
		if(entity instanceof Item)
		{
			Item item = (Item)entity;
			if(item.getMesh() instanceof Model3DS)
			{
				this.setTableDataModel3DS(item.getMesh());
			}
			if(item.getMesh() instanceof ModelMD2)
			{
				this.setTableDataModelMD2(item.getMesh());
			}
			if(item.getMesh() instanceof ModelMS3DAscii)
			{
				this.setTableDataModelMS3D(item.getMesh());
			}

			// set special data
			this.tableProperties.setValueAt("name", 10, 0);
			this.tableProperties.setValueAt(item.getScreenName(), 10, 1);
			this.tableProperties.setValueAt("pickable", 11, 0);
			this.tableProperties.setValueAt(""+item.canBePickedUp(), 11, 1);
			this.tableProperties.setValueAt("script id:", 12, 0);
			this.tableProperties.setValueAt(item.getScriptId(), 12, 1);

		}
		// set special table data for characters
		if(entity instanceof NonPlayerCharacter)
		{
			NonPlayerCharacter npc = (NonPlayerCharacter)entity;
			if(npc.getMesh() instanceof Model3DS)
			{
				this.setTableDataModel3DS(npc.getMesh());
			}
			if(npc.getMesh() instanceof ModelMD2)
			{
				this.setTableDataModelMD2(npc.getMesh());
			}
			if(npc.getMesh() instanceof ModelMS3DAscii)
			{
				this.setTableDataModelMS3D(npc.getMesh());
			}

			// set special data
			this.tableProperties.setValueAt("name", 10, 0);
			this.tableProperties.setValueAt(npc.getScreenName(), 10, 1);
			this.tableProperties.setValueAt("script id:", 11, 0);
			this.tableProperties.setValueAt(npc.getScriptId(), 11, 1);
		}

		// set special table data for props
		if(entity instanceof Prop)
		{
			Prop prop = (Prop)entity;
			if(prop.getMesh() instanceof Model3DS)
			{
				this.setTableDataModel3DS(prop.getMesh());
			}
			if(prop.getMesh() instanceof ModelMD2)
			{
				this.setTableDataModelMD2(prop.getMesh());
			}
			if(prop.getMesh() instanceof ModelMS3DAscii)
			{
				this.setTableDataModelMS3D(prop.getMesh());
			}

			// set special data
			this.tableProperties.setValueAt("script id:", 10, 0);
			this.tableProperties.setValueAt(prop.getScriptId(), 10, 1);
		}
	}

	/**
	 * Convenience method to insert the data of a 3DS model to
	 * the table.
	 * @param mesh AbstractMesh object that actually
	 * is a Model3DS object
	 */
	private void setTableDataModel3DS(AbstractMesh mesh)
	{
		Model3DS model3ds = (Model3DS)mesh;
		this.tableProperties.setValueAt(""+model3ds.getPosX(), 0, 1);
		this.tableProperties.setValueAt(""+model3ds.getPosY(), 1, 1);
		this.tableProperties.setValueAt(""+model3ds.getPosZ(), 2, 1);
		this.tableProperties.setValueAt(""+model3ds.getRotX(), 3, 1);
		this.tableProperties.setValueAt(""+model3ds.getRotY(), 4, 1);
		this.tableProperties.setValueAt(""+model3ds.getRotZ(), 5, 1);
		this.tableProperties.setValueAt(""+model3ds.getScaleX(), 6, 1);
		this.tableProperties.setValueAt(""+model3ds.getScaleY(), 7, 1);
		this.tableProperties.setValueAt(""+model3ds.getScaleZ(), 8, 1);
		this.tableProperties.setValueAt(""+model3ds.isShadowEnabled(), 9, 1);

		// add specific data, according to the entity type
	}

	/**
	 * Convenience method to insert the data of a MD2 model to
	 * the table.
	 * @param mesh AbstractMesh object that actually
	 * is a ModelMD2 object
	 */
	private void setTableDataModelMD2(AbstractMesh mesh)
	{
		ModelMD2 modelMd2 = (ModelMD2)mesh;
		this.tableProperties.setValueAt(""+modelMd2.getPosX(), 0, 1);
		this.tableProperties.setValueAt(""+modelMd2.getPosY(), 1, 1);
		this.tableProperties.setValueAt(""+modelMd2.getPosZ(), 2, 1);
		this.tableProperties.setValueAt(""+modelMd2.getRotX(), 3, 1);
		this.tableProperties.setValueAt(""+modelMd2.getRotY(), 4, 1);
		this.tableProperties.setValueAt(""+modelMd2.getRotZ(), 5, 1);
		this.tableProperties.setValueAt(""+modelMd2.getScaleX(), 6, 1);
		this.tableProperties.setValueAt(""+modelMd2.getScaleY(), 7, 1);
		this.tableProperties.setValueAt(""+modelMd2.getScaleZ(), 8, 1);
		this.tableProperties.setValueAt(""+modelMd2.isShadowEnabled(), 9, 1);
	}

	/**
	 * Convenience method to insert the data of a MS3D Ascii model to
	 * the table.
	 * @param mesh AbstractMesh object that actually
	 * is a ModelMS3DAscii object
	 */
	private void setTableDataModelMS3D(AbstractMesh mesh)
	{
		ModelMS3DAscii modelMs3d = (ModelMS3DAscii)mesh;
		this.tableProperties.setValueAt(""+modelMs3d.getPosX(), 0, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getPosY(), 1, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getPosZ(), 2, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getRotX(), 3, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getRotY(), 4, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getRotZ(), 5, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getScaleX(), 6, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getScaleY(), 7, 1);
		this.tableProperties.setValueAt(""+modelMs3d.getScaleZ(), 8, 1);
		this.tableProperties.setValueAt(""+modelMs3d.isShadowEnabled(), 9, 1);
	}

	/**
	 * Saves the table data of the seleceted entity to the object.
	 * @param entity selected entity
	 */
	private void saveTableDataEntity(AbstractEntity entity)
	{
		if(entity instanceof Prop)
		{
			// just patch the data through, there are no
			// specicial table entries.
			if(entity.getMesh() instanceof Model3DS)
			{
				this.saveTableDataModel3DS(entity.getMesh());
			}
			if(entity.getMesh() instanceof ModelMD2)
			{
				this.saveTableDataModelMD2(entity.getMesh());
			}
			if(entity.getMesh() instanceof ModelMS3DAscii)
			{
				this.saveTableDataModelMS3D(entity.getMesh());
			}
			if(entity.getMesh() instanceof Terrain)
			{
				this.saveTableDataTerrain(entity.getMesh());
			}
			if(entity.getMesh() instanceof GroundPlane)
			{
				this.saveTableDataGroundPlane(entity.getMesh());
			}
		}
		// save special table data for items
		if(entity instanceof Item)
		{
			Item item = (Item)entity;
			if(item.getMesh() instanceof Model3DS)
			{
				this.saveTableDataModel3DS(item.getMesh());
			}
			if(item.getMesh() instanceof ModelMD2)
			{
				this.saveTableDataModelMD2(item.getMesh());
			}
			if(item.getMesh() instanceof ModelMS3DAscii)
			{
				this.saveTableDataModelMS3D(item.getMesh());
			}

			// save special data
			String name = (String)this.tableProperties.getValueAt(10, 1);
			item.setScreenName(name);
			boolean pickUp = Boolean.parseBoolean((String)this.tableProperties.getValueAt(11, 1));
			item.setCanBePickedUp(pickUp);
			String scriptId = (String)this.tableProperties.getValueAt(12, 1);
			item.setScriptId(scriptId);

		}
		// save special table data for characters
		if(entity instanceof NonPlayerCharacter)
		{
			NonPlayerCharacter npc = (NonPlayerCharacter)entity;
			if(npc.getMesh() instanceof Model3DS)
			{
				this.saveTableDataModel3DS(npc.getMesh());
			}
			if(npc.getMesh() instanceof ModelMD2)
			{
				this.saveTableDataModelMD2(npc.getMesh());
			}
			if(npc.getMesh() instanceof ModelMS3DAscii)
			{
				this.saveTableDataModelMS3D(npc.getMesh());
			}

			// save special data
			String name = (String)this.tableProperties.getValueAt(10, 1);
			npc.setScreenName(name);
			String scriptId = (String)this.tableProperties.getValueAt(11, 1);
			npc.setScriptId(scriptId);
		}

		// save special table data for props
		if(entity instanceof Prop)
		{
			Prop prop = (Prop)entity;
			if(prop.getMesh() instanceof Model3DS)
			{
				this.saveTableDataModel3DS(prop.getMesh());
			}
			if(prop.getMesh() instanceof ModelMD2)
			{
				this.saveTableDataModelMD2(prop.getMesh());
			}
			if(prop.getMesh() instanceof ModelMS3DAscii)
			{
				this.saveTableDataModelMS3D(prop.getMesh());
			}

			// save special data
			String scriptId = (String)this.tableProperties.getValueAt(10, 1);
			prop.setScriptId(scriptId);
		}
	}

	/**
	 * Convenience method to insert the data of a heightmap terrain to
	 * the table.
	 * @param mesh AbstractMesh object that actually
	 * is a Terrain object
	 */
	private void setTableDataTerrain(AbstractMesh mesh)
	{
		Terrain terrain = (Terrain)mesh;
		this.tableProperties.setValueAt(""+terrain.getPosX(), 0, 1);
		this.tableProperties.setValueAt(""+terrain.getPosY(), 1, 1);
		this.tableProperties.setValueAt(""+terrain.getPosZ(), 2, 1);
		this.tableProperties.setValueAt(""+terrain.getRotX(), 3, 1);
		this.tableProperties.setValueAt(""+terrain.getRotY(), 4, 1);
		this.tableProperties.setValueAt(""+terrain.getRotZ(), 5, 1);
		this.tableProperties.setValueAt(""+terrain.getScaleX(), 6, 1);
		this.tableProperties.setValueAt(""+terrain.getScaleY(), 7, 1);
		this.tableProperties.setValueAt(""+terrain.getScaleZ(), 8, 1);
	}

	/**
	 * Convenience method to insert the data of a ground plain to
	 * the table.
	 * @param mesh AbstractMesh object that actually
	 * is a GroundPlane object
	 */
	private void setTableDataGroundPlane(AbstractMesh mesh)
	{
		GroundPlane plane = (GroundPlane)mesh;
		this.tableProperties.setValueAt(""+plane.getPosX(), 0, 1);
		this.tableProperties.setValueAt(""+plane.getPosY(), 1, 1);
		this.tableProperties.setValueAt(""+plane.getPosZ(), 2, 1);
		this.tableProperties.setValueAt(""+plane.getRotX(), 3, 1);
		this.tableProperties.setValueAt(""+plane.getRotY(), 4, 1);
		this.tableProperties.setValueAt(""+plane.getRotZ(), 5, 1);
		this.tableProperties.setValueAt(""+plane.getScaleX(), 6, 1);
		this.tableProperties.setValueAt(""+plane.getScaleY(), 7, 1);
		this.tableProperties.setValueAt(""+plane.getScaleZ(), 8, 1);
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the AbstractMesh object that actually
	 * is a Model3DS object
	 * @param mesh AbstractMesh object that actually
	 * is a Model3DS object
	 */
	private void saveTableDataModel3DS(AbstractMesh mesh)
	{
		Model3DS model3ds = (Model3DS)mesh;

		// apply mesh position properties
		model3ds.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2,1)));

		// apply mesh rotation properties
		model3ds.setRotation(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)));

		// apply mesh scale properties
		model3ds.scale(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)));

		model3ds.setShadowEnabled(Boolean.parseBoolean((String)this.tableProperties.getValueAt(9, 1)));
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the AbstractMesh object that actually
	 * is a ModelMD2 object
	 * @param mesh AbstractMesh object that actually
	 * is a ModelMD2 object
	 */
	private void saveTableDataModelMD2(AbstractMesh mesh)
	{
		ModelMD2 modelMd2 = (ModelMD2)mesh;

		// apply mesh position properties
		modelMd2.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2,1)));

		// apply dmesh rotation properties
		modelMd2.setRotation(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)));

		// apply mesh scale properties
		modelMd2.scale(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)));

		modelMd2.setShadowEnabled(Boolean.parseBoolean((String)this.tableProperties.getValueAt(9, 1)));
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the AbstractMesh object that actually
	 * is a ModelMS3DAscii object
	 * @param mesh AbstractMesh object that actually
	 * is a ModelMS3DAscii object
	 */
	private void saveTableDataModelMS3D(AbstractMesh mesh)
	{
		ModelMS3DAscii modelMs3d = (ModelMS3DAscii)mesh;

		// apply mesh position properties
		modelMs3d.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2,1)));

		// apply mesh rotation properties
		modelMs3d.setRotation(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)));

		// apply mesh scale properties
		modelMs3d.scale(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)));

		modelMs3d.setShadowEnabled(Boolean.parseBoolean((String)this.tableProperties.getValueAt(9, 1)));
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the AbstractMesh object that actually
	 * is a (heightmap) Terrain object
	 * @param mesh AbstractMesh object that actually
	 * is a Terrain object
	 */
	private void saveTableDataTerrain(AbstractMesh mesh)
	{
		Terrain terrain = (Terrain)mesh;

		// apply mesh position properties
		terrain.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2,1)));

		// apply dmesh rotation properties
		terrain.setRotation(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)));

		// apply mesh scale properties
		terrain.scale(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)));
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the AbstractMesh object that actually
	 * is a GroundPlane object
	 * @param mesh AbstractMesh object that actually
	 * is a GroundPlane object
	 */
	private void saveTableDataGroundPlane(AbstractMesh mesh)
	{
		GroundPlane plain = (GroundPlane)mesh;

		// apply mesh position properties
		plain.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2,1)));

		// apply mesh rotation properties
		plain.setRotation(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)));

		// apply mesh scale properties
		plain.scale(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)));
	}

	/**
	 * Convenience method to apply the current table properties
	 * to the selected camera perspective.
	 * @param persp camera perspective to apply the data to
	 */
	private void saveTableDataCamPerspectives(CameraPerspective persp)
	{
		// apply position properties
		persp.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0,1))*-1,
				Float.parseFloat((String)this.tableProperties.getValueAt(1,1))*-1,
				Float.parseFloat((String)this.tableProperties.getValueAt(2,1))*-1);

		// apply rotation properties
		persp.setRotX(Float.parseFloat((String)this.tableProperties.getValueAt(3,1))*-1);
		persp.setRotY(Float.parseFloat((String)this.tableProperties.getValueAt(4,1))*-1);


		// apply remaining properties
		persp.setFieldOfView(Float.parseFloat((String)this.tableProperties.getValueAt(5,1)));
		persp.setNearPlane(Float.parseFloat((String)this.tableProperties.getValueAt(6,1)));
		persp.setFarPlane(Float.parseFloat((String)this.tableProperties.getValueAt(7,1)));
	}


	/**
	 * Convenience method to insert the data of a directional
	 * light to the table.
	 * @param light LightIface object that actually
	 * is a DirectionalLight object
	 */
	private void setTableDataDirectLight(LightIface light)
	{
		DirectionalLight posLight = (DirectionalLight)light;

		Point3D dir = posLight.getDirection();

		this.clearTableData();
		this.tableProperties.setValueAt("dir x:", 0, 0);
		this.tableProperties.setValueAt("dir y:", 1, 0);
		this.tableProperties.setValueAt("dir z:", 2, 0);
		this.tableProperties.setValueAt("Amb red:", 3, 0);
		this.tableProperties.setValueAt("Amb green:", 4, 0);
		this.tableProperties.setValueAt("Amb blue:", 5, 0);
		this.tableProperties.setValueAt("Diff red:", 6, 0);
		this.tableProperties.setValueAt("Diff green:", 7, 0);
		this.tableProperties.setValueAt("Diff blue:", 8, 0);

		this.tableProperties.setValueAt(""+dir.x, 0, 1);
		this.tableProperties.setValueAt(""+dir.y, 1, 1);
		this.tableProperties.setValueAt(""+dir.z, 2, 1);
		this.tableProperties.setValueAt(""+posLight.getAmbient().red, 3, 1);
		this.tableProperties.setValueAt(""+posLight.getAmbient().green, 4, 1);
		this.tableProperties.setValueAt(""+posLight.getAmbient().blue, 5, 1);
		this.tableProperties.setValueAt(""+posLight.getDiffuse().red, 6, 1);
		this.tableProperties.setValueAt(""+posLight.getDiffuse().green, 7, 1);
		this.tableProperties.setValueAt(""+posLight.getDiffuse().blue, 8, 1);
	}

	/**
	 * Convenience method to insert the data of a positional
	 * light to the table.
	 * @param light LightIface object that actually
	 * is a PositionalLight object
	 */
	private void setTableDataPosLight(LightIface light)
	{
		PositionalLight posLight = (PositionalLight)light;

		Point3D pos = posLight.getPosition();

		this.clearTableData();
		this.tableProperties.setValueAt("x:", 0, 0);
		this.tableProperties.setValueAt("y:", 1, 0);
		this.tableProperties.setValueAt("z:", 2, 0);
		this.tableProperties.setValueAt("Amb red:", 3, 0);
		this.tableProperties.setValueAt("Amb green:", 4, 0);
		this.tableProperties.setValueAt("Amb blue:", 5, 0);
		this.tableProperties.setValueAt("Diff red:", 6, 0);
		this.tableProperties.setValueAt("Diff green:", 7, 0);
		this.tableProperties.setValueAt("Diff blue:", 8, 0);

		this.tableProperties.setValueAt(""+pos.x, 0, 1);
		this.tableProperties.setValueAt(""+pos.y, 1, 1);
		this.tableProperties.setValueAt(""+pos.z, 2, 1);
		this.tableProperties.setValueAt(""+posLight.getAmbient().red, 3, 1);
		this.tableProperties.setValueAt(""+posLight.getAmbient().green, 4, 1);
		this.tableProperties.setValueAt(""+posLight.getAmbient().blue, 5, 1);
		this.tableProperties.setValueAt(""+posLight.getDiffuse().red, 6, 1);
		this.tableProperties.setValueAt(""+posLight.getDiffuse().green, 7, 1);
		this.tableProperties.setValueAt(""+posLight.getDiffuse().blue, 8, 1);
	}

	/**
	 * Convenience method to insert the data of a spot
	 * light to the table.
	 * @param light LightIface object that actually
	 * is a SpotLight object
	 */
	private void setTableDataSpotLight(LightIface light)
	{
		SpotLight spot = (SpotLight)light;

		Point3D pos = spot.getPosition();
		float rotX = spot.getRotX();
		float rotY = spot.getRotY();
		float cutOff = spot.getCutoff();
		float exp = spot.getExponent();

		this.clearTableData();
		this.tableProperties.setValueAt("x:", 0, 0);
		this.tableProperties.setValueAt("y:", 1, 0);
		this.tableProperties.setValueAt("z:", 2, 0);
		this.tableProperties.setValueAt("rot x:", 3, 0);
		this.tableProperties.setValueAt("rot y:", 4, 0);
		this.tableProperties.setValueAt("cutoff:", 5, 0);
		this.tableProperties.setValueAt("exponent:", 6, 0);
		this.tableProperties.setValueAt("Amb red:", 7, 0);
		this.tableProperties.setValueAt("Amb green:", 8, 0);
		this.tableProperties.setValueAt("Amb blue:", 9, 0);
		this.tableProperties.setValueAt("Diff red:", 10, 0);
		this.tableProperties.setValueAt("Diff green:", 11, 0);
		this.tableProperties.setValueAt("Diff blue:", 12, 0);

		this.tableProperties.setValueAt(""+pos.x, 0, 1);
		this.tableProperties.setValueAt(""+pos.y, 1, 1);
		this.tableProperties.setValueAt(""+pos.z, 2, 1);
		this.tableProperties.setValueAt(""+rotX, 3, 1);
		this.tableProperties.setValueAt(""+rotY, 4, 1);
		this.tableProperties.setValueAt(""+cutOff, 5, 1);
		this.tableProperties.setValueAt(""+exp, 6, 1);
		this.tableProperties.setValueAt(""+spot.getAmbient().red, 7, 1);
		this.tableProperties.setValueAt(""+spot.getAmbient().green, 8, 1);
		this.tableProperties.setValueAt(""+spot.getAmbient().blue, 9, 1);
		this.tableProperties.setValueAt(""+spot.getDiffuse().red, 10, 1);
		this.tableProperties.setValueAt(""+spot.getDiffuse().green, 11, 1);
		this.tableProperties.setValueAt(""+spot.getDiffuse().blue, 12, 1);
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the LightIface object that actually
	 * is a DirectionalLight object
	 * @param light LightIface object that actually
	 * is a DirectionalLight object
	 */
	private void saveTableDataDirectLight(LightIface light)
	{
		DirectionalLight dirLight = (DirectionalLight)light;

		// apply light position properties
		dirLight.setDirection(
				Float.parseFloat((String)this.tableProperties.getValueAt(0, 1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1, 1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2, 1)));

		// apply ambient light properties
		dirLight.setAmbient(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)),
				dirLight.getAmbient().alpha);

		// apply diffuse light properties
		dirLight.setDiffuse(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)),
				dirLight.getDiffuse().alpha);
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the LightIface object that actually
	 * is a PositionalLight object
	 * @param light LightIface object that actually
	 * is a PositionalLight object
	 */
	private void saveTableDataPosLight(LightIface light)
	{
		PositionalLight posLight = (PositionalLight)light;

		// apply light position properties
		posLight.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0, 1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1, 1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2, 1)));

		// apply ambient light properties
		posLight.setAmbient(
				Float.parseFloat((String)this.tableProperties.getValueAt(3,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(4,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(5,1)),
				posLight.getAmbient().alpha);

		// apply diffuse light properties
		posLight.setDiffuse(
				Float.parseFloat((String)this.tableProperties.getValueAt(6,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)),
				posLight.getDiffuse().alpha);
	}

	/**
	 * Convenience method to apply the (possibly changed) table
	 * properties to the LightIface object that actually
	 * is a SpotLight object
	 * @param light LightIface object that actually
	 * is a SpotLight object
	 */
	private void saveTableDataSpotLight(LightIface light)
	{
		SpotLight spot = (SpotLight)light;

		// apply light position properties
		spot.setPosition(
				Float.parseFloat((String)this.tableProperties.getValueAt(0, 1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(1, 1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(2, 1)));

		// apply special spot light properties (direction, cutoff, exponent)
		spot.setRotX(Float.parseFloat((String)this.tableProperties.getValueAt(3, 1)));
		spot.setRotY(Float.parseFloat((String)this.tableProperties.getValueAt(4, 1)));
		spot.setCutOff(Float.parseFloat((String)this.tableProperties.getValueAt(5, 1)));
		spot.setExponent(Float.parseFloat((String)this.tableProperties.getValueAt(6, 1)));

		// apply ambient light properties
		spot.setAmbient(
				Float.parseFloat((String)this.tableProperties.getValueAt(7,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(8,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(9,1)),
				spot.getAmbient().alpha);

		// apply diffuse light properties
		spot.setDiffuse(
				Float.parseFloat((String)this.tableProperties.getValueAt(10,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(11,1)),
				Float.parseFloat((String)this.tableProperties.getValueAt(12,1)),
				spot.getDiffuse().alpha);
	}

	/**
	 * This method initializes btnRemove
	 *
	 * @return javax.swing.JButton
	 */
	private JButton getBtnRemove()
	{
		if (this.btnRemove == null)
		{
			this.btnRemove = new JButton();
			this.btnRemove.setText("Remove selected");
			this.btnRemove.setPreferredSize(new Dimension(125, 23));
			this.btnRemove.setHorizontalAlignment(SwingConstants.CENTER);
			this.btnRemove.addActionListener(new java.awt.event.ActionListener()
			{
				public void actionPerformed(java.awt.event.ActionEvent e)
				{
					if(EditorMenu.this.lastSelectType == NOTHING_SELECTED) return;

					if(EditorMenu.this.lastSelectType == MESH_SELECTED)
					{
						// remove the selected mesh from the scene

						String name = (String)listMeshes.getSelectedValue();
						// clear the value from additions like "(npc), (item), (prop)"
						name = name.substring(0,name.indexOf(" ("));

						AbstractMesh mesh = WorldEditor.room.getMeshes().getMeshByName(name);
						AbstractEntity entity = WorldEditor.room.getEntityByMesh(mesh);

						// reset the backup values
						EditorMenu.this.materialBackup = null;
						EditorMenu.this.lastSelectedMeshName = null;

						if(entity instanceof NonPlayerCharacter)
						{
							WorldEditor.room.removeCharacter((NonPlayerCharacter)entity);
						}
						if(entity instanceof Item)
						{
							WorldEditor.room.removeItem((Item)entity);
						}
						if(entity instanceof Prop)
						{
							WorldEditor.room.removeProp((Prop)entity);
						}

						// remove the selected mesh from the list data
						Vector<String> data = new Vector<String>();
						int size = listMeshes.getModel().getSize();
						for(int i=0; i<size; i++)
							data.add((String)listMeshes.getModel().getElementAt(i));

						int selectionIndex = listMeshes.getSelectedIndex();
						data.removeElementAt(selectionIndex);
						listMeshes.setListData(data);
					}


					if(EditorMenu.this.lastSelectType == LIGHT_SELECTED)
					{
						// remove the seleceted light from the scene.
						int selectedLightNr = Integer.parseInt((String)listLights.getSelectedValue());
						if(selectedLightNr >= 0 && selectedLightNr <= 7)
						{
							AbstractLight light = (AbstractLight)WorldEditor.room.getLight(selectedLightNr);
							WorldEditor.room.removeLight(light);
						}

						// remove the selected light from the list data
						Vector<String> data = new Vector<String>();
						int size = listLights.getModel().getSize();
						for(int i=0; i<size; i++)
							data.add((String)listLights.getModel().getElementAt(i));

						int selectionIndex = listLights.getSelectedIndex();
						data.removeElementAt(selectionIndex);
						listLights.setListData(data);

					}


					if(EditorMenu.this.lastSelectType == CAM_SELECTED)
					{
						// remove the seleceted camera perspective from the scene.
						int selectedPerspNr = Integer.parseInt((String)listCamPerspectives.getSelectedValue());
						if(selectedPerspNr >= 0 && selectedPerspNr <= 31)
						{
							WorldEditor.room.removeCameraPerspective(selectedPerspNr);
						}

						// remove the selected perspective from the list data
						Vector<String> data = new Vector<String>();
						int size = listCamPerspectives.getModel().getSize();
						for(int i=0; i<size; i++)
							data.add((String)listCamPerspectives.getModel().getElementAt(i));

						int selectionIndex = listCamPerspectives.getSelectedIndex();
						data.removeElementAt(selectionIndex);
						listCamPerspectives.setListData(data);

					}

					if(EditorMenu.this.lastSelectType == TRIGGER_SELECTED)
					{
						// remove the seleceted trigger from the scene.
						String selectedTriggerName = (String)listTriggers.getSelectedValue();
						WorldEditor.room.removeTrigger(selectedTriggerName);


						// remove the selected trigger from the list data
						Vector<String> data = new Vector<String>();
						int size = listTriggers.getModel().getSize();
						for(int i=0; i<size; i++)
							data.add((String)listTriggers.getModel().getElementAt(i));

						int selectionIndex = listTriggers.getSelectedIndex();
						data.removeElementAt(selectionIndex);
						listTriggers.setListData(data);

					}

					if(EditorMenu.this.lastSelectType == HOTSPOT_SELECTED)
					{
						// remove the seleceted hotspot from the scene.
						String selectedHotspotName = (String)listHotspots.getSelectedValue();
						WorldEditor.room.removeHotspot(selectedHotspotName);


						// remove the selected hotspot from the list data
						Vector<String> data = new Vector<String>();
						int size = listHotspots.getModel().getSize();
						for(int i=0; i<size; i++)
							data.add((String)listHotspots.getModel().getElementAt(i));

						int selectionIndex = listHotspots.getSelectedIndex();
						data.removeElementAt(selectionIndex);
						listHotspots.setListData(data);
					}

					// clear selection
					EditorMenu.this.lastSelectType = NOTHING_SELECTED;
					listMeshes.clearSelection();
					listLights.clearSelection();
					listCamPerspectives.clearSelection();
					listTriggers.clearSelection();
					listHotspots.clearSelection();
					EditorMenu.this.clearTableData();
				}
			});
		}
		return this.btnRemove;
	}

	/**
	 * This method initializes jScrollPaneHotspotList
	 *
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getJScrollPaneHotspotList()
	{
		if (this.jScrollPaneHotspotList == null)
		{
			this.jScrollPaneHotspotList = new JScrollPane();
			this.jScrollPaneHotspotList.setPreferredSize(new Dimension(259, 131));
			this.jScrollPaneHotspotList.setViewportView(this.getListHotspots());
		}
		return this.jScrollPaneHotspotList;
	}

	/**
	 * This method initializes listHotspots
	 *
	 * @return javax.swing.JList
	 */
	private JList getListHotspots()
	{
		if (listHotspots == null)
		{
			listHotspots = new JList(new DefaultListModel());
			listHotspots.setSize(new Dimension(130, 72));

			listHotspots
			.addListSelectionListener(new javax.swing.event.ListSelectionListener()
			{
				public void valueChanged(javax.swing.event.ListSelectionEvent e)
				{
					EditorMenu.this.lastSelectType = HOTSPOT_SELECTED;
					listLights.clearSelection();
					listCamPerspectives.clearSelection();
					listMeshes.clearSelection();
					listTriggers.clearSelection();

					int hotspotListSelIndex = listHotspots.getSelectedIndex();
					if(hotspotListSelIndex != -1)
					{
						EditorMenu.this.clearTableData();
						// this table data is always needed
						EditorMenu.this.tableProperties.setValueAt("x:", 0, 0);
						EditorMenu.this.tableProperties.setValueAt("y:", 1, 0);
						EditorMenu.this.tableProperties.setValueAt("z:", 2, 0);
						EditorMenu.this.tableProperties.setValueAt("scriptid:", 3, 0);

						AbstractInteractiveHotspot hotspot = WorldEditor.room.getHotspot((String)listHotspots.getSelectedValue());

						// add the concrete hotspot data to the table
						EditorMenu.this.tableProperties.setValueAt(""+hotspot.getPosition().x, 0, 1);
						EditorMenu.this.tableProperties.setValueAt(""+hotspot.getPosition().y, 1, 1);
						EditorMenu.this.tableProperties.setValueAt(""+hotspot.getPosition().z, 2, 1);
						EditorMenu.this.tableProperties.setValueAt(""+hotspot.getScriptId(), 3, 1);

						if(hotspot instanceof SphericalHotspot)
						{
							SphericalHotspot sphere = (SphericalHotspot)hotspot;
							EditorMenu.this.tableProperties.setValueAt("radius:", 4, 0);
							EditorMenu.this.tableProperties.setValueAt(""+sphere.getRadius(), 4, 1);
							EditorMenu.this.tableProperties.setValueAt("needs item", 5, 0);
							EditorMenu.this.tableProperties.setValueAt(""+sphere.needsItem(), 5, 1);

						}
						else if(hotspot instanceof CubicalHotpot)
						{
							CubicalHotpot box = (CubicalHotpot)hotspot;
							EditorMenu.this.tableProperties.setValueAt("width:", 4, 0);
							EditorMenu.this.tableProperties.setValueAt("height:", 5, 0);
							EditorMenu.this.tableProperties.setValueAt("length:", 6, 0);
							EditorMenu.this.tableProperties.setValueAt(""+box.getWidth(), 4, 1);
							EditorMenu.this.tableProperties.setValueAt(""+box.getHeight(), 5, 1);
							EditorMenu.this.tableProperties.setValueAt(""+box.getLength(), 6, 1);
							EditorMenu.this.tableProperties.setValueAt("needs item", 7, 0);
							EditorMenu.this.tableProperties.setValueAt(""+box.needsItem(), 7, 1);

						}
					}
				}
			});
		}
		return listHotspots;
	}

	/**
	 * This method initializes jTabbedPane
	 *
	 * @return javax.swing.JTabbedPane
	 */
	private JTabbedPane getJTabbedPane()
	{
		if (this.jTabbedPane == null)
		{
			this.jTabbedPane = new JTabbedPane();
			this.jTabbedPane.setPreferredSize(new Dimension(264, 220));
			this.jTabbedPane.setTabPlacement(JTabbedPane.TOP);
			this.jTabbedPane.addTab("Meshes", null, this.getPanelMeshes(), null);
			this.jTabbedPane.addTab("Lights", null, this.getPanelLights(), null);
			this.jTabbedPane.addTab("Cams", null, this.getPanelCameras(), null);
			this.jTabbedPane.addTab("Hotspots", null, this.getPanelHotspots(), null);
			this.jTabbedPane.addTab("Triggers", null, this.getPanelTriggers(), null);
		}
		return this.jTabbedPane;
	}

	/**
	 * This method initializes panelMeshes
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelMeshes()
	{
		if (this.panelMeshes == null)
		{
			this.panelMeshes = new JPanel();
			this.panelMeshes.setLayout(new BoxLayout(this.getPanelMeshes(), BoxLayout.Y_AXIS));

			this.labelMeshes = new JLabel();
			this.labelMeshes.setText("Meshes");
			this.panelMeshes.add(this.labelMeshes, null);
			this.panelMeshes.add(this.getJScrollPaneMeshList(), null);
		}
		return this.panelMeshes;
	}

	/**
	 * This method initializes panelLights
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelLights()
	{
		if (this.panelLights == null)
		{
			this.panelLights = new JPanel();
			this.panelLights.setLayout(new BoxLayout(this.getPanelLights(), BoxLayout.Y_AXIS));

			this.labelLights = new JLabel();
			this.labelLights.setText("Lights");

			this.panelLights.add(this.labelLights, null);
			this.panelLights.add(this.getJScrollPaneLightList(), null);
		}
		return this.panelLights;
	}

	/**
	 * This method initializes panelCameras
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelCameras()
	{
		if (this.panelCameras == null)
		{
			this.panelCameras = new JPanel();
			this.panelCameras.setLayout(new BoxLayout(this.getPanelCameras(), BoxLayout.Y_AXIS));

			this.labelCams = new JLabel();
			this.labelCams.setText("Cameras");

			this.panelCameras.add(this.labelCams, null);
			this.panelCameras.add(this.getJScrollPaneCamPerspectivesList(), null);
		}
		return this.panelCameras;
	}

	/**
	 * This method initializes panelHotspots
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelHotspots()
	{
		if (this.panelHotspots == null)
		{
			this.panelHotspots = new JPanel();
			this.panelHotspots.setLayout(new BoxLayout(this.getPanelHotspots(), BoxLayout.Y_AXIS));

			this.labelHotspots = new JLabel();
			this.labelHotspots.setText("Hotspots");

			this.panelHotspots.add(this.labelHotspots, null);
			this.panelHotspots.add(this.getJScrollPaneHotspotList(), null);
		}
		return this.panelHotspots;
	}

	/**
	 * This method initializes panelTriggers
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelTriggers()
	{
		if (this.panelTriggers == null)
		{
			this.panelTriggers = new JPanel();
			this.panelTriggers.setLayout(new BoxLayout(this.getPanelTriggers(), BoxLayout.Y_AXIS));

			this.labelTriggers = new JLabel();
			this.labelTriggers.setText("Triggers");

			this.panelTriggers.add(this.labelTriggers, null);
			this.panelTriggers.add(this.getJScrollPaneTriggersList(), null);
		}
		return this.panelTriggers;
	}

	/**
	 * This method initializes panelObjects
	 *
	 * @return javax.swing.JPanel
	 */
	private JPanel getPanelObjects()
	{
		if (this.panelObjects == null)
		{
			this.labelForGap = new JLabel();
			this.labelForGap.setText("   "); // just a gap
			this.labelForGap.setVisible(true);
			this.panelObjects = new JPanel();
			this.panelObjects.setLayout(new BoxLayout(this.getPanelObjects(), BoxLayout.Y_AXIS));
			this.panelObjects.add(this.getJTabbedPane(), null);
			this.panelObjects.add(this.getBtnRemove(), null);
			this.panelObjects.add(this.labelForGap, null);
		}
		return this.panelObjects;
	}

}  // @jve:decl-index=0:visual-constraint="10,10"


