/*
 * Open Source Physics software is free software as described near the bottom of this code file.
 *
 * For additional information and documentation on Open Source Physics please see:
 * <http://www.opensourcephysics.org/>
 */

package org.opensourcephysics.tools;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import org.opensourcephysics.display.DisplayRes;
import org.opensourcephysics.display.OSPRuntime;

/**
 * Utility classes to work with Ejs at a high level
 *
 * @author Francisco Esquembre (http://fem.um.es)
 * @version 1.0
 */
public class EjsTool {
  static private final String INFO_FILE = ".Ejs.txt";                                      //$NON-NLS-1$
  static public final String GET_MODEL_METHOD = "_getEjsModel";                            //$NON-NLS-1$
  static public final String GET_RESOURCES_METHOD = "_getEjsResources";                    //$NON-NLS-1$
  static public final String GET_APPLET_DIMENSION_METHOD = "_getEjsAppletDimension";       //$NON-NLS-1$
  // ---- Localization
  static private final String BUNDLE_NAME = "org.opensourcephysics.resources.tools.tools"; //$NON-NLS-1$
  static private ResourceBundle res = ResourceBundle.getBundle(BUNDLE_NAME);

  static public void setLocale(Locale locale) {
    res = ResourceBundle.getBundle(BUNDLE_NAME, locale);
  }

  static public String getString(String key) {
    try {
      return res.getString(key);
    } catch(MissingResourceException e) {
      return '!'+key+'!';
    }
  }

  // --- End of localization

  /**
   * Whether a class provides an Ejs model.
   * @param _ejsClass Class
   * @return boolean
   */
  static public boolean hasEjsModel(Class<?> _ejsClass) {
    try {
      Class<?>[] c = {};
      java.lang.reflect.Method getModelMethod = _ejsClass.getMethod(GET_MODEL_METHOD, c);
      return getModelMethod!=null;
    } catch(Exception _exc) {
      return false;
    }
  }

  /**
   * Returns the preferred dimension for the simulation's main window.
   * @param _ejsClass Class
   * @return boolean
   */
  static public java.awt.Dimension getEjsAppletDimension(Class<?> _ejsClass) {
    try {
      Class<?>[] c = {};
      java.lang.reflect.Method getDimensionMethod = _ejsClass.getMethod(GET_APPLET_DIMENSION_METHOD, c);
      if(getDimensionMethod==null) {
        return null;
      }
      Object[] o = {};
      return(java.awt.Dimension) getDimensionMethod.invoke(null, o);
    } catch(Exception _exc) {
      return null;
    }
  }

  /**
   * Runs the Ejs model corresponding to the given class.
   * The model and resources required will be extracted using
   * the ResourceLoader utility.
   * @param _ejsClass Class
   * @return boolean true if successful
   */
  static public boolean runEjs(Class<?> _ejsClass) {
    return runEjs(_ejsClass,null);
  }
  
  /**
   * Runs the Ejs model corresponding to the given class providing a given password
   * The model and resources required will be extracted using
   * the ResourceLoader utility.
   * @param _ejsClass Class
   * @param _password String
   * @return boolean true if successful
   */
  @SuppressWarnings("unchecked")
  static public boolean runEjs(Class<?> _ejsClass, String _password) {
    try {
      Class<?>[] c = {};
      java.lang.reflect.Method getModelMethod = _ejsClass.getMethod(GET_MODEL_METHOD, c);
      java.lang.reflect.Method getResourcesMethod = _ejsClass.getMethod(GET_RESOURCES_METHOD, c);
      Object[] o = {};
      String model = (String) getModelMethod.invoke(null, o);
      java.util.Set<String> list;
      if(getResourcesMethod!=null) {
        list = (java.util.Set<String>) getResourcesMethod.invoke(null, o);
      } else {
        list = new java.util.HashSet<String>();
      }
      return doRunEjs(model, list, _ejsClass, _password);
    } catch(Exception _exc) {
      _exc.printStackTrace();
      String[] message = new String[] {res.getString("EjsTool.EjsNotRunning"), res.getString("EjsTool.NoModel")+" "+_ejsClass.getName()}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      JOptionPane.showMessageDialog((JFrame) null, message, res.getString("EjsTool.Error"), JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$
      return false;
    }
  }

  /**
   * To be used by EJS version 3.47 and earlier only.
   * It is here to make sure that the information saved matches the
   * information read by runEjs().
   * @param _release String
   */
  static public void saveInformation(String _home, String _release) {
    try {
      String filename = System.getProperty("user.home").replace('\\', '/'); //$NON-NLS-1$
      if(!filename.endsWith("/")) {                                         //$NON-NLS-1$ 
        filename = filename+"/";                                            //$NON-NLS-1$ 
      }
      filename = filename+INFO_FILE;
      String dir = System.getProperty("user.dir");                          //$NON-NLS-1$
      FileWriter fout = new FileWriter(filename);
      fout.write("directory = "+dir+"\n");                                  //$NON-NLS-1$ //$NON-NLS-2$
      fout.write("home = "+_home+"\n");                                     //$NON-NLS-1$ //$NON-NLS-2$
      fout.write("version = "+_release+"\n");                               //$NON-NLS-1$ //$NON-NLS-2$
      fout.close();
    } catch(Exception exc) {
      exc.printStackTrace();
    }
  }

  /**
   * To be used by EJS version 4.0 and later only.
   * It is here to make sure that the information saved matches the
   * information read by runEjs().
   * @param _binDirectoryPath String The binary directory from which EJS was launched
   * @param _sourceDirectoryPath String The source directory path
   * @param _release String The EJS release version
   */
  static public void saveInformation(String _binDirectoryPath, String _sourceDirectoryPath, String _release) {
    try {
      String filename = System.getProperty("user.home").replace('\\', '/'); //$NON-NLS-1$
      if(!filename.endsWith("/")) {                                         //$NON-NLS-1$ 
        filename = filename+"/";                                            //$NON-NLS-1$ 
      }
      FileWriter fout = new FileWriter(filename+INFO_FILE);
      fout.write("ejs_root_directory = "+_binDirectoryPath+"\n");           //$NON-NLS-1$ //$NON-NLS-2$
      //fout.write("console_options = "+_consoleOptionsFilePath+"\n");
      fout.write("source_directory = "+_sourceDirectoryPath+"\n");          //$NON-NLS-1$ //$NON-NLS-2$
      fout.write("version = "+_release+"\n");                               //$NON-NLS-1$ //$NON-NLS-2$
      fout.close();
    } catch(Exception exc) {
      exc.printStackTrace();
    }
  }

  //------------------------------------
  // Private methods and inner classes
  //------------------------------------

  /**
   * Gets the path of a file in standard form.
   * If it is a directory, the path ends in "/"
   */
  static public String getPath(File _file) {
    String path;
    try {
      path = _file.getCanonicalPath();
    } catch(Exception exc) {
      path = _file.getAbsolutePath();
    }
    if(org.opensourcephysics.display.OSPRuntime.isWindows()) {
      path = path.replace('\\', '/');
      // Sometimes the system provides c:, sometimes C:\
      int a = path.indexOf(':');
      if(a>0) {
        path = path.substring(0, a).toUpperCase()+path.substring(a);
      }
    }
    if(_file.isDirectory()&&!path.endsWith("/")) { //$NON-NLS-1$ 
      path = path+"/";                             //$NON-NLS-1$ 
    }
    return path;
  }

  /**
   * Extracts an EJS model (and its resource files) from the given
   * source and then runs EJS with that model. The example is extracted
   * in the source directory of the users' EJS. The user will be warned
   * before overwriting any file.
   * @return boolean
   */
  static private boolean doRunEjs(String _model, java.util.Set<String> _resources, Class<?> _ejsClass, final String _password) {
    String ejsRootDirPath = null;
    //String console_options = null;
    String sourceDirPath = null;
    String version = null;
    File ejsRootDirectory = null;
    java.awt.Component parentComponent = null;
    try {
      String filename = System.getProperty("user.home").replace('\\', '/');       //$NON-NLS-1$
      if(!filename.endsWith("/")) {                                               //$NON-NLS-1$ 
        filename = filename+"/";                                                  //$NON-NLS-1$ 
      }
      Reader reader = new FileReader(filename+INFO_FILE);
      LineNumberReader l = new LineNumberReader(reader);
      String sl = l.readLine();
      while(sl!=null) {
        if(sl.startsWith("ejs_root_directory = ")) {                              //$NON-NLS-1$ 
          ejsRootDirPath = sl.substring("ejs_root_directory = ".length()).trim(); //$NON-NLS-1$ 
          //else if (sl.startsWith("console_options = "))    console_options = sl.substring("console_options = ".length()).trim();
        } else if(sl.startsWith("source_directory = ")) {                                                     //$NON-NLS-1$ 
          sourceDirPath = sl.substring("source_directory = ".length()).trim();                                //$NON-NLS-1$ 
        } else if(sl.startsWith("version = ")) {                                                              //$NON-NLS-1$ 
          version = sl.substring("version = ".length()).trim();                                               //$NON-NLS-1$ 
        }
        sl = l.readLine();
      }
      reader.close();
      int major = 3;
      if(version!=null) {
        int index = version.indexOf('.');
        if(index>=0) {
          major = Integer.parseInt(version.substring(0, index));
        }
      }
      if(major<4) {                                                                                           // Incorrect version, update to 4.0
        JOptionPane.showMessageDialog(parentComponent, version+" "+res.getString("EjsTool.IncorrectVersion"), //$NON-NLS-1$ //$NON-NLS-2$
          res.getString("EjsTool.Error"), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
        return false;
      }
      // See if EjsConsole.jar is there
      ejsRootDirectory = new File(ejsRootDirPath);
      if(!new File(ejsRootDirectory, "EjsConsole.jar").exists()) {    //$NON-NLS-1$ 
        ejsRootDirectory = null;
      }
    } catch(Exception exc) {
      exc.printStackTrace();
      ejsRootDirectory = null;
    }
    if(ejsRootDirectory==null) {
      // Create a chooser
      JFileChooser chooser = OSPRuntime.createChooser("", new String[] {});         //$NON-NLS-1$
      chooser.setDialogTitle(res.getString("EjsTool.EjsNotFound"));                 //$NON-NLS-1$
      chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
      chooser.setMultiSelectionEnabled(false);
      // The message
      JTextArea textArea = new JTextArea(res.getString("EjsTool.IndicateRootDir")); //$NON-NLS-1$
      textArea.setWrapStyleWord(true);
      textArea.setLineWrap(true);
      textArea.setEditable(false);
      textArea.setFont(textArea.getFont().deriveFont(java.awt.Font.BOLD));
      textArea.setPreferredSize(new java.awt.Dimension(150, 60));
      textArea.setBackground(chooser.getBackground());
      textArea.setBorder(new javax.swing.border.EmptyBorder(5, 10, 0, 0));
      chooser.setAccessory(textArea);
      // Check that it exists or ask the user for it
      while(ejsRootDirectory==null) {
        if(chooser.showOpenDialog((java.awt.Component) null)!=JFileChooser.APPROVE_OPTION) {
          return false;                                                             // The user canceled
        }
        ejsRootDirectory = chooser.getSelectedFile();
        if(ejsRootDirectory==null) {
          return false;                                                             // The user canceled
        }
        if(!new File(ejsRootDirectory, "EjsConsole.jar").exists()) {                //$NON-NLS-1$ 
          ejsRootDirectory = null;
        }
      }
    }
    File sourceDir = new File(sourceDirPath);
    if(!sourceDir.exists()) {
      sourceDir.mkdirs();
    }
    // Extract the model and auxiliary files
    java.util.List<String> extractList = new ArrayList<String>();
    // Make relative files relative
    String modelPath = _model;
    int modelPathLength = 0;
    int index = modelPath.lastIndexOf('/');
    if(index>=0) {
      _model = "./"+modelPath.substring(index+1);  //$NON-NLS-1$
      modelPath = modelPath.substring(0, index+1); // including the '/'
      modelPathLength = modelPath.length();
    }
    if(!_resources.contains(_model)) {
      _resources.add(_model); // Make sure the model is there
    }
    if(modelPathLength>0) {
      for(String res : _resources) {
        extractList.add(res.startsWith(modelPath) ? "./"+res.substring(modelPathLength) : res); //$NON-NLS-1$
      }
    } else {
      extractList.addAll(_resources);
    }
    java.util.Collections.sort(extractList);
    
    // Auxiliary panel for the confirmation list
    JPanel auxPanel = new JPanel(new BorderLayout());

    JCheckBox originalPathBox = new JCheckBox(res.getString("EjsTool.KeepOriginalPath"), false); //$NON-NLS-1$
    JTextField originalPathField = new JTextField(modelPath);
    originalPathField.setEditable(false);
    
    JPanel originalPathPanel = new JPanel(new BorderLayout());
    originalPathPanel.add(originalPathBox,BorderLayout.WEST);
    originalPathPanel.add(originalPathField,BorderLayout.CENTER);
    
    JCheckBox quitCheckBox = null;
    if (!OSPRuntime.appletMode) { // Applets do not quit
      quitCheckBox = new JCheckBox(res.getString("EjsTool.QuitSimulation"), true); //$NON-NLS-1$
      auxPanel.add(quitCheckBox, BorderLayout.NORTH);
    }
    
    auxPanel.add(originalPathPanel, BorderLayout.CENTER);
    
    java.util.List<Object> finalList = ejsConfirmList(parentComponent, new java.awt.Dimension(400, 400), res.getString("EjsTool.ExtractingFiles"), res.getString("EjsTool.Message"), extractList, auxPanel); //$NON-NLS-1$ //$NON-NLS-2$
    if(finalList==null) {
      return false; // The user canceled
    }
    /* Add the "files" directory to the ResourceLoader
    String filesDir=null;
    if (ResourceLoader.getResource(_model)==null) { // Search in the class "files" directory
      filesDir = _ejsClass.getName().replace('.', '/') + "/files";
      ResourceLoader.addSearchPath(filesDir);
    }
    */
    
    File destinationDirectory = null;
    String relativeDir = ""; //$NON-NLS-1$
    if (originalPathBox.isSelected()) {
      destinationDirectory = new File(sourceDir,modelPath);
      relativeDir = modelPath;
    }
    else { // the user selects a destination directory
      // Create a chooser
      JFileChooser chooser = OSPRuntime.createChooser("", new String[] {}); //$NON-NLS-1$
      chooser.setDialogTitle(res.getString("EjsTool.ChooseDestinationDirectory")); //$NON-NLS-1$
      chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
      chooser.setMultiSelectionEnabled(false);
      chooser.setCurrentDirectory(sourceDir);
      // Choose a correct destination directory
      sourceDirPath = EjsTool.getPath(sourceDir);
      while(destinationDirectory==null) {
        if(chooser.showOpenDialog((java.awt.Component) null)!=JFileChooser.APPROVE_OPTION) {
          return false;                                                                              // The user canceled
        }
        destinationDirectory = chooser.getSelectedFile();
        if(destinationDirectory==null) {
          return false;                                                                              // The user canceled
        }
        String destDirPath = EjsTool.getPath(destinationDirectory);
        if(!destDirPath.startsWith(sourceDirPath)) {
          JOptionPane.showMessageDialog(parentComponent, res.getString("EjsTool.MustBeUnderSource"), //$NON-NLS-1$
              res.getString("EjsTool.Error"), JOptionPane.ERROR_MESSAGE);                              //$NON-NLS-1$
          destinationDirectory = null;
        } else {
          relativeDir = destDirPath.substring(sourceDirPath.length());
        }
      }

    }
    // Extract files
    destinationDirectory.mkdirs();
    int policy = JarTool.NO;
    for(Iterator<?> it = finalList.iterator(); it.hasNext(); ) {
      String resource = (String) it.next();
      File targetFile = resource.startsWith("./") ? new File(destinationDirectory, resource.substring(2)) : new File(sourceDir, resource); //$NON-NLS-1$
      if(targetFile.exists()) {
        switch(policy) {
           case JarTool.NO_TO_ALL :
             continue;
           case JarTool.YES_TO_ALL :
             break;                                                                                                                // will overwrite
           default :
             switch(policy = JarTool.confirmOverwrite(resource)) {
                case JarTool.NO_TO_ALL :
                case JarTool.NO :
                  continue;
                default :                                                                                                          // Do nothing, i.e., will overwrite the file
             }
        }
      }
      String originalName = resource.startsWith("./") ? modelPath+resource.substring(2) : resource;                                //$NON-NLS-1$
//      System.err.println ("Extract "+originalName+" into "+targetFile.getAbsolutePath());
      File result = JarTool.extract(originalName, targetFile);                                                                     // Use the ResourceLoader
      if(result==null) {
        String[] message = new String[] {res.getString("JarTool.FileNotExtracted"),                                                //$NON-NLS-1$
                                         originalName+" "+res.getString("JarTool.FileNotExtractedFrom")+" "+_ejsClass.toString()}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        JOptionPane.showMessageDialog((JFrame) null, message, res.getString("JarTool.Error"), JOptionPane.WARNING_MESSAGE); //$NON-NLS-1$
        return false;
      }
    }
    // Now run the EJS console
    //final String theOptions = console_options;
    final String theModel = relativeDir+(_model.startsWith("./") ? _model.substring(2) : _model); //$NON-NLS-1$
    final File theDir = ejsRootDirectory;
    Runnable runner = new Runnable() {
      public void run() {
        try {
          final Vector<String> cmd = new Vector<String>();
          String javaHome = System.getProperty("java.home");                                      //$NON-NLS-1$
          if(javaHome!=null) {
            cmd.add(javaHome+java.io.File.separator+"bin"+java.io.File.separator+"java");         //$NON-NLS-1$ //$NON-NLS-2$
          } else {
            cmd.add("java");                                                                      //$NON-NLS-1$
          }
          //if (theOptions!=null) cmd.add("-Dejs.console_options="+theOptions);
          cmd.add("-jar");                                                                        //$NON-NLS-1$
          cmd.add("EjsConsole.jar");                                                              //$NON-NLS-1$
          if (_password!=null && _password.length()>0) {
            cmd.add("-launcher.password"); //$NON-NLS-1$
            cmd.add("\""+_password+"\"");                                                         //$NON-NLS-1$ //$NON-NLS-2$
          }
          cmd.add("-file");                                                                       //$NON-NLS-1$
          cmd.add(theModel);
          String[] cmdarray = cmd.toArray(new String[0]);
//                    for (int i=0; i<cmdarray.length; i++) System.out.println ("Trying to run ["+i+"] = "+cmdarray[i]);
          Process proc = Runtime.getRuntime().exec(cmdarray, null, theDir);
          proc.waitFor();
        } catch(Exception exc) {
          exc.printStackTrace();
        }
      }

    };
    java.lang.Thread thread = new Thread(runner);
    thread.setPriority(Thread.NORM_PRIORITY);
    thread.start();
    return quitCheckBox==null ? false : quitCheckBox.isSelected();
  }

  public static java.util.List<Object> ejsConfirmList(Component _target, Dimension _size, String _message, String _title, java.util.List<?> _list) {
    return ejsConfirmList(_target, _size, _message, _title, _list, (JComponent) null);
  }

  /**
   * This method receives a list of objects which it exposes to the user.
   * The user can remove objects from the list and click OK.
   * The class then returns the modified list.
   * If the user clicks cancel it will return null
   * @param _target Component The dialog will be shown relative to this component
   * @param _size Dimension The size of the display dialog
   * @param _message String The message to display
   * @param _title String The title for the display dialog
   * @param _list java.util.List<?> The initial list of objects
   * @param _bottomComponent JComponent and additional component to show at the bottom
   * @return AbstractList
   */
  public static java.util.List<Object> ejsConfirmList(Component _target, Dimension _size, String _message, String _title, java.util.List<?> _list, JComponent _bottomComponent) {
    class ReturnValue {
      boolean value = false;

    }
    final ReturnValue returnValue = new ReturnValue();
    final DefaultListModel listModel = new DefaultListModel();
    for(int i = 0, n = _list.size(); i<n; i++) {
      listModel.addElement(_list.get(i));
    }
    final JList list = new JList(listModel);
    list.setEnabled(true);
    list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
    list.setSelectionInterval(0, listModel.getSize()-1);
    JScrollPane scrollPane = new JScrollPane(list);
    scrollPane.setPreferredSize(_size);
    final JDialog dialog = new JDialog();
    java.awt.event.MouseAdapter mouseListener = new java.awt.event.MouseAdapter() {
      public void mousePressed(java.awt.event.MouseEvent evt) {
        AbstractButton button = (AbstractButton) (evt.getSource());
        String aCmd = button.getActionCommand();
        if(aCmd.equals("ok")) {                //$NON-NLS-1$ 
          returnValue.value = true;
          dialog.setVisible(false);
        } else if(aCmd.equals("cancel")) {     //$NON-NLS-1$ 
          returnValue.value = false;
          dialog.setVisible(false);
        } else if(aCmd.equals("selectall")) {  //$NON-NLS-1$ 
          list.setSelectionInterval(0, listModel.getSize()-1);
        } else if(aCmd.equals("selectnone")) { //$NON-NLS-1$ 
          list.removeSelectionInterval(0, listModel.getSize()-1);
        }
      }

    };
    JButton okButton = new JButton(DisplayRes.getString("GUIUtils.Ok")); //$NON-NLS-1$
    okButton.setActionCommand("ok"); //$NON-NLS-1$
    okButton.addMouseListener(mouseListener);
    JButton cancelButton = new JButton(DisplayRes.getString("GUIUtils.Cancel")); //$NON-NLS-1$
    cancelButton.setActionCommand("cancel"); //$NON-NLS-1$
    cancelButton.addMouseListener(mouseListener);
    JButton excludeButton = new JButton(DisplayRes.getString("GUIUtils.SelectAll")); //$NON-NLS-1$
    excludeButton.setActionCommand("selectall"); //$NON-NLS-1$
    excludeButton.addMouseListener(mouseListener);
    JButton includeButton = new JButton(DisplayRes.getString("GUIUtils.SelectNone")); //$NON-NLS-1$
    includeButton.setActionCommand("selectnone"); //$NON-NLS-1$
    includeButton.addMouseListener(mouseListener);
    JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
    buttonPanel.add(okButton);
    buttonPanel.add(excludeButton);
    buttonPanel.add(includeButton);
    buttonPanel.add(cancelButton);
    JPanel topPanel = new JPanel(new BorderLayout());
    JTextArea textArea = new JTextArea(_message);
    textArea.setWrapStyleWord(true);
    textArea.setLineWrap(true);
    textArea.setEditable(false);
    textArea.setFont(textArea.getFont().deriveFont(Font.BOLD));
    textArea.setBackground(topPanel.getBackground());
    textArea.setBorder(new javax.swing.border.EmptyBorder(5, 5, 10, 5));
    topPanel.setBorder(new javax.swing.border.EmptyBorder(5, 10, 5, 10));
    topPanel.add(textArea, BorderLayout.NORTH);
    topPanel.add(scrollPane, BorderLayout.CENTER);
    if(_bottomComponent!=null) {
      topPanel.add(_bottomComponent, BorderLayout.SOUTH);
    }
    JSeparator sep1 = new JSeparator(SwingConstants.HORIZONTAL);
    JPanel southPanel = new JPanel(new java.awt.BorderLayout());
    southPanel.add(sep1, java.awt.BorderLayout.NORTH);
    southPanel.add(buttonPanel, java.awt.BorderLayout.SOUTH);
    dialog.getContentPane().setLayout(new java.awt.BorderLayout(5, 0));
    dialog.getContentPane().add(topPanel, java.awt.BorderLayout.CENTER);
    dialog.getContentPane().add(southPanel, java.awt.BorderLayout.SOUTH);
    dialog.addWindowListener(new java.awt.event.WindowAdapter() {
      public void windowClosing(java.awt.event.WindowEvent event) {
        returnValue.value = false;
      }

    });
    //    dialog.setSize (_size);
    dialog.validate();
    dialog.pack();
    dialog.setTitle(_title);
    dialog.setLocationRelativeTo(_target);
    dialog.setModal(true);
    dialog.setVisible(true);
    if(!returnValue.value) {
      return null;
    }
    Object[] selection = list.getSelectedValues();
    java.util.List<Object> newList = new ArrayList<Object>();
    for(int i = 0, n = selection.length; i<n; i++) {
      newList.add(selection[i]);
    }
    return newList;
  }

} // End of class

/*
 * Open Source Physics software is free software; you can redistribute
 * it and/or modify it under the terms of the GNU General Public License (GPL) as
 * published by the Free Software Foundation; either version 2 of the License,
 * or(at your option) any later version.
 *
 * Code that uses any portion of the code in the org.opensourcephysics package
 * or any subpackage (subdirectory) of this package must must also be be released
 * under the GNU GPL license.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA
 * or view the license online at http://www.gnu.org/copyleft/gpl.html
 *
 * Copyright (c) 2007  The Open Source Physics project
 *                     http://www.opensourcephysics.org
 */
