package de.rico.editor.gui;

import java.awt.event.ActionEvent;
import java.io.File;

import javax.swing.AbstractAction;
import javax.swing.ButtonGroup;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.ToolTipManager;

import de.rico.editor.WorldEditor;
import de.rico.editor.enums.Mode;
import de.rico.editor.gui.dialog.DialogAddCamPersp;
import de.rico.editor.gui.dialog.DialogAddGroundPlane;
import de.rico.editor.gui.dialog.DialogAddHMTerrain;
import de.rico.editor.gui.dialog.DialogAddHotspot;
import de.rico.editor.gui.dialog.DialogAddLight;
import de.rico.editor.gui.dialog.DialogAddMesh;
import de.rico.editor.gui.dialog.DialogAddSkybox;
import de.rico.editor.gui.dialog.DialogAddTrigger;
import de.rico.editor.gui.dialog.DialogExportScriptFile;
import de.rico.editor.gui.dialog.DialogLoadRecording;
import de.rico.editor.gui.dialog.DialogLoadRoom;
import de.rico.editor.gui.dialog.DialogSaveCreatedPath;
import de.rico.editor.gui.dialog.DialogSaveRecording;
import de.rico.editor.gui.dialog.DialogSaveRoom;
import de.rico.editor.gui.dialog.DialogSetBaseFolder;
import de.rico.editor.gui.dialog.DialogSetRoomScriptFile;
import de.rico.editor.gui.dialog.DialogSetRoomScriptId;
import de.rico.editor.gui.dialog.DialogSetShadowRefLight;
import de.rico.editor.gui.filter.Filter3DS;
import de.rico.editor.gui.filter.FilterImage;
import de.rico.editor.gui.filter.FilterMD2;
import de.rico.editor.gui.filter.FilterMS3D;

public class MainMenuBar extends JMenuBar
{
	private JRadioButtonMenuItem radioModeConstruction = null;
	private JRadioButtonMenuItem radioModePathGrid = null;
	private JRadioButtonMenuItem radioModeRecorder = null;
	private JRadioButtonMenuItem radioModeTrigger = null;
	private JRadioButtonMenuItem radionModePath = null;
	private JRadioButtonMenuItem radioModePathCreation = null;
	private JMenuItem loadRecording;
	private JMenuItem saveRecording;
	private JMenuItem playRecording;
	private JMenuItem resetRecording;
	private JMenuItem addTrigger;
	private JMenuItem addHotspot;
	private JMenuItem exportMethods;
	private JMenuItem savePath;

	public MainMenuBar(JFrame mainFrame)
	{
		JPopupMenu.setDefaultLightWeightPopupEnabled(false);
		ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);

		this.createFileMenu(mainFrame);
		this.createMeshMenu(mainFrame);
		this.createLightMenu(mainFrame);
		this.createCameraMenu(mainFrame);
		this.createScriptingMenu(mainFrame);
		this.createPathMenu(mainFrame);
		this.createModeMenu(mainFrame);
	}

	/**
	 * Creates the file menu content.
	 * @param mainFrame the main frame
	 */
	private void createFileMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// File menu
		JMenu menuFile = new JMenu("File");

		JMenuItem load = new JMenuItem();
		load.setAction(new AbstractAction("Load room")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogLoadRoom(frame).setVisible(true);
			}

		});
		load.setToolTipText("Loads a .room file.");
		menuFile.add(load);


		JMenuItem save = new JMenuItem();
		save.setAction(new AbstractAction("Save room")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogSaveRoom(frame).setVisible(true);
			}

		});
		save.setToolTipText("Saves the scene to a .room file.");
		menuFile.add(save);


		JMenuItem setBaseFolder = new JMenuItem();
		setBaseFolder.setAction(new AbstractAction("Set room's base folder")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogSetBaseFolder(frame).setVisible(true);
			}

		});
		setBaseFolder.setToolTipText("<html>Sets the base folder <br>to create relative file pathes <br>in the .room file.</html>");
		menuFile.add(setBaseFolder);

		JMenuItem runGC = new JMenuItem();
		runGC.setAction(new AbstractAction("Run garbage collection")
		{

			public void actionPerformed(ActionEvent e)
			{
				System.gc();
			}

		});
		runGC.setToolTipText("<html>Runs garbage collection <br>to free heap space memory.</html>");
		menuFile.add(runGC);

		JMenuItem quit = new JMenuItem();
		quit.setAction(new AbstractAction("Quit")
		{

			public void actionPerformed(ActionEvent e)
			{
				System.exit(0);
			}

		});
		quit.setToolTipText("Closes the editor");
		menuFile.add(quit);

		this.add(menuFile);
	}


	/**
	 * Creates the mesh menu content.
	 * @param mainFrame the main frame
	 */
	private void createMeshMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// Instert mesh menu
		JMenu addMesh = new JMenu("Mesh");

		JMenuItem addSkybox = new JMenuItem();
		addSkybox.setAction(new AbstractAction("Add skybox")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogAddSkybox(frame).setVisible(true);
			}

		});
		addMesh.add(addSkybox);


		JMenuItem load3ds = new JMenuItem();
		load3ds.setAction(new AbstractAction("Load 3D Studio Max file (.3ds)")
		{

			public void actionPerformed(ActionEvent e)
			{
				JFileChooser fc = new JFileChooser();
				fc.setCurrentDirectory(new File("./"));

				fc.setAcceptAllFileFilterUsed(false);
				fc.setFileFilter(new Filter3DS());
				int returnVal = fc.showOpenDialog(frame);

				if (returnVal == JFileChooser.APPROVE_OPTION)
				{
					File file = fc.getSelectedFile();
					new DialogAddMesh(frame, file).setVisible(true);
				}

			}

		});
		addMesh.add(load3ds);

		JMenuItem loadMd2 = new JMenuItem();
		loadMd2.setAction(new AbstractAction("Load Quake2 model file (.md2) - No automatic centering!")
		{

			public void actionPerformed(ActionEvent e)
			{
				JFileChooser fc = new JFileChooser();
				fc.setCurrentDirectory(new File("./"));

				fc.setAcceptAllFileFilterUsed(false);
				fc.setFileFilter(new FilterMD2());
				int returnVal = fc.showOpenDialog(frame);

				if (returnVal == JFileChooser.APPROVE_OPTION)
				{
					File file = fc.getSelectedFile();
					new DialogAddMesh(frame, file).setVisible(true);
				}

			}

		});
		addMesh.add(loadMd2);

		JMenuItem loadMS3D = new JMenuItem();
		loadMS3D.setAction(new AbstractAction("Load Milkshape3D file (.txt) - No automatic centering, if animated!")
		{

			public void actionPerformed(ActionEvent e)
			{
				JFileChooser fc = new JFileChooser();
				fc.setCurrentDirectory(new File("./"));

				fc.setAcceptAllFileFilterUsed(false);
				fc.setFileFilter(new FilterMS3D());
				int returnVal = fc.showOpenDialog(frame);

				if (returnVal == JFileChooser.APPROVE_OPTION)
				{
					File file = fc.getSelectedFile();
					new DialogAddMesh(frame, file).setVisible(true);
				}

			}

		});
		addMesh.add(loadMS3D);


		JMenuItem loadHeightMapTerrain = new JMenuItem();
		loadHeightMapTerrain.setAction(new AbstractAction("Load Heightmap Terrain")
		{

			public void actionPerformed(ActionEvent e)
			{
				JFileChooser fc = new JFileChooser();
				fc.setCurrentDirectory(new File("./"));
				fc.setFileFilter(new FilterImage());

				int returnVal = fc.showOpenDialog(frame);

				if (returnVal == JFileChooser.APPROVE_OPTION)
				{
					File file = fc.getSelectedFile();
					new DialogAddHMTerrain(frame, file).setVisible(true);
				}

			}

		});
		addMesh.add(loadHeightMapTerrain);


		JMenuItem addGroundPlane = new JMenuItem();
		addGroundPlane.setAction(new AbstractAction("Add Ground Plain")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogAddGroundPlane(frame).setVisible(true);
			}

		});
		addMesh.add(addGroundPlane);




		this.add(addMesh);
	}

	/**
	 * Creates the light menu content.
	 * @param mainFrame the main frame
	 */
	private void createLightMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// Instert light menu
		JMenu menuLight = new JMenu("Light");
		JMenuItem addLight = new JMenuItem();
		addLight.setAction(new AbstractAction("Insert Light")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogAddLight(frame).setVisible(true);
			}

		});
		menuLight.add(addLight);

		JMenuItem setShadowRefLight = new JMenuItem();
		setShadowRefLight.setAction(new AbstractAction("Set shadow reference light")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogSetShadowRefLight(frame).setVisible(true);
			}

		});
		menuLight.add(setShadowRefLight);

		JMenuItem clearShadowRefLight = new JMenuItem();
		clearShadowRefLight.setAction(new AbstractAction("Clear shadow reference light")
		{

			public void actionPerformed(ActionEvent e)
			{
				// set the shadow reference light to null
				WorldEditor.room.setShadowReferenceLight(null);
			}

		});
		menuLight.add(clearShadowRefLight);

		this.add(menuLight);
	}

	/**
	 * Creates the camera menu content.
	 * @param mainFrame the main frame
	 */
	private void createCameraMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// Instert camera menu
		JMenu menuCam = new JMenu("Camera");
		JMenuItem addCam = new JMenuItem();
		addCam.setAction(new AbstractAction("Add camera perspective")
		{

			public void actionPerformed(ActionEvent e)
			{
				// adds a camera perspective to the scene and the
				// editor menu
				new DialogAddCamPersp(frame).setVisible(true);
			}

		});
		menuCam.add(addCam);

		this.loadRecording = new JMenuItem();
		this.loadRecording.setAction(new AbstractAction("Load recorded cam flight")
		{

			public void actionPerformed(ActionEvent e)
			{
				// loads a recorded camera flight
				new DialogLoadRecording(frame).setVisible(true);
			}

		});
		this.loadRecording.setEnabled(false);
		menuCam.add(this.loadRecording);

		this.saveRecording = new JMenuItem();
		this.saveRecording.setAction(new AbstractAction("Save recorded cam flight")
		{

			public void actionPerformed(ActionEvent e)
			{
				// saves the current content of the camera
				// flight recorder. This should be the flight
				// that has been recorded last
				new DialogSaveRecording(frame).setVisible(true);
			}

		});
		this.saveRecording.setEnabled(false);
		menuCam.add(this.saveRecording);


		this.playRecording = new JMenuItem();
		this.playRecording.setAction(new AbstractAction("Play recorded cam flight")
		{

			public void actionPerformed(ActionEvent e)
			{
				// plays the recorded camera flight
				if(WorldEditor.camFlightPlayer != null)
				{
					WorldEditor.camFlightPlayer.reset();
					WorldEditor.camFlightPlayer.start();
				}
			}

		});
		this.playRecording.setEnabled(false);
		menuCam.add(this.playRecording);

		this.resetRecording = new JMenuItem();
		this.resetRecording.setAction(new AbstractAction("Reset cam flight recorder")
		{

			public void actionPerformed(ActionEvent e)
			{
				// plays the recorded camera flight
				if(WorldEditor.camFlightRecorder != null)
				{
					WorldEditor.camFlightRecorder.reset();
				}
			}

		});
		this.resetRecording.setEnabled(false);
		menuCam.add(this.resetRecording);

		this.add(menuCam);
	}

	/**
	 * Creates the path menu content.
	 * @param mainFrame the main frame
	 */
	private void createPathMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// Instert light menu
		JMenu menuPath = new JMenu("Path");
		this.savePath = new JMenuItem();
		this.savePath.setAction(new AbstractAction("Save path")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogSaveCreatedPath(frame).setVisible(true);
			}

		});
		menuPath.add(this.savePath);
		this.savePath.setEnabled(false);

		this.add(menuPath);
	}

	/**
	 * Creates the scripting menu content.
	 * @param mainFrame the main frame
	 */
	private void createScriptingMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// Instert scripting menu
		JMenu menuScripting = new JMenu("Scripting");

		this.addHotspot = new JMenuItem();
		this.addHotspot.setAction(new AbstractAction("Add a hotspot")
		{
			public void actionPerformed(ActionEvent e)
			{
				// adds a hotspot to the scene and the
				// editor menu
				new DialogAddHotspot(frame).setVisible(true);
			}
		});
		menuScripting.add(this.addHotspot);

		this.addTrigger = new JMenuItem();
		this.addTrigger.setAction(new AbstractAction("Add a trigger")
		{

			public void actionPerformed(ActionEvent e)
			{
				// adds a trigger to the scene and the
				// editor menu
				new DialogAddTrigger(frame).setVisible(true);
			}

		});
		this.addTrigger.setEnabled(false);
		menuScripting.add(this.addTrigger);

		this.exportMethods = new JMenuItem();
		this.exportMethods.setAction(new AbstractAction("Create script file (method bodies)")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogExportScriptFile(frame).setVisible(true);
			}

		});
		menuScripting.add(this.exportMethods);

		JMenuItem setScriptId = new JMenuItem();
		setScriptId.setAction(new AbstractAction("Set room's script id")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogSetRoomScriptId(frame).setVisible(true);
			}

		});
		menuScripting.add(setScriptId);

		JMenuItem setScriptFile= new JMenuItem();
		setScriptFile.setAction(new AbstractAction("Assign script file to room")
		{

			public void actionPerformed(ActionEvent e)
			{
				new DialogSetRoomScriptFile(frame).setVisible(true);
			}

		});
		menuScripting.add(setScriptFile);

		this.add(menuScripting);
	}

	/**
	 * Creates the mode menu content.
	 * @param mainFrame the main frame
	 */
	private void createModeMenu(JFrame mainFrame)
	{
		final JFrame frame = mainFrame;

		// Instert mode menu
		JMenu menuMode = new JMenu("Mode");

		// create radio button "Construction"
		this.radioModeConstruction = new JRadioButtonMenuItem();
		this.radioModeConstruction.setSelected(true);
		this.radioModeConstruction.setText("Construction");
		this.radioModeConstruction.addItemListener(new java.awt.event.ItemListener()
		{
			public void itemStateChanged(java.awt.event.ItemEvent e)
			{
				// enable normal construction mode
				WorldEditor.setMode(Mode.CONSTRUCTION);

				MainMenuBar.this.addHotspot.setEnabled(true);
				MainMenuBar.this.loadRecording.setEnabled(false);
				MainMenuBar.this.saveRecording.setEnabled(false);
				MainMenuBar.this.playRecording.setEnabled(false);
				MainMenuBar.this.addTrigger.setEnabled(false);
				MainMenuBar.this.resetRecording.setEnabled(false);
				MainMenuBar.this.savePath.setEnabled(false);
			}
		});
		menuMode.add(this.radioModeConstruction);

		// create radio button "Path Grid"
		this.radioModePathGrid = new JRadioButtonMenuItem();
		this.radioModePathGrid.setText("Path Grid");
		this.radioModePathGrid.addItemListener(new java.awt.event.ItemListener()
		{
			public void itemStateChanged(java.awt.event.ItemEvent e)
			{
				// enable path grid mode
				WorldEditor.setMode(Mode.PATH_GRID);

				MainMenuBar.this.loadRecording.setEnabled(false);
				MainMenuBar.this.saveRecording.setEnabled(false);
				MainMenuBar.this.playRecording.setEnabled(false);
				MainMenuBar.this.addTrigger.setEnabled(false);
				MainMenuBar.this.addHotspot.setEnabled(false);
				MainMenuBar.this.resetRecording.setEnabled(false);
				MainMenuBar.this.savePath.setEnabled(false);
			}
		});
		menuMode.add(this.radioModePathGrid);

		// create radio button "Trigger"
		this.radioModeTrigger = new JRadioButtonMenuItem();
		this.radioModeTrigger.setText("Trigger");
		this.radioModeTrigger.addItemListener(new java.awt.event.ItemListener()
		{
			public void itemStateChanged(java.awt.event.ItemEvent e)
			{
				// enable trigger mode
				WorldEditor.setMode(Mode.TRIGGER);

				MainMenuBar.this.addTrigger.setEnabled(true);
				MainMenuBar.this.loadRecording.setEnabled(false);
				MainMenuBar.this.saveRecording.setEnabled(false);
				MainMenuBar.this.playRecording.setEnabled(false);
				MainMenuBar.this.addHotspot.setEnabled(false);
				MainMenuBar.this.resetRecording.setEnabled(false);
				MainMenuBar.this.savePath.setEnabled(false);
			}
		});
		menuMode.add(this.radioModeTrigger);

		// create radio button "Recorder"
		this.radioModeRecorder = new JRadioButtonMenuItem();
		this.radioModeRecorder.setText("Recorder (Keys: R = start/stop, K = camera mode)");
		this.radioModeRecorder.addItemListener(new java.awt.event.ItemListener()
		{
			public void itemStateChanged(java.awt.event.ItemEvent e)
			{
				// enable recorder mode
				WorldEditor.setMode(Mode.RECORDER);
				MainMenuBar.this.loadRecording.setEnabled(true);
				MainMenuBar.this.saveRecording.setEnabled(true);
				MainMenuBar.this.playRecording.setEnabled(true);
				MainMenuBar.this.resetRecording.setEnabled(true);
				MainMenuBar.this.addTrigger.setEnabled(false);
				MainMenuBar.this.addHotspot.setEnabled(false);
				MainMenuBar.this.savePath.setEnabled(false);
			}
		});
		menuMode.add(this.radioModeRecorder);

		// create radio button "Recorder"
		this.radioModePathCreation = new JRadioButtonMenuItem();
		this.radioModePathCreation.setText("Path creation (left mouse = add point, right mouse = remove last point)");
		this.radioModePathCreation.addItemListener(new java.awt.event.ItemListener()
		{
			public void itemStateChanged(java.awt.event.ItemEvent e)
			{
				// enable path creation mode
				WorldEditor.setMode(Mode.PATH_CREATOR);
				MainMenuBar.this.savePath.setEnabled(true);
				MainMenuBar.this.loadRecording.setEnabled(false);
				MainMenuBar.this.saveRecording.setEnabled(false);
				MainMenuBar.this.playRecording.setEnabled(false);
				MainMenuBar.this.resetRecording.setEnabled(false);
				MainMenuBar.this.addTrigger.setEnabled(false);
				MainMenuBar.this.addHotspot.setEnabled(false);
			}
		});
		menuMode.add(this.radioModePathCreation);

		// assign the radio buttons to a button group so that
		// only one radio button can be checked at a time.
		ButtonGroup radioGroup = new ButtonGroup();
		radioGroup.add(this.radioModeConstruction);
		radioGroup.add(this.radioModePathGrid);
		radioGroup.add(this.radioModeTrigger);
		radioGroup.add(this.radioModeRecorder);
		radioGroup.add(this.radioModePathCreation);

		this.add(menuMode);
	}
}
