import javax.media.opengl.GLJPanel;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.text.BadLocationException;

import java.awt.*;
import java.awt.event.*;

/** 
 * CMCGui.java
 * 
 * A class for interacting and displaying the CMC project..
 * 
 * @author Matt Kracum
 * @version 3-11-2010
 * */
public class CMCgui{
	
	  //Initialize all motion capture objects.
	  private CMCMarkerTrackingEx mt = new CMCMarkerTrackingEx();
      private CMCAnimationPanel ap  = new CMCAnimationPanel(500);     
      
      //Initialize all swing objects.
      private JFrame f = new JFrame("Carleton Motion Capture"); //create Frame
      private JPanel pnlControls = new JPanel();
      private JPanel pnlButtons = new JPanel();
      private JPanel pnlCameraButtons = new JPanel();
      private JPanel pnlBlack1 = new JPanel();
      private JPanel pnlBlack2 = new JPanel();
      private JFileChooser fc;
      private GLJPanel[] pnlDisplays = ap.getCanvas();
      private GLJPanel pnlAnimation = pnlDisplays[0];
      private GLJPanel pnlVideo = pnlDisplays[1];
      private JTextArea log;
      private JSlider sldrSetFrame = new JSlider(JSlider.HORIZONTAL, 0, 0, 0);
      
      //Initialize buttons.
      private JButton btnFindMarkers = new JButton("Find Markers");
      private JButton btnStartAnimation = new JButton("Start Animation");
      private JButton btnPause = new JButton("Pause");
      private JButton btnPlay = new JButton("Play");
      private JButton btnStop = new JButton("Stop");
      private JButton btnRewind = new JButton("Rewind");
      private JButton btnCamera1 = new JButton("Camera 1");
      private JButton btnCamera2 = new JButton("Camera 2");
      private JButton btnCamera3 = new JButton("Camera 3");
  
      //Initialize menu.
      private JMenuBar mb = new JMenuBar();
      private JMenu mnuFile = new JMenu("File");
      private JMenuItem mnuItemQuit = new JMenuItem("Quit");
      private JMenuItem mnuItemOpenDirectory = new JMenuItem("Open Image Folder");
      private JMenuItem mnuItemOpenFile = new JMenuItem("Open Marker File");
      private JMenu mnuOptions = new JMenu("Options");
      private JMenu mnuSubMenuSelectSkin = new JMenu("Select Skin");
      private JCheckBoxMenuItem mnuItemCheckBoxDefault = new JCheckBoxMenuItem("Default");
      private JCheckBoxMenuItem mnuItemCheckBoxSimple = new JCheckBoxMenuItem("Simple");
      private JCheckBoxMenuItem mnuItemCheckBoxBender = new JCheckBoxMenuItem("Bender");
      private JMenu mnuHelp = new JMenu("Help");
      private JMenuItem mnuItemAbout = new JMenuItem("About");
      
      //Initialize other variables.
	  private double[][] coordinates;
	  private Color black = new Color(0,0,0);
	  private Timer playTimer = new Timer(33, new ListenPlayTimer());
	  private boolean settingSlider = true;
	  private boolean isPlaying = false;
	  private boolean fileLoaded = false;
	  int x = 0;
	  int y = 0;
      
	  
      /** 
       * INPUT: Null.
       * DEFINITION: Constructor for the GUI. Sets up the frame and adds all relevant swing objects.
       * OUTPUT: Null. 
       * */
      public CMCgui(){
    	  Container contentPane = f.getContentPane();
          
    	  // Set menu bar
          f.setJMenuBar(mb);
          
          // Allows the swing app to be closed
          f.addWindowListener(new ListenCloseWdw());
          
          // Build Menus
          mnuFile.add(mnuItemOpenDirectory);  // Create Open Directory line
          mnuFile.add(mnuItemOpenFile);  // Create Open File line
          mnuFile.add(mnuItemQuit);  // Create Quit line
          mnuItemCheckBoxDefault.setSelected(true);
          mnuSubMenuSelectSkin.add(mnuItemCheckBoxDefault);
          mnuSubMenuSelectSkin.add(mnuItemCheckBoxSimple);
          mnuSubMenuSelectSkin.add(mnuItemCheckBoxBender);
          mnuOptions.add(mnuSubMenuSelectSkin);
          mnuHelp.add(mnuItemAbout); // Create About line
          mb.add(mnuFile);        // Add Menu items to form
          mb.add(mnuOptions);
          mb.add(mnuHelp);
          
          //Set up log
          log = new JTextArea(5,20);
          log.setMargin(new Insets(5,5,5,5));
          log.setEditable(false);
          JScrollPane logScrollPane = new JScrollPane(log);
          log.append("Welcome to Carleton Motion Capture!\n");
          log.append("Please select the folder with video images or a previous marker file.\n");
          log.append("----------------------------------------------------\n");        
          
          // Add buttons
          pnlButtons.add(btnFindMarkers);
          pnlButtons.add(btnStartAnimation);
          pnlButtons.add(btnPause);
          pnlButtons.add(btnPlay);
          pnlButtons.add(btnStop);
          pnlButtons.add(btnRewind);
          pnlButtons.add(sldrSetFrame);
          pnlCameraButtons.add(btnCamera1);
          pnlCameraButtons.add(btnCamera2);
          pnlCameraButtons.add(btnCamera3);
          
          // Add listeners
          mnuItemOpenDirectory.addActionListener(new ListenMenuOpenDirectory());
          mnuItemOpenFile.addActionListener(new ListenMenuOpenFile());
          mnuItemQuit.addActionListener(new ListenMenuQuit());
          mnuItemCheckBoxDefault.addActionListener(new ListenSelectDefault());
          mnuItemCheckBoxSimple.addActionListener(new ListenSelectSimple());
          mnuItemCheckBoxBender.addActionListener(new ListenSelectBender());
          btnFindMarkers.addActionListener(new ListenBtnFindMarkers());
          btnStartAnimation.addActionListener(new ListenBtnStartAnimation());
          btnPause.addActionListener(new ListenBtnPause());
          btnPlay.addActionListener(new ListenBtnPlay());
          btnStop.addActionListener(new ListenBtnStop());
          btnRewind.addActionListener(new ListenBtnRewind());
          btnCamera1.addActionListener(new ListenBtnCamera1());
          btnCamera2.addActionListener(new ListenBtnCamera2());
          btnCamera3.addActionListener(new ListenBtnCamera3());
          mnuItemOpenDirectory.addKeyListener(new ListenKeyRotates());
          mnuItemOpenFile.addKeyListener(new ListenKeyRotates());
          mnuItemQuit.addKeyListener(new ListenKeyRotates());
          btnFindMarkers.addKeyListener(new ListenKeyRotates());
          btnStartAnimation.addKeyListener(new ListenKeyRotates());
          btnPause.addKeyListener(new ListenKeyRotates());
          btnPlay.addKeyListener(new ListenKeyRotates());
          btnStop.addKeyListener(new ListenKeyRotates());
          btnRewind.addKeyListener(new ListenKeyRotates());
          btnPause.addKeyListener(new ListenKeyRotates());
          btnCamera1.addKeyListener(new ListenKeyRotates());
          btnCamera2.addKeyListener(new ListenKeyRotates());
          btnCamera3.addKeyListener(new ListenKeyRotates());
          f.setFocusable(true);
          f.addKeyListener(new ListenKeyRotates());
          log.addKeyListener(new ListenKeyRotates());
          mb.addKeyListener(new ListenKeyRotates());
          pnlAnimation.setFocusable(true);
          pnlAnimation.addKeyListener(new ListenKeyRotates());
          contentPane.addKeyListener(new ListenKeyRotates());
          sldrSetFrame.addChangeListener(new ListenSldrSetFrame());
          pnlAnimation.setFocusable(true);
          pnlAnimation.addMouseMotionListener(new ListenMouseRotates());
          pnlAnimation.addMouseListener(new ListenMouseClick());
          
          // Set up availability
          btnFindMarkers.setEnabled(false);
          btnStartAnimation.setEnabled(false);
          btnPause.setVisible(false);
          btnPlay.setVisible(false);
          btnStop.setVisible(false);
          btnRewind.setVisible(false);
          sldrSetFrame.setVisible(false);
          btnCamera1.setEnabled(false);
          btnCamera2.setEnabled(false);
          btnCamera3.setEnabled(false);
          
          // Set up controls frame
          GridBagConstraints c = new GridBagConstraints();
          GridBagLayout gridbag = new GridBagLayout();

          pnlControls.setLayout(gridbag);
          c.weightx = 0.5;
      	  c.fill = GridBagConstraints.NONE;
      	  c.insets = new Insets(0,0,40,0);
      	  c.gridx = 0;
      	  c.gridy = 0;
      	  pnlControls.add(pnlButtons, c);
      	  
      	  c = new GridBagConstraints();
      	  c.weightx = 0.5;
    	  c.fill = GridBagConstraints.NONE;
    	  c.insets = new Insets(-40,0,0,0);
    	  c.gridx = 0;
    	  c.gridy = 1;
    	  pnlControls.add(sldrSetFrame, c);
    	  
          // Set up main frame
          pnlBlack1.setSize(576, 384);
          pnlBlack1.setBackground(black);
          pnlBlack2.setSize(576, 384);
          pnlBlack2.setBackground(black);
          gridbag = new GridBagLayout();

          contentPane.setLayout(gridbag);
          c.weightx = 0.5;
          c.ipadx = 576;
          c.ipady = 384;
      	  c.fill = GridBagConstraints.NONE;
      	  c.insets = new Insets(0,-10,40,-20);
      	  c.gridx = 0;
      	  c.gridy = 0;
      	  contentPane.add(pnlBlack1, c);
      	  
      	  c = new GridBagConstraints();
      	  c.weightx = 0.5;
      	  c.ipadx = 576;
      	  c.ipady = 384;
    	  c.fill = GridBagConstraints.NONE;
    	  c.insets = new Insets(0,-20,40,-10);
    	  c.gridx = 1;
    	  c.gridy = 0;
    	  contentPane.add(pnlBlack2, c);
    	  
    	  c = new GridBagConstraints();
      	  c.weightx = 0.5;
    	  c.fill = GridBagConstraints.NONE;
    	  c.insets = new Insets(-35,0,15,0);
    	  c.gridx = 1;
    	  c.gridy = 1;
    	  contentPane.add(pnlCameraButtons, c);
    	  
    	  c = new GridBagConstraints();
    	  c.weightx = 0.5;
    	  c.fill = GridBagConstraints.HORIZONTAL;
    	  c.insets = new Insets(-20,0,15,0);
    	  c.gridx = 0;
    	  c.gridy = 2;
    	  c.gridwidth = GridBagConstraints.REMAINDER;
    	  contentPane.add(pnlControls, c);
    	  
    	  c = new GridBagConstraints();
    	  c.weightx = 0.5;
      	  c.ipady = 100;
    	  c.fill = GridBagConstraints.HORIZONTAL;
    	  c.insets = new Insets(0,10,0,10);
    	  c.gridx = 0;
    	  c.gridy = 3;
    	  c.gridwidth = GridBagConstraints.REMAINDER;
    	  contentPane.add(logScrollPane, c);
      }
      
      //The following are a bunch of self-defined listener classes that were previously added to swing objects.
      public class ListenMenuOpenDirectory implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Open Directory MenuItem.
           * DEFINITION: Opens a JFileChooser, which allows the user to select a directory containing
           * a file system of images. If selected, it then allows the user to run marker tracking on those
           * files.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  fc = new JFileChooser(); 
        	  fc.setCurrentDirectory(null);
        	  fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        	  fc.setAcceptAllFileFilterUsed(false);
        	  if(fileLoaded){
        		  if(isPlaying){
        			  ap.pause();
        			  btnPlay.setVisible(true);
        			  btnPause.setVisible(false);
        			  btnPlay.requestFocusInWindow();
        		  }
        	  }
        	  if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { 
        		  log.append("Opening Image Folder:"+fc.getSelectedFile()+"\n");
        	      mt.setInFolder(fc.getSelectedFile().toString());
        	      ap.setInFolder(fc.getSelectedFile().toString());
        	      btnFindMarkers.setEnabled(true);
        	      btnFindMarkers.requestFocusInWindow();
        	      btnStartAnimation.setEnabled(false);
        	      btnStartAnimation.setVisible(true);
            	  btnFindMarkers.setVisible(true);
        	      btnPause.setVisible(false);
        	      btnPlay.setVisible(false);
        	      btnStop.setVisible(false);
            	  btnRewind.setVisible(false);
            	  sldrSetFrame.setVisible(false);
        	      }
        	  else {
        		  btnFindMarkers.requestFocusInWindow();
        	  }
          }
      }
      
      public class ListenMenuOpenFile implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Open File MenuItem.
           * DEFINITION: Opens a JFileChooser, which allows the user to select a marker file that was
           * already created. If selected, it then allows the user to run marker tracking on those files.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  fc = new JFileChooser(); 
        	  fc.setCurrentDirectory(null);
        	  fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        	  fc.setAcceptAllFileFilterUsed(false);
        	  if(fileLoaded){
        		  if(isPlaying){
        			  ap.pause();
        			  btnPlay.setVisible(true);
        			  btnPause.setVisible(false);
        			  btnPlay.requestFocusInWindow();
        		  }
        	  }
        	  if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) { 
        	      log.append("Opening Marker File:"+fc.getSelectedFile()+"\n");
        	      ap.loadFile(fc.getSelectedFile().toString());
        	      btnFindMarkers.setEnabled(false);
        	      btnFindMarkers.setVisible(true);
        	      btnStartAnimation.setEnabled(true);
        	      btnStartAnimation.setVisible(true);
        	      btnStartAnimation.requestFocusInWindow();
        	      btnPause.setVisible(false);
        	      btnPlay.setVisible(false);
        	      btnStop.setVisible(false);
            	  btnRewind.setVisible(false);
            	  sldrSetFrame.setVisible(false);
        	      }
        	  else {
        		  btnFindMarkers.requestFocusInWindow();
        	  	}
          }
      }
      
      public class ListenSelectDefault implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Select Default MenuItem.
           * DEFINITION: Changes the current skin to Default.
           * OUTPUT: Null. 
           * */
    	  public void actionPerformed(ActionEvent e){
              ap.setSkin(0);
              mnuItemCheckBoxDefault.setSelected(true);
              mnuItemCheckBoxSimple.setSelected(false);
              mnuItemCheckBoxBender.setSelected(false);
          }
      }
      public class ListenSelectSimple implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Select Simple MenuItem.
           * DEFINITION: Changes the current skin to Simple.
           * OUTPUT: Null. 
           * */
    	  public void actionPerformed(ActionEvent e){
    		  ap.setSkin(1);
    		  mnuItemCheckBoxSimple.setSelected(true);
    		  mnuItemCheckBoxDefault.setSelected(false);
    		  mnuItemCheckBoxBender.setSelected(false);
          }
      }
      public class ListenSelectBender implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Select Bender MenuItem.
           * DEFINITION: Changes the current skin to Default.
           * OUTPUT: Null. 
           * */
    	  public void actionPerformed(ActionEvent e){
    		  ap.setSkin(2);
    		  mnuItemCheckBoxBender.setSelected(true);
    		  mnuItemCheckBoxSimple.setSelected(false);
    		  mnuItemCheckBoxDefault.setSelected(false);
          }
      }
      public class ListenMenuQuit implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Quit MenuItem.
           * DEFINITION: Closes the frame and ends the program.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
              System.exit(0);
          }
      }
      
      public class ListenCloseWdw extends WindowAdapter{
    	  /** 
           * INPUT: Action event interacting with the close window button.
           * DEFINITION: Closes the frame and ends the program.
           * OUTPUT: Null. 
           * */
          public void windowClosing(WindowEvent e){
              System.exit(0);
          }
      }
      
      public class ListenPlayTimer implements ActionListener{
    	  /** 
           * INPUT: Action event triggered at 1/30 of a second by the timer, when timer is running.
           * DEFINITION: Changes the position of the slider to the curFrame, effectively incrementing.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  settingSlider = true;
        	  sldrSetFrame.setValue(ap.getFrame());
        	  settingSlider = false;
          }
      }
      
      public class ListenBtnFindMarkers implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Find Markers button.
           * DEFINITION: Runs getCoordinates on the currently selected directory.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
              coordinates = mt.getCoordinates();      
        	  btnStartAnimation.setEnabled(true);
        	  btnStartAnimation.requestFocusInWindow();
        	  btnFindMarkers.setEnabled(false);
        	  ap.loadDirect(coordinates);
          }
      }
      
      public class ListenBtnStartAnimation implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Start Animation button.
           * DEFINITION: Initializes the threads and adds the animation and video panels.
           * It will start playing the animation and video in sync, and allow for the user
           * to interact with the video.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.initializeThreads();
        	  if(!fileLoaded){
        		  GridBagConstraints c = new GridBagConstraints();
        	  
        		  Container contentPane = f.getContentPane();
        		  c.weightx = 0.5;
        		  c.ipadx = 576;
        		  c.ipady = 384;
        		  c.fill = GridBagConstraints.NONE;
        		  c.insets = new Insets(0,-10,40,-20);
        		  c.gridx = 0;
        		  c.gridy = 0;
        		  contentPane.add(pnlAnimation, c);
          	  
        		  c.weightx = 0.5;
        		  c.ipadx = 576;
        		  c.ipady = 384;
        		  c.fill = GridBagConstraints.NONE;
        		  c.insets = new Insets(0,-20,40,-10);
        		  c.gridx = 1;
        		  c.gridy = 0;
        		  contentPane.add(pnlVideo, c);
        	  }
        	  
        	  ap.playAnimation();
        	  ap.setCameraDisplay(1);
        	  isPlaying = true;
        	  fileLoaded = true;
        	  
        	  btnPause.setVisible(true);
        	  btnPause.requestFocusInWindow();
        	  btnStop.setVisible(true);
        	  btnRewind.setVisible(true);
        	  btnStartAnimation.setVisible(false);
        	  btnFindMarkers.setVisible(false);
        	  btnCamera1.setEnabled(true);
        	  btnCamera2.setEnabled(false);
        	  btnCamera3.setEnabled(true);
        	  
        	  sldrSetFrame.setMaximum(ap.getNumFrames()-1);
        	  sldrSetFrame.setMajorTickSpacing((int)(ap.getNumFrames()/10));
              sldrSetFrame.setPaintTicks(true);
        	  sldrSetFrame.setVisible(true);
        	  sldrSetFrame.setValue(0);
        	  playTimer.start();
          }
      }
      
      public class ListenBtnPause implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Pause button.
           * DEFINITION: Pauses the animation and video at the current frame.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.pause();
        	  isPlaying = false;
        	  playTimer.stop();
        	  btnPlay.setVisible(true);
        	  btnPlay.requestFocusInWindow();
        	  btnPause.setVisible(false); 
          }
      }
      
      public class ListenBtnPlay implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Play button.
           * DEFINITION: Resumes playing of the animation and video.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.pause();
        	  isPlaying = true;
        	  playTimer.start();
        	  btnPause.setVisible(true);
        	  btnPause.requestFocusInWindow();
        	  btnPlay.setVisible(false);
          }
      }
      
      public class ListenBtnStop implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Stop button.
           * DEFINITION: Stops the animation and resets to the first frame.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.resetAnimation();
        	  isPlaying = false;
        	  settingSlider = true;
        	  sldrSetFrame.setValue(0);
        	  settingSlider = false;
        	  playTimer.stop();
        	  btnPlay.setVisible(true);
        	  btnPlay.requestFocusInWindow();
        	  btnPause.setVisible(false);
          }
      }
      
      public class ListenBtnRewind implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Rewind button.
           * DEFINITION: Sets the animation and video to play in reverse until clicked again.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.rewindAnimation();
        	  btnPlay.setVisible(true);
        	  btnPlay.requestFocusInWindow();
        	  btnPause.setVisible(false);
        	  isPlaying = true;
          }
      }
      
      public class ListenBtnCamera1 implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Camera1 button.
           * DEFINITION: Sets the video to display images from camera1.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.setCameraDisplay(2);
        	  btnCamera1.setEnabled(false);
        	  btnCamera2.setEnabled(true);
              btnCamera3.setEnabled(true);
          }
      }
      
      public class ListenBtnCamera2 implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Camera2 button.
           * DEFINITION: Sets the video to display images from camera2.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.setCameraDisplay(1);
        	  btnCamera1.setEnabled(true);
        	  btnCamera2.setEnabled(false);
              btnCamera3.setEnabled(true);
          }
      }
      
      public class ListenBtnCamera3 implements ActionListener{
    	  /** 
           * INPUT: Action event interacting with the Camera3 button.
           * DEFINITION: Sets the video to display images from camera3.
           * OUTPUT: Null. 
           * */
          public void actionPerformed(ActionEvent e){
        	  ap.setCameraDisplay(0);
        	  btnCamera1.setEnabled(true);
        	  btnCamera2.setEnabled(true);
              btnCamera3.setEnabled(false);
          }
      }
      
      public class ListenSldrSetFrame implements ChangeListener{
    	  /** 
           * INPUT: Change event interacting with the Set Frame slider.
           * DEFINITION: A slider which allows the user to move the video around to any frame.
           * OUTPUT: Null. 
           * */
    	  public void stateChanged(ChangeEvent e){
    		  if(!settingSlider){
    			  if(isPlaying){
    				  ap.pause();
    			  }
    			  isPlaying = false;
    			  playTimer.stop();
    			  int frame = (int)sldrSetFrame.getValue();
    			  try{
    				  ap.setFrame(frame);}
    			  catch(BadLocationException ex){};
    			  btnPlay.setVisible(true);
    			  btnPause.setVisible(false);
    			  btnPlay.requestFocusInWindow();
    		  }
    	  }
      }
      
      public class ListenKeyRotates implements KeyListener{
    	  /** 
           * INPUT: Key event which listens to everything in the frame.
           * DEFINITION: Allows the user to rotate the animation.
           * OUTPUT: Null. 
           * */
    	  public void keyTyped(KeyEvent e) {
    		  char c = e.getKeyChar();
    		  if (c == 'x') {
    			  double[] rotate = {1,0,0};
    			  ap.setRotation(rotate);
    	      } else if (c == 'X') {
    	    	  double[] rotate = {-1,0,0};
    	    	  ap.setRotation(rotate);
    	      } else if (c == 'y') {
    	    	  double[] rotate = {0,1,0};
    	    	  ap.setRotation(rotate);
    	      } else if (c == 'Y') {
    	    	  double[] rotate = {0,-1,0};
    	    	  ap.setRotation(rotate);
    	      }	else if (c == 'z') {
    	    	  double[] rotate = {0,0,1};
    	    	  ap.setRotation(rotate);
    	      } else if (c == 'Z') {
    	    	  double[] rotate = {0,0,-1};
    	    	  ap.setRotation(rotate);
    	      } else if (c == 'h') {
    	    	  ap.resetRotation();
    	      }
    	  }
    	  public void keyReleased(KeyEvent e) {
    	  }
    	  public void keyPressed(KeyEvent e) {
    	  }
      }
      
      public class ListenMouseClick implements  MouseListener{
    	  /** 
           * INPUT: Mouse event which listens to the animation panel.
           * DEFINITION: Gets the initial click position.
           * OUTPUT: Null. 
           * */
    	  public void mousePressed(MouseEvent e){
    		  x = e.getX();
    		  y = e.getY();
    	  }
    	  public void mouseExited(MouseEvent e){
    	  }
    	  public void mouseReleased(MouseEvent e){
    	  }
    	  public void mouseClicked(MouseEvent e){
    		  
    	  }
    	  public void mouseEntered(MouseEvent e){
    	  }
      }
      public class ListenMouseRotates implements MouseMotionListener{
    	  /** 
           * INPUT: MouseMotion event which listens to the animation panel.
           * DEFINITION: Listens to dragging of the mouse so the user can rotate the frame.
           * OUTPUT: Null. 
           * */
    	  public void mouseDragged(MouseEvent e){
    		  int mouse_dx, mouse_dy;
    		  double[] rotate = {0,0,0}; 
    		  int mouse_x = e.getX();
    		  int mouse_y = e.getY();
    		  mouse_dx = -(mouse_x - x);
    		  mouse_dy = -(mouse_y - y);;

    		  x = mouse_x;
    		  y = mouse_y;

    		  if (Math.abs(mouse_dx) > Math.abs(mouse_dy)) { 
    			  rotate[2] = -mouse_dx*.5; 
    		  } 
    		  else {
    			  rotate[1] = -mouse_dy*.5;
    			  rotate[0] = mouse_dy*.5; 		  
    		  }
    		    ap.setRotation(rotate);
    	  }
    	  public void mouseMoved(MouseEvent e){
    	  } 
      }
      
      public void launchFrame(){
          // Display Frame
          f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          f.pack();
          f.setSize(1210,730);
          f.setResizable(false);
          f.setVisible(true);
      }
      
      public static void main(String args[]){
          CMCgui gui = new CMCgui();
          gui.launchFrame();
      }
  }
