/******************************************************************************
* Copyright 1996-2014 United States Government as represented by the
* Administrator of the National Aeronautics and Space Administration.
* All Rights Reserved.
******************************************************************************/

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import javax.swing.*;

/** The CDFValidate tool program which can be run either from the CDFTools 
    driver or as an application, will provide the version of the CDF 
    distribution being used and the default toolkit qualifiers.
 */ 

public class CDFValidate extends JFrame 
			 implements ActionListener, ItemListener, 
                                    MouseListener, FocusListener, Runnable {

    static final long serialVersionUID = 1L;
    static int macLib = 0;
    static String cdfbase = null;
    static String libcdfPath = null;

    JFrame parentFrame;
/** dialog for user interface. */
    JDialog dialog;
/** The FileChooser for the file selection. */
    JFileChooser fileChooser = new JFileChooser();
    JPanel panelx = new JPanel(new BorderLayout(), true);

/** The panel for selectable buttons which goes to dialog's north portion. */
    JPanel panel1 = new JPanel(new GridBagLayout(), true);
/** The panel containing all checkboxes goes to dialog's center portion. */
    JPanel panel2 = new JPanel(new GridBagLayout(), true);
/** The panel for run/help/quit buttons. */
    JPanel panel31 = new JPanel(new GridLayout(1, 3, 50, 20), true);
/** The panel containing panel31 goes to dialog's south portion. */
    JPanel panel3 = new JPanel(new BorderLayout(), true);
/** The panel for text area which goes to dialog's south portion. */
//    JPanel panel4 = new JPanel(new BorderLayout(), true);

/** A group radio buttons for DISPLAY */
    ButtonGroup display = new ButtonGroup();
/** A group radio buttons for zMode. */
    JRadioButton debug = new JRadioButton("Debug");
    JRadioButton quiet = new JRadioButton("Quiet");
/** A radio button panel for display. */
//    JPanel DISPLAY = new JPanel(new BorderLayout(), true);
    JLabel DISPLAY = new JLabel("Display: ");

/** "Debug" checkbox. */
    JCheckBox dbc = new JCheckBox("Debug",false);
/** "Validate" checkbox. */
    JCheckBox vdc = new JCheckBox("Validate");
/** "About" checkbox. */
    JCheckBox abc = new JCheckBox("About");

/** "Run CDFValidate" button. */
    JButton entrb = new JButton(" Enter ");
/** "Help" button. */
    JButton helpb = new JButton(" Help ");
/** "Quit" button. */
    JButton quitb = new JButton(" Quit ");

/** "Select" button for selecting the CDF file. */
    JButton slt = new JButton("Select");

/** Text area for information. */
    JTextArea info = new JTextArea(20,60);

/** Text field for entering the mandatory CDF file name. */
    JTextField cdf = new JTextField("", 40);

/** A label of "CDF:" for the text field cdf (CDF). */
    JLabel CDF = new JLabel("CDF: ");

/** Scroll pane for the text area. */
    JScrollPane scroller;

/** Hold valid extensions for the CDF files for the file chooser. */
    String[] cdfs = {"cdf", "CDF"};
/** A file filter for the file chooser. */
    SimpleFileFilter filter = new SimpleFileFilter(cdfs,
                                                " CDF files (*.cdf, *.CDF)");
/** command string. */
    String command = "cdfvalidate ";
    String commandX;
    String[] cmds = new String[3];
/** Environment variable for the current directory. */
    String currentdir = System.getProperty("user.dir");
    String strdb = " ";
    String strvd = " ";
    String cdfspec = " ";
    String cdfDelimiter = "";

/** The file separator. */
    String separator = System.getProperty("file.separator");
/** A platform-dependent Runtime object. */
    Runtime runtime = Runtime.getRuntime();
/** A separate process to run the command. */ 
    Process process = null;
    int hlp = 0;
    int abx = 0;

/** The text field is currently getting the focus. */
    JTextField focused = null;
/** The text field previously was focused. */
    JTextField prevfocused = null;

/** Menu bar. */
    JMenuBar menuBar = new JMenuBar();
/** A menu: File. */
    JMenu menuFile = new JMenu("File");
/** A menu: Help. */
    JMenu menuHelp = new JMenu("Help");
/** A File menu item: Exit. */
    JMenuItem menuFileExit = new JMenuItem("Exit");
/** A Help menu item: Help. */
    JMenuItem menuHelpHelp = new JMenuItem("Help");
    int istart = -1;
    int iend = -1;

    Dimension hpad5 = new Dimension(5,1);
    Dimension hpad10 = new Dimension(10,1);
    Dimension hpad20 = new Dimension(20,1);
    Dimension hpad25 = new Dimension(25,1);
    Dimension hpad30 = new Dimension(30,1);
    Dimension hpad40 = new Dimension(40,1);
    Dimension hpad50 = new Dimension(50,1);
    Dimension vpad5 = new Dimension(1,5);
    Dimension vpad10 = new Dimension(1,10);
    Dimension vpad20 = new Dimension(1,20);
    Dimension vpad25 = new Dimension(1,25);
    Dimension vpad30 = new Dimension(1,30);
    Dimension vpad40 = new Dimension(1,40);
    Dimension vpad50 = new Dimension(1,50);

    Font  defaultFont = new Font("Dialog", Font.PLAIN, 12);
    Font  boldFont = new Font("Dialog", Font.BOLD, 12);
    Font  bigFont = new Font("Dialog", Font.PLAIN, 18);
    Font  bigboldFont = new Font("Dialog", Font.BOLD, 18);
    static Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    static int INITIAL_WIDTH = 650;
    static int INITIAL_HEIGHT = 450;

/** The default dialog modal (is set to false). */
    static boolean defaultModal = false;
/** The current dialog modal. */
    boolean modal;
    int frommain = 0;

    CDFValidate() {
	this(null, null, defaultModal);
    }

    CDFValidate(JFrame parentFrame) {
        this(parentFrame, null, defaultModal);
    }

    CDFValidate(JFrame parentFrame, String cdfbase) {
        this(parentFrame, cdfbase, defaultModal);
    }

    CDFValidate(JFrame parentFrame, String cdfbase, boolean modal) {
        if (cdfbase == null) {
          cdfbase = System.getProperty("CDF_BASE");
          if (cdfbase == null)
            cdfbase = CDFToolsUtil.getenv("CDF_BASE");
        }
        if (cdfbase != null)
          command = cdfbase + separator + "bin" + separator + "cdfvalidate ";
        else
          command = "cdfvalidate ";

        dialog = new JDialog(this, modal);
	this.parentFrame = parentFrame;
        this.modal = modal;
    }

/** Set up the GUI stuff for user selection.
 */

    private void buildGUI() {

        WindowListener l = new WindowAdapter() {
           public void windowClosing(WindowEvent e) {
              if (frommain == 0) {
                if (modal) dialog.dispose();
                else dialog.setVisible(false);
		if (parentFrame != null) parentFrame.setVisible(true);
              } else {
		if (macLib == 1) new File(libcdfPath).delete();
		System.exit(1);
	      }
	   }
        };
        dialog.addWindowListener(l);
        dialog.setTitle("Enter   Parameters/qualifiers  for  CDFvalidate");
        dialog.setSize(INITIAL_WIDTH, INITIAL_HEIGHT);
        dialog.setLocation(screenSize.width/2 - INITIAL_WIDTH/2,
                          screenSize.height/2 - INITIAL_HEIGHT/2);
        dialog.getContentPane().setLayout(new BorderLayout());

        // set the menu bar
        dialog.setJMenuBar(menuBar);

        // add the file menu
        menuBar.add(menuFile);

        // add the menu items to file
        menuFile.add(menuFileExit);
        menuFileExit.addActionListener(this);

        // add the help menu
        menuBar.add(menuHelp);

        // add the menu items to help
        menuHelp.add(menuHelpHelp);
        menuHelpHelp.addActionListener(this);

        // Panel 1
	makeJButton(panel1, Box.createRigidArea(vpad10), 0, 0, 1, 1, 1.0, 1.0);
        makeJButton(panel1, CDF, 0, 1, 1, 1, 1.0, 1.0);
        makeJButton(panel1, cdf, 1, 1, 1, 1, 1.0, 1.0);
        makeJButton(panel1, slt, 2, 1, 1, 1, 1.0, 1.0);
        makeJButton(panel1, Box.createRigidArea(vpad20), 0, 3, 1, 1, 1.0, 1.0);
        cdf.addActionListener(this);
        cdf.addFocusListener(this);
        cdf.addMouseListener(this); 
        cdf.setToolTipText("Enter the CDF (without extension) to be validated");
        slt.addActionListener(this);
        slt.setToolTipText("Use the file chooser to select the CDF");
        CDF.setFont(boldFont);
        cdf.setFont(boldFont);
//        dialog.getContentPane().add(panel1,BorderLayout.NORTH);
        panelx.add(panel1,BorderLayout.NORTH);

        // Initialize the zMode choice.

        DisplayListener displayListener = new DisplayListener();
        debug.setActionCommand("1");
        quiet.setActionCommand("2");
        debug.addActionListener(displayListener);
        quiet.addActionListener(displayListener);
        display.add(debug);
        display.add(quiet);
	quiet.setSelected(true);
        debug.setToolTipText("Displays the detailed validating processe");
        quiet.setToolTipText("Shows nothing for a successful validation");

        JPanel displayPanel = new JPanel(true);
        JPanel tpanel1 = new JPanel(new BorderLayout(), true);
        displayPanel.setLayout(new FlowLayout());
        displayPanel.add(debug);
        displayPanel.add(quiet);

        tpanel1.add(DISPLAY,BorderLayout.WEST);
        tpanel1.add(displayPanel, BorderLayout.CENTER);
        tpanel1.add(Box.createRigidArea(hpad20), BorderLayout.EAST);

	// Panel 2
	makeJButton(panel2, Box.createRigidArea(hpad50), 0, 1, 1, 1, 1.0, 1.0);
	makeJButton(panel2, vdc, 1, 1, 1, 1, 1.0, 1.0);
	makeJButton(panel2, Box.createRigidArea(hpad50), 2, 1, 1, 1, 1.0, 1.0);
	makeJButton(panel2, tpanel1, 3, 1, 1, 1, 1.0, 1.0);
	makeJButton(panel2, Box.createRigidArea(hpad50), 4, 1, 1, 1, 1.0, 1.0);
        makeJButton(panel2, abc, 5, 1, 1, 1, 1.0, 1.0);
	makeJButton(panel2, Box.createRigidArea(vpad20), 0, 2, 1, 1, 1.0, 1.0);

	vdc.addItemListener(this);
        vdc.setToolTipText("Validate the file");
        vdc.setSelected(true);
	dbc.addItemListener(this);
        dbc.setToolTipText("Dispay the error message when validating fails");
        abc.addItemListener(this);
        abc.setToolTipText("Display the current version");
//	dialog.getContentPane().add(panel2,BorderLayout.CENTER);
	panelx.add(panel2,BorderLayout.CENTER);
	

        // Panel 3
        panel31.add(entrb);
        panel31.add(helpb);
        panel31.add(quitb);
        panel3.add(panel31, BorderLayout.NORTH);
        panel3.add(Box.createRigidArea(vpad20),BorderLayout.CENTER);

        // Listen for events on buttons
        entrb.addActionListener(this);
        entrb.setToolTipText("Run CDFValidate");
        helpb.addActionListener(this);
        helpb.setToolTipText("Get the complete help information");
        quitb.addActionListener(this);
        quitb.setToolTipText("Exit CDFValidate");

	// Text Area
	info.setEditable(false);
        scroller = new JScrollPane() {
                static final long serialVersionUID = 1L;

                public Dimension getPreferredSize() {
                   return new Dimension(200, 260);
                }
                public float getAlignmentX() {
                   return LEFT_ALIGNMENT;
                }
        };

	scroller.getViewport().add(info);
//        panel3.add(scroller, BorderLayout.SOUTH);
        info.setVisible(true);
//        dialog.getContentPane().add(panel3, BorderLayout.SOUTH);
        panelx.add(panel3, BorderLayout.SOUTH);

        dialog.getContentPane().add(panelx, BorderLayout.NORTH);
        dialog.getContentPane().add(scroller, BorderLayout.CENTER);

    }

/** Implement the run method for Runabout interface.
 */ 

    public void run() {
	buildGUI();
	dialog.pack();
	fileChooser.setCurrentDirectory(new File(currentdir));
	dialog.setVisible(true);
	if (parentFrame != null) parentFrame.setVisible(false);

    }

/** Reenter from the main toolkit driver. Reset the dialog to visible. 
 */ 

    public void reEnter() {
	dialog.setVisible(true);
	if (parentFrame != null) parentFrame.setVisible(false);
	info.setText("");
	cdf.setText("");
    }


/** Action for buttons or menu items selection
 */

    public void actionPerformed(ActionEvent evt) {
	Object obj = evt.getSource();
        if (obj == quitb || obj == menuFileExit) { // for "Quit" button
              if (frommain == 0) { 
                if (modal) dialog.dispose();
                else dialog.setVisible(false);
		if (parentFrame != null) parentFrame.setVisible(true);
              } else {
		if (macLib == 1) new File(libcdfPath).delete();
		System.exit(1);
	      }
        } else if (obj == slt) { // for "Select" button
                doFileChooser("Select/enter the CDF", cdf, 1, filter);
	} else if (obj == entrb) { // for "Enter" button
                cdfspec = cdf.getText();
                if (cdfspec.equals("") || cdfspec.trim().equals("")) {
                  info.setText("");
                  info.append("Please enter a CDF file...");
                  Toolkit.getDefaultToolkit().beep();
                  return;
                } else
                  cdfspec = cdfspec.trim();

                if (cdfspec.startsWith("'")) cdfDelimiter = " ";
                else if (cdfspec.startsWith("\"")) cdfDelimiter = " ";
                else cdfDelimiter = "\"";
               
                if (!vdc.isSelected())
                  strvd = "-novalidate";
                else
                  strvd = " ";
                
                if (!debug.isSelected() && !quiet.isSelected())
                  strdb = "";
                else if (debug.isSelected())
                  strdb = "-debug ";
                else if (quiet.isSelected())
                  strdb = "-quiet ";
                else 
                  strdb = "";

                commandX = command + strvd + " " + strdb + " " + 
                           cdfDelimiter + cdfspec + cdfDelimiter;

                String OS = System.getProperty("os.name").toLowerCase();
                if (OS.indexOf("windows") != -1) {
                    cmds[0] = commandX;
                } else if (OS.indexOf("vms") != -1) {
                    cmds[0] = commandX;
                } else {
                    cmds[0] = "/bin/sh";
                    cmds[1] = "-c";
                    cmds[2] = commandX;
                }
                runit(cmds);
                // runit(commandX);
	} else { // for "Help" button
		hlp = 1;
                commandX = command + "-java"; 
                String OS = System.getProperty("os.name").toLowerCase();
                if (OS.indexOf("windows") != -1) {
                    cmds[0] = commandX;
                } else if (OS.indexOf("vms") != -1) {
                    cmds[0] = commandX;
                } else {
                    cmds[0] = "/bin/sh";
                    cmds[1] = "-c";
                    cmds[2] = commandX;
                }
                runit(cmds);
                // runit(commandX);
	}
    }

/** Action for radio buttons for zMode
 */

    class DisplayListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
           String cmd = e.getActionCommand();
        }
    }

/** Action for checkboxes selection
 */
    public void itemStateChanged(ItemEvent evt) {
	Object obj = evt.getSource();
	if (obj == abc) { // "About" checkbox
	  if (abc.isSelected()) {
		abx = 1;
		commandX = command + " -about";
                String OS = System.getProperty("os.name").toLowerCase();
                if (OS.indexOf("windows") != -1) {
                    cmds[0] = commandX;
                } else if (OS.indexOf("vms") != -1) {
                    cmds[0] = commandX;
                } else {
                    cmds[0] = "/bin/sh";
                    cmds[1] = "-c";
                    cmds[2] = commandX;
                }
                runit(cmds);
                // runit(commandX);
                abc.setSelected(false);
		abx = 0;
	  }
//	} else if (obj == dbc) { // "Debug" checkbox
//		if (dbc.isSelected()) 
//			strdb = "-debug";
//		else
//			strdb = " ";
	} else if (obj == vdc) { // "Validate" checkbox
		if (!vdc.isSelected()) {
			strvd = "-novalidate";
                        dbc.setSelected(false);
                }
	}
    }

    public void focusGained(FocusEvent e) {
        focused = (JTextField)e.getSource();
        if (prevfocused != null) {
            prevfocused.setText(prevfocused.getText());
            if (iend != -1)
                if (iend < focused.getText().length())
                             prevfocused.setCaretPosition(iend);
                else focused.setCaretPosition(focused.getText().length());
        }  
    }           
        
    public void focusLost(FocusEvent e) {
        if (istart != -1)     {
            focused.setSelectionStart(istart);
            focused.setSelectionEnd(iend);
            prevfocused = focused;
          }
        }       
    public void mouseClicked(MouseEvent e) {}
    public void mouseEntered(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
    public void mouseExited(MouseEvent e) {
        if (focused != null) { 
          String selectedText = focused.getSelectedText();
          if (selectedText!=null) {
            istart = focused.getSelectionStart();
            iend = focused.getSelectionEnd();
          } else {
            istart = -1;
            iend = -1;
          } 
        }       
    }   
           
/** Set up gridbaglayout.
 */
    private void makeJButton(Container cont, Object arg,
            int x, int y, int w, int h, double weightx, double weighty) {
        GridBagLayout gbl = (GridBagLayout)cont.getLayout();
        GridBagConstraints c = new GridBagConstraints();
        Component comp;

        c.fill = GridBagConstraints.BOTH;
        c.gridx = x;
        c.gridy = y;
        c.gridwidth = w;
        c.gridheight = h;
        c.weightx = weightx;
        c.weighty = weighty;
        if (arg instanceof String) {
            comp = new JButton((String)arg);
        } else {
            comp = (Component)arg;
        }
        cont.add(comp);
        gbl.setConstraints(comp, c);
    }

/** Execute a command as a separate process for the user selection and returns 
    the results in the text area.
 */ 
    private void runit(String[] command) {
        try {
           String osName = System.getProperty("os.name");
           String cwd = System.getProperty("user.dir");
           libcdfPath = cwd + "/libcdf.dylib";
           if (osName.toLowerCase().indexOf("mac") != -1) {
               File libcdf = new File(libcdfPath);
               if (libcdf.exists()) {
                   macLib = 0;
               } else {
                 if (Files.isWritable(Paths.get(cwd))) {
                   try {
                     cdfbase = System.getProperty("CDF_BASE");
                     if (cdfbase == null)
                         cdfbase = CDFToolsUtil.getenv("CDF_BASE");
                     Files.copy(Paths.get(cdfbase+"/lib/libcdf.dylib"),
                                Paths.get(libcdfPath),
                                StandardCopyOption.REPLACE_EXISTING);
                     macLib = 1;
                   } catch (Exception ex) {
                     System.out.println ("**** Error for copying... "+ex);
                   }
                 }
               }
           }
	   int whichOne;
	   if (command[1] != null) {
		  whichOne = 1;
                  process = runtime.exec(command);
	   } else {
		  whichOne = 0;
                  process = runtime.exec(command[0]);
	   }
   	   if (hlp == 0 && abx == 0) { // skip if just for help info
                  info.setText("Program is running...\n");
	   }
	   Dimension dialogSize = dialog.getSize();
	   ((JComponent)(dialog.getContentPane())).paintImmediately(
                                                0, 0, dialogSize.width, dialogSize.height);
	   String line = null;
	   InputStreamReader inReader2 = new InputStreamReader(process.getInputStream(), "UTF-8");
	   BufferedReader inStream = new BufferedReader(inReader2, 8192);

	   boolean first = true;
	   while ((line = inStream.readLine()) != null) {
	     if (first) {
		info.setText("");
		first = false;
	     }
	     info.append(line+"\n");
	   }
	   if ((whichOne == 0 && command[0].indexOf("about") == -1) ||
	       (whichOne == 1 && command[2].indexOf("about") == -1))
	     info.append("Done");
	   process.waitFor();
	   info.setCaretPosition(0);
	   if (process.exitValue() == 1) Toolkit.getDefaultToolkit().beep();
	   if (hlp == 1) hlp = 0;
        } catch (Exception e) {
              info.setText("error executing: "+e);
              Toolkit.getDefaultToolkit().beep();
        }
    }

/** Initiate the file chooser and strip the extension for the selected file
    if necessary
 */

    private void doFileChooser (String title, JTextField textField, int theone, SimpleFileFilter filter) {
//        JFileChooser fileChooser = new JFileChooser();
        ExampleFileView fileView = new ExampleFileView();
//        fileChooser.setCurrentDirectory(new File(currentdir));
        fileChooser.setDialogTitle(title);
        if (filter != null) {
           fileChooser.addChoosableFileFilter(filter);
           fileChooser.setFileFilter(filter);
        }
        try {
           fileView.putIcon("cdf",
                            new ImageIcon(CDFStats.class.getResource("CDF_Logo3.gif")));
           fileView.putIcon("CDF",
                            new ImageIcon(CDFStats.class.getResource("CDF_Logo3.gif")));
           fileChooser.setFileView(fileView);
        } catch (Exception e) {}

        int returnValue = fileChooser.showDialog(dialog, "OK");
        if (returnValue == JFileChooser.APPROVE_OPTION) {
           File selectedFile = fileChooser.getSelectedFile();
           if (selectedFile != null) {
              int ind;
              String myfile = selectedFile.getAbsolutePath();
              if (theone == 1) { // for .cdf file
                  ind = myfile.lastIndexOf(".cdf");
                  if (ind != -1) myfile = myfile.substring(0, ind);
                  ind = myfile.lastIndexOf(".CDF");
                  if (ind != -1) myfile = myfile.substring(0, ind);
              } else { // for .skt file
                  ind = myfile.lastIndexOf(".skt");
                  if (ind != -1) myfile = myfile.substring(0, ind);
                  ind = myfile.lastIndexOf(".SKT");
                  if (ind != -1) myfile = myfile.substring(0, ind);
              }
              fileChooser.setCurrentDirectory(selectedFile);
              textField.setText(myfile);
           }
        } else {
//                JOptionPane.showMessageDialog(dialog, "No file chosen");
        }
    }

/** This class can run as an application by its own.
 */
    static public void main(String[] args) {

        String cdfbase = System.getProperty("CDF_BASE");
        if (cdfbase == null)
          cdfbase = CDFToolsUtil.getenv("CDF_BASE");

        CDFValidate thispgm = new CDFValidate(null, cdfbase);
        thispgm.frommain = 1;
	thispgm.run();
    }

}
