package walsaip.vte.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.media.opengl.GL;
import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.SoftBevelBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import edu.uprm.walsaip.vte.core.camera.Camera;
import edu.uprm.walsaip.vte.core.loader.VTEFileLoader;
import edu.uprm.walsaip.vte.core.messagebus.Message;
import edu.uprm.walsaip.vte.core.messagebus.MessageBus;
import edu.uprm.walsaip.vte.core.model.TerrainModel;
import edu.uprm.walsaip.vte.core.renderer.Renderer;
import edu.uprm.walsaip.vte.core.views.View;

/**
 * 
 * @author Martha Roldan
 */
public class GUI extends JFrame {

	private static final long serialVersionUID = 3403379845432499718L;
	private JPanel desktopPane;
	private JMenuItem openMenuItem;
	private JMenuItem closeMenuItem;
	
	private static JTextField statusText;

//	private JProgressBar statusProgressBar;

	public GUI(String args[]) {

		// try {
		// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		// } catch (Exception e) {}
		initComponents();
		setVisible(true);
	}

	/**
	 * 
	 */
	private void initComponents() {

		// initialize fields
		JPanel MainPanel = new JPanel();
		JPanel InfoPanel = new JPanel();
		JLabel coordinatesL = new JLabel();
		JTextField coordinatesText = new JTextField();
//		JLabel scaleL = new JLabel();
//		JTextField scaleText = new JTextField();
//		JLabel statusL = new JLabel();
		statusText = new JTextField();
//		statusProgressBar = new JProgressBar();
		desktopPane = new JPanel();
		JPanel browsePanel = new JPanel();
		JPanel sidePanel = new JPanel();
		JPanel eastPanel = new JPanel();
		JSeparator EastSeparator = new JSeparator();
		JLabel BrowseLabel = new JLabel();
		JComboBox BrowseBox = new JComboBox();
		JScrollPane ScrollPane = new JScrollPane();
		JList FileList = new JList();
		JPanel controlsPanel = new JPanel();
		JButton moveLeftButton = new JButton();
		JButton zoomOutButton = new JButton();
		JButton zoomInButton = new JButton();
		JButton moveRightButton = new JButton();
		JSlider tiltSlider = new JSlider(0,90);
		JButton moveDownButton = new JButton();
		JButton rotateLeftButton = new JButton();
		JButton rotateRightButton = new JButton();
		JButton moveUpButton = new JButton();
		JMenuBar MainMenuBar = new JMenuBar();
		JMenu fileMenu = new JMenu();
		openMenuItem = new JMenuItem();
		closeMenuItem = new JMenuItem();
		JSeparator fileSeparator = new JSeparator();
		JMenuItem exitMenuItem = new JMenuItem();
		JMenu renderingMenu = new JMenu();
		JMenu mode_m = new JMenu();
		JRadioButtonMenuItem solidItem = new JRadioButtonMenuItem();
		JRadioButtonMenuItem wireframeItem = new JRadioButtonMenuItem();
		JRadioButtonMenuItem pointsItem = new JRadioButtonMenuItem();
		JSeparator renderingSeparator = new JSeparator();
		JMenu color_m = new JMenu();
		JRadioButtonMenuItem onItem = new JRadioButtonMenuItem();
		JRadioButtonMenuItem offItem = new JRadioButtonMenuItem();

		
		// Start of GUI
		addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				exitActionPerformed();
			}
			
		});
		setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
		setTitle("WALSAIP - Visual Terrain Explorer");

		MainPanel.setLayout(new BorderLayout());

		MainPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, new Color(
				204, 204, 204), new Color(204, 204, 204), new Color(153, 153,
				153), new Color(153, 153, 153)));


		// BOTTOM STATUS PANEL

		InfoPanel.setLayout(new AbsoluteLayout());
		InfoPanel.setBorder(new SoftBevelBorder(BevelBorder.LOWERED, new Color(
				204, 204, 204), new Color(204, 204, 204), new Color(153, 153,
				153), new Color(153, 153, 153)));

		coordinatesL.setText("Coordinates:");
		//InfoPanel.add(coordinatesL, new AbsoluteConstraints(10, 5, -1, 10));

		coordinatesText.setText("18.15 N, 66.30 W");
		coordinatesText.setBorder(null);
		//InfoPanel.add(coordinatesText, new AbsoluteConstraints(100, 5, 100, 10));

//		scaleL.setText("Scale:");
//		InfoPanel.add(scaleL, new AbsoluteConstraints(200, 5, -1, 10));

//		scaleText.setText("100.0");
//		scaleText.setBorder(null);
//
//		scaleText.addActionListener(new ActionListener() {
//			public void actionPerformed(ActionEvent evt) {
//				//scaleTFActionPerformed(evt);
//			}
//		});
//
//		InfoPanel.add(scaleText, new AbsoluteConstraints(240, 5, -1, 10));

//		statusL.setText("Status:");
		//InfoPanel.add(statusL, new AbsoluteConstraints(400, 5, -1, 10));

		statusText.setBorder(null);
		statusText.setText("Done");
		statusText.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent evt) {
				statusTextActionPerformed(evt);
			}
		});
		/*
		 * statusThread.text.setEditable(false); //
		 * statusText.setBounds(2,2,100,20); statusThread.text.setText("Messages
		 * Here!"); statusThread.text.addActionListener(new ActionListener() {
		 * public void actionPerformed(ActionEvent evt) {
		 * statusTextActionPerformed(evt); } });
		 */
		//InfoPanel.add(statusText, new AbsoluteConstraints(450, 5, -1, 10));
		//InfoPanel.add(statusProgressBar, new AbsoluteConstraints(690, 2, 230,16));

		MainPanel.add(InfoPanel, BorderLayout.SOUTH);
		desktopPane.setBackground(new Color(0, 102, 153));
		desktopPane.setLayout(new BorderLayout());
		desktopPane.setVisible(true);
		
		
		
		ViewPanel terrainViewPanel = new ViewPanel();
		
		terrainViewPanel.setSize(desktopPane.getSize());
		desktopPane.add(terrainViewPanel,BorderLayout.CENTER);
		
		
		MainPanel.add(desktopPane, BorderLayout.CENTER);

		// EAST and SIDE PANEL

		eastPanel.setLayout(new AbsoluteLayout());

		eastPanel.setPreferredSize(new Dimension(220, 550));
		eastPanel.setLayout(new BorderLayout());

		EastSeparator.setBackground(new Color(153, 153, 153));
		EastSeparator.setOrientation(SwingConstants.VERTICAL);
		eastPanel.add(EastSeparator, BorderLayout.WEST);

		// sidePanel.setLayout(new AbsoluteLayout());

		sidePanel.setPreferredSize(new Dimension(220, 550));
		sidePanel.setLayout(new BorderLayout());

		// BROWSE PANEL - List of Items on map

		browsePanel.setLayout(new AbsoluteLayout());

		browsePanel.setPreferredSize(new Dimension(220, 350));

		BrowseLabel.setText("Browse:");
		browsePanel.add(BrowseLabel, new AbsoluteConstraints(10, 10, -1, -1));

		BrowseBox.setMaximumRowCount(16);

		// TODO - Lists have to be dynamic

		BrowseBox.setModel(new DefaultComboBoxModel(new String[] { "List 1",
				"List 2", "List 3", "List 4" }));
		browsePanel.add(BrowseBox, new AbsoluteConstraints(10, 30, 190, -1));

		// TODO
		// remove Warning - they are ugly

		FileList.setModel(new AbstractListModel() {

			private static final long serialVersionUID = -6536612299237371367L;

			String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4",
					"Item 5" };

			public int getSize() {
				return strings.length;
			}

			public Object getElementAt(int i) {
				return strings[i];
			}
		});
		FileList.setSelectionBackground(new Color(0, 102, 204));
		ScrollPane.setViewportView(FileList);

		browsePanel.add(ScrollPane, new AbsoluteConstraints(10, 60, 190, 240));

		//sidePanel.add(browsePanel, BorderLayout.NORTH);

		// CONTROLS PANEL

		controlsPanel.setLayout(new AbsoluteLayout());

		controlsPanel.setMinimumSize(new Dimension(220, 240));
		controlsPanel.setPreferredSize(new Dimension(220, 240));

		zoomOutButton.setIcon(new ImageIcon("images/zoomOut.png"));
		zoomOutButton.setContentAreaFilled(false);
		zoomOutButton.setBorderPainted(false);
		zoomOutButton.setFocusPainted(false);
		zoomOutButton.addMouseListener(new ViewControlHandler<Float>(Camera.ID,Camera.MOVE_BACKWARD,Camera.MOVE_BACKWARD,null,0.0f));
		zoomOutButton.setToolTipText("Zoom Out");
		controlsPanel.add(zoomOutButton, new AbsoluteConstraints(115, 170, 50,-1));

		zoomInButton.setIcon(new ImageIcon("images/zoomIn.png"));
		zoomInButton.setContentAreaFilled(false);
		zoomInButton.setBorderPainted(false);
		zoomInButton.setFocusPainted(false);
		zoomInButton.addMouseListener(new ViewControlHandler<Float>(Camera.ID,Camera.MOVE_FORWARD,Camera.MOVE_FORWARD,null,0.0f));
		zoomInButton.setToolTipText("Zoom In");
		controlsPanel.add(zoomInButton, new AbsoluteConstraints(165, 170, 50,-1));

		rotateLeftButton.setIcon(new ImageIcon("images/rotateLeft.png"));
		rotateLeftButton.setContentAreaFilled(false);
		rotateLeftButton.setBorderPainted(false);
		rotateLeftButton.setFocusPainted(false);
		rotateLeftButton.addMouseListener(new ViewControlHandler<Float>(TerrainModel.ID,TerrainModel.ROTATE_Y_PLUS,TerrainModel.ROTATE_Y_PLUS,null,0.0f));
		rotateLeftButton.setToolTipText("Rotate Left");
		controlsPanel.add(rotateLeftButton, new AbsoluteConstraints(10, 170,50, -1));

		rotateRightButton.setIcon(new ImageIcon("images/rotateRight.png"));
		rotateRightButton.setContentAreaFilled(false);
		rotateRightButton.setBorderPainted(false);
		rotateRightButton.setFocusPainted(false);
		rotateRightButton.addMouseListener(new ViewControlHandler<Float>(TerrainModel.ID,TerrainModel.ROTATE_Y_MINUS,TerrainModel.ROTATE_Y_MINUS,null,0.0f));
		rotateRightButton.setToolTipText("Rotate Right");
		controlsPanel.add(rotateRightButton, new AbsoluteConstraints(60, 170,50, -1));

		moveRightButton.setIcon(new ImageIcon("images/moveRight.png"));
		moveRightButton.setContentAreaFilled(false);
		moveRightButton.setBorderPainted(false);
		moveRightButton.setFocusPainted(false);
		moveRightButton.addMouseListener(new ViewControlHandler<Float>(Camera.ID,Camera.MOVE_RIGHT,Camera.MOVE_RIGHT,null,0.0f));
		moveRightButton.setToolTipText("Move Right");
		controlsPanel.add(moveRightButton, new AbsoluteConstraints(106, 58, 48,	48));

		moveLeftButton.setIcon(new ImageIcon("images/moveLeft.png"));
		moveLeftButton.setContentAreaFilled(false);
		moveLeftButton.setBorderPainted(false);
		moveLeftButton.setFocusPainted(false);
		moveLeftButton.addMouseListener(new ViewControlHandler<Float>(Camera.ID,Camera.MOVE_LEFT,Camera.MOVE_LEFT,null,0.0f));
		moveLeftButton.setToolTipText("Move Left");
		controlsPanel.add(moveLeftButton, new AbsoluteConstraints(10, 58, 48,48));

		moveDownButton.setIcon(new ImageIcon("images/moveDown.png"));
		moveDownButton.setContentAreaFilled(false);
		moveDownButton.setBorderPainted(false);
		moveDownButton.setFocusPainted(false);
		moveDownButton.addMouseListener(new ViewControlHandler<Float>(Camera.ID,Camera.MOVE_DOWN,Camera.MOVE_DOWN,null,0.0f));
		moveDownButton.setToolTipText("Move Down");
		controlsPanel.add(moveDownButton, new AbsoluteConstraints(58, 106, 48,48));

		moveUpButton.setIcon(new ImageIcon("images/moveUp.png"));
		moveUpButton.setBorderPainted(false);
		moveUpButton.setContentAreaFilled(false);
		moveUpButton.setFocusPainted(false);
		moveUpButton.addMouseListener(new ViewControlHandler<Float>(Camera.ID,Camera.MOVE_UP,Camera.MOVE_UP,null,0.0f));
		moveUpButton.setToolTipText("Move Up");
		controlsPanel.add(moveUpButton, new AbsoluteConstraints(58, 10, 48, 48));

		tiltSlider.setOrientation(JSlider.VERTICAL);
		tiltSlider.setMajorTickSpacing(30);
		tiltSlider.setMinorTickSpacing(5);
		tiltSlider.setPaintTicks(true);
		
		// tiltSlider.setPaintTrack(false);
		//tiltSlider.setInverted(true);
		//tiltSlider.setValue(-90);
		tiltSlider.setInverted(true);
		tiltSlider.setValue(90);
		tiltSlider.setToolTipText("Tilt");
		tiltSlider.addChangeListener(new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				MessageBus.sendMessage(new Message<Float>(TerrainModel.ID,TerrainModel.SET_PITCH,(float)((JSlider)e.getSource()).getValue()));

			}
		});
		controlsPanel.add(tiltSlider, new AbsoluteConstraints(170, 10, 30, 130));

		sidePanel.add(controlsPanel, BorderLayout.SOUTH);
		eastPanel.add(sidePanel, BorderLayout.EAST);
		MainPanel.add(eastPanel, BorderLayout.EAST);

		getContentPane().add(MainPanel);


		MainMenuBar.setBorder(new SoftBevelBorder(BevelBorder.LOWERED,
				new Color(204, 204, 204), new Color(204, 204, 204), new Color(
						153, 153, 153), new Color(153, 153, 153)));

		fileMenu.setBorder(null);

		fileMenu.setText("File");
		fileMenu.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fileMenuActionPerformed(e);
			}
		});

		openMenuItem.setText("Open Terrain");
		openMenuItem.setBorder(BorderFactory.createEtchedBorder());
		openMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				openActionPerformed();
			}
		});
		fileMenu.add(openMenuItem);
		closeMenuItem.setText("Close Terrain");
		closeMenuItem.setBorder(BorderFactory.createEtchedBorder());
		closeMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				closeActionPerformed();
				exitActionPerformed();
			}
		});
		closeMenuItem.setEnabled(false);
		fileMenu.add(closeMenuItem);

		fileMenu.add(fileSeparator);

		exitMenuItem.setText("Exit");
		exitMenuItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				exitActionPerformed();
			}
		});
		fileMenu.add(exitMenuItem);

		MainMenuBar.add(fileMenu);

		renderingMenu.setBorder(null);
		renderingMenu.setText("Rendering");

		mode_m.setText("Mode");
		mode_m.setOpaque(true);


		solidItem.setSelected(true);
		solidItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MessageBus.sendMessage(new Message<Integer>(Renderer.ID,Renderer.SET_POLYGON_TYPE,GL.GL_FILL));
			}
		});
		solidItem.setText("Solid");

		wireframeItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MessageBus.sendMessage(new Message<Integer>(Renderer.ID,Renderer.SET_POLYGON_TYPE,GL.GL_LINE));
			}
		});
		wireframeItem.setText("Wire Frame");

		pointsItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MessageBus.sendMessage(new Message<Integer>(Renderer.ID,Renderer.SET_POLYGON_TYPE,GL.GL_POINT));
			}
		});
		pointsItem.setText("Points");

		ButtonGroup group1 = new ButtonGroup();
		group1.add(solidItem);
		group1.add(wireframeItem);
		group1.add(pointsItem);
		mode_m.add(solidItem);
		mode_m.add(wireframeItem);
		mode_m.add(pointsItem);

		renderingMenu.add(mode_m);

		renderingMenu.add(renderingSeparator);

		color_m.setOpaque(true);
		
		color_m.setText("Color");

		onItem.setSelected(true);
		onItem.setText("On");
		onItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MessageBus.sendMessage(new Message<Boolean>(Renderer.ID,Renderer.SET_TEXTURE,true));
			}
		});
		offItem.setText("Off");
		offItem.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				MessageBus.sendMessage(new Message<Boolean>(Renderer.ID,Renderer.SET_TEXTURE,false));
			}
		});
		
//		JMenu m = new JMenu();
//		m.setText("Test");
//		JMenuItem l = new JMenuItem();
//		l.setText("LOAD");
//		l.addActionListener(new ActionListener() {
//			public void actionPerformed(ActionEvent e) {
//				MessageBus.sendMessage(new Message<Boolean>(TerrainModel.ID,TerrainModel.LOAD,true));
//			}
//		});
//		m.add(l);
		
		
		ButtonGroup group2 = new ButtonGroup();
		group2.add(onItem);
		group2.add(offItem);
		color_m.add(onItem);
		color_m.add(offItem);

		renderingMenu.add(color_m);
//		renderingMenu.add(m);
		MainMenuBar.add(renderingMenu);

		setJMenuBar(MainMenuBar);

		setSize(1024, 700);
		setResizable(false);

	}

	protected void closeActionPerformed() {
		
		MessageBus.sendMessage(new Message<String>(View.ID,View.DESTROY, null));
		openMenuItem.setEnabled(true);
		closeMenuItem.setEnabled(false);
	}

	private void openActionPerformed() {

		JFileChooser fileChooser = new JFileChooser();

		fileChooser.setFileFilter(VTEFileLoader.getFileFilter());
		fileChooser.setMultiSelectionEnabled(false);
		if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
			
			String filename = fileChooser.getSelectedFile().getAbsolutePath();
			
			MessageBus.sendMessage(new Message<String>(View.ID, View.NEW, filename));
			MessageBus.sendMessage(new Message<String>(View.ID, View.START, null));
			
			
			openMenuItem.setEnabled(false);
			closeMenuItem.setEnabled(true);
		}
	}



	private void exitActionPerformed() {

		MessageBus.sendMessage(new Message<String>(View.ID, View.STOP, null));
		System.exit(0);
	}


	protected void windowMenuActionPerformed(ActionEvent event) {}

	private void fileMenuActionPerformed(ActionEvent event) {}

	private void statusTextActionPerformed(ActionEvent evt) {}

	/**
	 * Class used to Display messages on the status Bar
	 * 
	 * @author Peter Bangdiwala
	 * @date 06-29-06
	 */
	public static class Display {// extends Thread{


		public static void NewMsg(String msg) {

			// statusThread.setText(msg);
			statusText.setText(msg);
		}

		public static void printf(String msg) {

			statusText.setText(msg);
			// statusThread.setText(msg);
		}

		public static void print(String msg) {

			String old = statusText.getText();
			statusText.setText(old + msg);
			// String old = statusThread.getText();
			// statusThread.setText(old + msg);
		}

		public static void println(String msg) {

			String old = statusText.getText();
			statusText.setText(old + msg + "\n");
			// String old = statusThread.getText();
			// statusThread.setText(old + msg + "\n");
		}
	}

	class ViewControlHandler<T>  implements MouseListener {

		
		final private Message<T> mousePressedEvent;
		final private Message<T> mouseReleasedEvent;
		final private Message<T> mouseClickedEvent;
		final private Message<T> mouseEnteredEvent;
		final private Message<T> mouseExitedEvent;
		

		public ViewControlHandler( final Message<T> mousePressedEvent, final Message<T> mouseReleasedEvent, final Message<T> mouseClickedEvent, final Message<T> mouseEnteredEvent, final Message<T> mouseExitedEvent) {
			super();
			this.mousePressedEvent = mousePressedEvent;
			this.mouseReleasedEvent = mouseReleasedEvent;
			this.mouseClickedEvent = mouseClickedEvent;
			this.mouseEnteredEvent = mouseEnteredEvent;
			this.mouseExitedEvent = mouseExitedEvent;
		}
		
		private ViewControlHandler (String channel, String pressedEventName, String clickedEventName,String enteredEventName, T value) {
			
			if (pressedEventName != null) {
				this.mousePressedEvent = new Message<T>(channel, pressedEventName, Message.MSG_START, value);
				this.mouseReleasedEvent = new Message<T>(channel, pressedEventName, Message.MSG_STOP, value);
			}
			else {
				this.mousePressedEvent = null;
				this.mouseReleasedEvent = null;
			}
			
			if (clickedEventName != null) {
				this.mouseClickedEvent = new Message<T>(channel, clickedEventName, Message.MSG_INSTANT, value);
			}
			else {
				this.mouseClickedEvent = null;
			}

			if (enteredEventName != null) {
				this.mouseEnteredEvent = new Message<T>(channel, enteredEventName, Message.MSG_START, value);
				this.mouseExitedEvent = new Message<T>(channel, enteredEventName, Message.MSG_STOP, value);
			}
			else {
				this.mouseEnteredEvent = null;
				this.mouseExitedEvent = null;
			}	
		}


		public void mousePressed(MouseEvent event) {
			if (mousePressedEvent != null)
				MessageBus.sendMessage(mousePressedEvent);
		}

		public void mouseReleased(MouseEvent event) {
			if (mouseReleasedEvent != null)
				MessageBus.sendMessage(mouseReleasedEvent);
		}

		public void mouseClicked(MouseEvent event) {
			if (mouseClickedEvent != null)
				MessageBus.sendMessage(mouseClickedEvent);
		}

		public void mouseEntered(MouseEvent event) {
			if (mouseEnteredEvent != null)
				MessageBus.sendMessage(mouseEnteredEvent);
		}

		public void mouseExited(MouseEvent event) {
			if (mouseExitedEvent != null)
				MessageBus.sendMessage(mouseExitedEvent);
		}

	}




}
