import rock.*;
import rock.dRockPackage.*;
import rock.RockManagerPackage.*;
import common.ClientData;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;

import javax.naming.*;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.event.*;
import javax.swing.table.*;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

import java.text.*;

/**
 * Creates a CORBA client applet or standalone application that implements a MELTS GUI.
 * This is a beta version and lacks a few of the unix GUI features.
 * @version 1.0 (August 2007)
 * @author Mark S. Ghiorso, OFM-Research Inc.
 */
public class Melts extends JApplet { 
  /** Public declaration of applet container. */
  public Container cp;
  /** Public declaration of applet frame. */
  public JFrame frame;
  /** CORBA ORB reference for the server-side rock object. */
  public rock.dRock rockRef;
  /** True if invoked as a standalone application; false if invoked as an applet. */
  public boolean isStandalone = false;
  /** Command line arguments passed to application. */
  public String args[];  
  /** Holds bulk composition display entry. */
  public JFormattedTextField bcEntry[];
  /** Holds phase composition display entry. */
  public JFormattedTextField ppEntry[];
  /** Holds temperature display entry. */
  public JFormattedTextField tEntry;
  /** Holds pressure display entry. */
  public JFormattedTextField pEntry;
  /** Holds oxygen fugacity display entry. */
  public JFormattedTextField fO2Entry;
  /** Holds iteration count display entry. */
  public JFormattedTextField iterEntry;
  /** Holds quadratic iteration count display entry. */
  public JFormattedTextField quadEntry;
  /** Holds linear search iteration count display entry. */
  public JFormattedTextField linEntry;
  /** Displays relative concentration of liquid phase in the system. */
  public JProgressBar liqProgress;
  /** Displays relative concentration of solid phase(s) in the system. */
  public JProgressBar solProgress;
  /** Displays relative amount of assimilant consumed by the system. */
  public JProgressBar assimProgress;
  /** Displays relative amount of fractionated phase(s) in the system. */
  public JProgressBar fracProgress;
  /** Selected row in the phases present table. */
  public int ptSelectedRow;
  /** Selected column in the phases present table. */
  public int ptSelectedCol;
  /** Dialog box for opening files from and saving output to the local disk. */
  public JFileChooser openSaveDialog;

  private static JTextArea statusDisplay;
  private int nc;
  private PhaseTableModel  pTableModel;
  private UpdatePhaseTable updatePT;
  private JComboBox        phasePopupMenu;
  private double bulkComp[];
  private int fO2DisplayMode;
  private TPHandler tphsvDialog;
  private PhaseHandler phaseDialog;
  private JRadioButtonMenuItem fO2Choice[];
  private JCheckBoxMenuItem mulLiqRBMI, fracSolRBMI,  fracLiqRBMI, isoEnthalpyRBMI, isoEntropyRBMI, isoVolumeRBMI;
  private File saveFile;
  private boolean hasSaveFile, doServerUpdates;
  private MeltsOutput mOutput;
  
  /** Set to true if running in isenthalpic mode (independent variables H and P). */
  public static boolean isenthalpic;
  /** Set to true if running in isetopic mode (independent variables S and P). */
  public static boolean isentropic;
  /** Set to true if running in isochoric mode (independent variables T and V). */
  public static boolean isochoric;
  /** Set to true if solid phases are fractionated to an inert system reservoir. */
  public static boolean fracSolids;
  /** Set to true if the liquid phase is fractionated to an inert system reservoir (fractional melting). */
  public static boolean fracLiquids;
  
  private static final int FO2_DISPLAY_NONE = 0;
  private static final int FO2_DISPLAY_HM   = 1;
  private static final int FO2_DISPLAY_NNO  = 2;
  private static final int FO2_DISPLAY_QFM  = 3;
  private static final int FO2_DISPLAY_CCOH = 4;
  private static final int FO2_DISPLAY_IW   = 5;

  /**
   * Displays informative messages in the status display box on the main GUI.
   * The status display box is scrollable and all messages are saved.
   * @param output Message to be displayed.
   */
  public static void printStatus (String output) {
    if (statusDisplay == null) return;
    statusDisplay.append(output + "\n");
    statusDisplay.setCaretPosition(statusDisplay.getDocument().getLength());
  }
  
  /**
   * Converts numbers in a string to subscripts.
   * @param input String to be converted. Content is not altered.
   * @return Converted string with numbers replaced by subscripts.
   */
  public static String makeSubscript (String input) {
    String out1, out2, output;
    out1   = input.replace('0', '\u2080');
    out2   =  out1.replace('1', '\u2081');
    out1   =  out2.replace('2', '\u2082');
    out2   =  out1.replace('3', '\u2083');
    out1   =  out2.replace('4', '\u2084');
    out2   =  out1.replace('5', '\u2085');
    out1   =  out2.replace('6', '\u2086');
    out2   =  out1.replace('7', '\u2087');
    out1   =  out2.replace('8', '\u2088');
    output =  out1.replace('9', '\u2089');
    return output;
  }
  
  /**
   * Generates class instance. Called by applet manager.
   */
  public Melts() {
  }
  
  /**
   * Generates class instance. Called when invoked as a standalone application. 
   * @param args String array of standard arguments used to initialize the class.
   */
  public Melts(String args[]) {
    this.isStandalone = true;
    this.args = args;
  }
  
  /**
   * Applet method. Creates GUI interface.  
   */
  public void init() {
    
    String laf = UIManager.getCrossPlatformLookAndFeelClassName();
    try {
      UIManager.setLookAndFeel(laf);
    } catch(Exception ce) {
      System.err.println("Error loading" + laf + ":" +ce);
    }
    doServerUpdates = true;
    
    // ORB Call
    try {
      Connection c1 = new Connection();
      ORB orb;
      
      if (isStandalone) {
        java.util.Properties props = new java.util.Properties();
        props.put("org.omg.CORBA.ORBInitialPort", "2809");
        props.put("org.omg.CORBA.ORBInitialHost", "216.231.56.114");
        //props.put("org.omg.CORBA.ORBInitialHost", "localhost");
        orb = c1.getORB(args, props);
      
      } else orb = c1.getORB(this); 
      RockFactory rFactory = c1.getRockFactory(orb);
      String chn, ha, hn;
      try {
        chn = InetAddress.getLocalHost().getCanonicalHostName();
        ha  = InetAddress.getLocalHost().getHostAddress();
        hn  = InetAddress.getLocalHost().getHostName();
      } catch (UnknownHostException e) { 
        chn = "no host name"; 
	ha  = "no ip address";
	hn  = "no host name";
      }      
      ClientData cd = new ClientData(
        "Java",
        System.getProperty("java.vendor"),
        System.getProperty("java.version"),
        System.getProperty("java.vendor"),
        System.getProperty("java.version"),
	"",
        System.getProperty("os.name"),
        System.getProperty("os.arch"),
        System.getProperty("os.version"),
        System.getProperty("user.name"),
        Locale.getDefault().getDisplayName(),
        TimeZone.getDefault().getDisplayName(),
        chn,
	ha,
        hn
      );
      rockRef = rFactory.spawnRock(cd);
    } catch (Exception e) { // catch any CORBA server connection problems 
      System.out.println("ERROR in ORB initialization: " + e);
      JOptionPane.showMessageDialog(null, 
        "Could not establish contact with server.\nPlease reload applet or restart application.",
	"CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      rockRef = null;
    }
    // ... End ORB Call

    //***************************
    // Create the Applet Instance
    //***************************
    frame = new JFrame("MELTS/pMELTS CORBA client. v.0.8, August 2007");
    if (isStandalone) {
      frame.addWindowListener(new java.awt.event.WindowAdapter() {
        public void windowClosing(java.awt.event.WindowEvent e) {
	  try {
  	    if (rockRef != null) rockRef.remove();
	  } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
	  } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
	  }
    	  System.exit(0);
        }
      });
    } else {
      frame.addWindowListener(new java.awt.event.WindowAdapter() {
        public void windowClosing(java.awt.event.WindowEvent e) {
	  doServerUpdates = false;  // Do this to prevent the Text Handler callback
        }                           // from locking up the browser when the server 
      });                           // has gone down or deleted the rock object
    }
    cp = frame.getContentPane();
    
    JApplet applet = new Melts();
    
    GridBagLayout gbl = new GridBagLayout();
    cp.setLayout(gbl);
    frame.setVisible(true);
    
    //************************************
    // Create a panel to hold the menu bar
    //************************************  
    JPanel mPanel = new JPanel();
    mPanel.setLayout(new BorderLayout());
   
    //********************
    // Create the menu bar
    //********************
    JMenuBar mb = new JMenuBar();
    
    //******************
    // The Commands menu
    //******************
    JMenu jm1 = new JMenu("Commands"); jm1.setMnemonic('C');
      
      JMenuItem item1a = new JMenuItem("Find Liquidus"); 
        	item1a.setMnemonic('L');
        	item1a.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK));
        	item1a.addActionListener(new FindLiquidusHandler());
      jm1.add(item1a);
      
      JMenuItem item1b = new JMenuItem("Equilibrate");
        	item1b.setMnemonic('E');
        	item1b.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, ActionEvent.CTRL_MASK));
        	item1b.addActionListener(new EquilibrateHandler());
      jm1.add(item1b);
      
      JMenuItem item1c = new JMenuItem("Open...");
        	item1c.setMnemonic('O');
        	item1c.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
        	item1c.addActionListener(new OpenHandler());
      jm1.add(item1c);      
      openSaveDialog = new JFileChooser();

      JMenuItem item1d = new JMenuItem("Save");
        	item1d.setMnemonic('S');
        	item1d.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
        	item1d.addActionListener(new SaveHandler());
      jm1.add(item1d);
      
      JMenuItem item1e = new JMenuItem("Save as...");
        	item1e.setMnemonic('A');
        	item1e.addActionListener(new SaveHandler());
      jm1.add(item1e);
      saveFile    = null;
      hasSaveFile = false;      

      
      JMenuItem item1f = new JMenuItem("Exit");
        	item1f.setMnemonic('X');
        	item1f.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
        	item1f.addActionListener(new ExitHandler());
      if (isStandalone) jm1.add(item1f);
    
    mb.add(jm1);
    
    //*********************
    // The Composition menu
    //*********************
    JMenu jm2 = new JMenu("Composition"); jm2.setMnemonic('p');
    
      JMenuItem item2a = new JMenuItem("Compute Redox State"); 
                item2a.setMnemonic('R');
                item2a.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK)); 
        	item2a.addActionListener(new RedoxHandler());
      jm2.add(item2a);
      
      JMenuItem item2b = new JMenuItem("Normalize"); 
                item2b.setMnemonic('N');
                item2b.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK)); 
        	item2b.addActionListener(new NormalizeHandler());
      jm2.add(item2b);
    
    mb.add(jm2);
    
    //*****************************
    // The Intensive variables menu
    //*****************************
    JMenu jm3 = new JMenu("Intensive Variables"); jm3.setMnemonic('I');
    
      JMenuItem item3a = new JMenuItem("T, P ...");
        	item3a.setMnemonic('T');
      tphsvDialog = new TPHandler(rockRef); 
        	item3a.addActionListener(tphsvDialog);
      jm3.add(item3a); 
      
      JMenu item3b = new JMenu("f O2 Constraint"); 
            item3b.setMnemonic('f'); 
      jm3.add(item3b);
      
        fO2Handler handler3b = new fO2Handler();
	fO2Choice = new JRadioButtonMenuItem[18]; // Number of buttons declared below
    
        // This order and indexing is fixed - change it and change the order in private class OpenHandler declared below
        fO2Choice[ 0] = new JRadioButtonMenuItem("Absent");     fO2Choice[0].setMnemonic('A'); fO2Choice[ 0].addActionListener(handler3b); item3b.add(fO2Choice[ 0]);
        fO2Choice[ 1] = new JRadioButtonMenuItem("Hm-Mt");	fO2Choice[1].setMnemonic('H'); fO2Choice[ 1].addActionListener(handler3b); item3b.add(fO2Choice[ 1]);
        fO2Choice[ 2] = new JRadioButtonMenuItem("Ni-NiO");	fO2Choice[2].setMnemonic('N'); fO2Choice[ 2].addActionListener(handler3b); item3b.add(fO2Choice[ 2]);
        fO2Choice[ 3] = new JRadioButtonMenuItem("Q-Fa-Mt");	fO2Choice[3].setMnemonic('Q'); fO2Choice[ 3].addActionListener(handler3b); item3b.add(fO2Choice[ 3]);
        fO2Choice[ 4] = new JRadioButtonMenuItem("C-COH");	fO2Choice[4].setMnemonic('C'); fO2Choice[ 4].addActionListener(handler3b); item3b.add(fO2Choice[ 4]);
        fO2Choice[ 5] = new JRadioButtonMenuItem("Fe-FeO");	fO2Choice[5].setMnemonic('F'); fO2Choice[ 5].addActionListener(handler3b); item3b.add(fO2Choice[ 5]);
        fO2Choice[ 6] = new JRadioButtonMenuItem("Q-Fa-Mt+3"); 	 			       fO2Choice[ 6].addActionListener(handler3b); item3b.add(fO2Choice[ 6]);
        fO2Choice[ 7] = new JRadioButtonMenuItem("Q-Fa-Mt+2"); 	 			       fO2Choice[ 7].addActionListener(handler3b); item3b.add(fO2Choice[ 7]);
        fO2Choice[ 8] = new JRadioButtonMenuItem("Q-Fa-Mt+1"); 	 			       fO2Choice[ 8].addActionListener(handler3b); item3b.add(fO2Choice[ 8]);
        fO2Choice[ 9] = new JRadioButtonMenuItem("Q-Fa-Mt-1"); 	 			       fO2Choice[ 9].addActionListener(handler3b); item3b.add(fO2Choice[ 9]);
        fO2Choice[10] = new JRadioButtonMenuItem("Q-Fa-Mt-2"); 	 			       fO2Choice[10].addActionListener(handler3b); item3b.add(fO2Choice[10]);
        fO2Choice[11] = new JRadioButtonMenuItem("Q-Fa-Mt-3"); 	 			       fO2Choice[11].addActionListener(handler3b); item3b.add(fO2Choice[11]);
        fO2Choice[12] = new JRadioButtonMenuItem("Q-Fa-Mt-4"); 	 			       fO2Choice[12].addActionListener(handler3b); item3b.add(fO2Choice[12]);
        fO2Choice[13] = new JRadioButtonMenuItem("Q-Fa-Mt-5"); 	 			       fO2Choice[13].addActionListener(handler3b); item3b.add(fO2Choice[13]);
        fO2Choice[14] = new JRadioButtonMenuItem("Q-Fa-Mt-6"); 	 			       fO2Choice[14].addActionListener(handler3b); item3b.add(fO2Choice[14]);
        fO2Choice[15] = new JRadioButtonMenuItem("Q-Fa-Mt-7"); 	 			       fO2Choice[15].addActionListener(handler3b); item3b.add(fO2Choice[15]);
        fO2Choice[16] = new JRadioButtonMenuItem("Q-Fa-Mt-8"); 	 			       fO2Choice[16].addActionListener(handler3b); item3b.add(fO2Choice[16]);
        fO2Choice[17] = new JRadioButtonMenuItem("Q-Fa-Mt-9"); 	 			       fO2Choice[17].addActionListener(handler3b); item3b.add(fO2Choice[17]);
    
    ButtonGroup mg = new ButtonGroup();
    mg.add(fO2Choice[ 0]); mg.add(fO2Choice[ 1]); mg.add(fO2Choice[ 2]); mg.add(fO2Choice[ 3]); mg.add(fO2Choice[ 4]); mg.add(fO2Choice[ 5]); mg.add(fO2Choice[ 6]); 
    mg.add(fO2Choice[ 7]); mg.add(fO2Choice[ 8]); mg.add(fO2Choice[ 9]); mg.add(fO2Choice[10]); mg.add(fO2Choice[11]); mg.add(fO2Choice[12]); mg.add(fO2Choice[13]); 
    mg.add(fO2Choice[14]); mg.add(fO2Choice[15]); mg.add(fO2Choice[16]); mg.add(fO2Choice[17]);
    
    fO2Choice[0].doClick();
    
    mb.add(jm3);
    
    //*****************
    // The Options menu
    //*****************
    JMenu jm4 = new JMenu("Options"); jm4.setMnemonic('O');
    
      isenthalpic = false;
      isoEnthalpyRBMI = new JCheckBoxMenuItem("Isenthalpic");
      isoEnthalpyRBMI.setMnemonic('e'); 
      isoEnthalpyRBMI.addActionListener(new IsenthalpicHandler()); 
      jm4.add(isoEnthalpyRBMI);
      
      isentropic = false;
      isoEntropyRBMI = new JCheckBoxMenuItem("Isentropic");
      isoEntropyRBMI.setMnemonic('n'); 
      isoEntropyRBMI.addActionListener(new IsentropicHandler());
      jm4.add(isoEntropyRBMI);
      
      isochoric = false;
      isoVolumeRBMI = new JCheckBoxMenuItem("Isochoric");
      isoVolumeRBMI.setMnemonic('c');
      isoVolumeRBMI.addActionListener(new IsochoricHandler());
      jm4.add(isoVolumeRBMI);
      
      fracSolids = false;
      fracSolRBMI = new JCheckBoxMenuItem("Fractionate Solids");	
      fracSolRBMI.setMnemonic('F'); 
      fracSolRBMI.addActionListener(new FracSolidsHandler());
      jm4.add(fracSolRBMI);
      
      fracLiquids = false;
      fracLiqRBMI = new JCheckBoxMenuItem("Fractionate Liquids");
      fracLiqRBMI.setMnemonic('r'); 
      fracLiqRBMI.addActionListener(new FracLiquidHandler());
      jm4.add(fracLiqRBMI);
      
      mulLiqRBMI = new JCheckBoxMenuItem("Allow Multiple Liquids");
      mulLiqRBMI.addActionListener(new MultLiquidsHandler());
      jm4.add(mulLiqRBMI);

      JMenuItem item4g = new JMenuItem("Assimilant ...");
                item4g.setMnemonic('A'); 
      AssimHandler handler4g = new AssimHandler(rockRef);
                item4g.addActionListener(handler4g);
      jm4.add(item4g);
      
      JMenuItem item4h = new JMenuItem("Solid Phases ...");
                item4h.setMnemonic('S'); 
		item4h.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK));
      phaseDialog = new PhaseHandler(rockRef);
      item4h.addActionListener(phaseDialog); 
      jm4.add(item4h);
    
    mb.add(jm4);
    
    mPanel.add(mb);
    addComponent(cp, mPanel, 0, 0, 3, 1, GridBagConstraints.BOTH);
    
    //****************************************
    //----------------------------------------
    // GUI elements of the main window display
    //****************************************
  
    Border etchedBdr = BorderFactory.createEtchedBorder();

    //***********************
    // Bulk Composition Panel

    JPanel panel1  = new JPanel(); 
           panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
           panel1.setBorder(etchedBdr);
	   
      JPanel panel1a = new JPanel(); 
             panel1a.setLayout(new GridLayout(0, 2));
	     panel1a.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      JPanel panel1b = new JPanel(); 
             panel1b.setLayout(new BorderLayout());
	     panel1b.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
          
      NumberFormat bcFormat = NumberFormat.getNumberInstance(); 
                   bcFormat.setMaximumFractionDigits(3);
                   bcFormat.setMinimumFractionDigits(3);
      TextHandler bcHandler = new TextHandler();
      
      String[] s2;
      // ORB Call
      try {
        nc = (rockRef != null) ? (int) rockRef.getNcomp() : 1;
	s2 = new String[nc];
        for (int i=0; i<nc; i++) s2[i] = (rockRef != null) ? rockRef.getCompName((short) i) : "No ORB";
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
	  "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
	nc = 1;
	s2 = new String[nc];
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
	  "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
	nc = 1;
	s2 = new String[nc];
      }
      // End ORB Call
        
      JLabel[] label1   = new JLabel[nc];
      JLabel[] label2   = new JLabel[nc];
      JLabel   label3   = new JLabel("grams");
      JLabel   label3a  = new JLabel();
               bcEntry  = new JFormattedTextField[nc];
	       bulkComp = new double[nc];
      if (nc == 1) bulkComp[ 0] = 0.00;
      else {
        bulkComp[ 0] = 48.68; bulkComp[ 1] =  1.01; bulkComp[ 2] = 17.64; bulkComp[ 3] =  0.89; bulkComp[ 4] =  0.0425;  
        bulkComp[ 5] =  7.59; bulkComp[ 6] =  0.00; bulkComp[ 7] =  9.10; bulkComp[ 8] =  0.00; bulkComp[ 9] =  0.00; 
        bulkComp[10] = 12.45; bulkComp[11] =  2.65; bulkComp[12] =  0.03; bulkComp[13] =  0.08; bulkComp[14] =  0.20;
        bulkComp[15] =  0.00; bulkComp[16] =  0.00; bulkComp[17] =  0.00; bulkComp[18] =  0.00;
      }
        
      panel1a.add(label3a);
      panel1a.add(label3);
      
      for (int j=0; j<nc; j++) {
        panel1a.add(label1[j] = new JLabel(Melts.makeSubscript(s2[j])));
	
	bcEntry[j] = new JFormattedTextField(bcFormat); 
	bcEntry[j].setColumns(7); 
	bcEntry[j].addPropertyChangeListener(bcHandler);
	bcEntry[j].setValue(new Double(bulkComp[j])); 
	bcEntry[j].setEditable(true);
	bcEntry[j].setHorizontalAlignment(JTextField.RIGHT);

        panel1a.add(bcEntry[j]);
      }
      try {
        if (rockRef != null) rockRef.setBulkCompW(bulkComp);
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
	  "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
	  "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      }
      
      JLabel bLabel = new JLabel("Bulk System");
      panel1b.add(bLabel, BorderLayout.SOUTH);
      
    panel1.add(panel1a);
    panel1.add(panel1b);
    
    addComponent(cp, panel1, 0, 1, 1, 4, GridBagConstraints.VERTICAL);
    
    //************************
    // Phase composition Panel
    
    JPanel panel2  = new JPanel();
           panel2.setLayout(new BoxLayout(panel2, BoxLayout.Y_AXIS));
           panel2.setBorder(etchedBdr);
	   
      JPanel panel2a = new JPanel();
             panel2a.setLayout(new GridLayout(0, 2));
	     panel2a.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
      JPanel panel2b = new JPanel();
             panel2b.setLayout(new FlowLayout());
      JPanel panel2c = new JPanel();
             panel2c.setLayout(new BorderLayout());
      
      JLabel label4  = new JLabel("wt% (ppm)");
      JLabel label4a = new JLabel();
      
      panel2a.add(label4a);
      panel2a.add(label4);
      
      ppEntry = new JFormattedTextField[nc];
      NumberFormat ppFormat = NumberFormat.getNumberInstance(); 
                   ppFormat.setMaximumFractionDigits(3);
                   ppFormat.setMinimumFractionDigits(3);
		   
      for (int j=0; j<nc; j++) {
        panel2a.add(label2[j] = new JLabel(Melts.makeSubscript(s2[j])));
	
	ppEntry[j] = new JFormattedTextField(ppFormat); 
	ppEntry[j].setColumns(7); 
	ppEntry[j].setValue(new Double(0.0)); 
	ppEntry[j].setEditable(false);
	ppEntry[j].setHorizontalAlignment(JTextField.RIGHT);

        panel2a.add(ppEntry[j]);    
      }
  
      JLabel phLabel = new JLabel("Phase: "); panel2b.add(phLabel);
      
      phasePopupMenu = new JComboBox(); 
      phasePopupMenu.addItem("None"); 
      phasePopupMenu.setPrototypeDisplayValue("ABCDEFGHIJ"); // length of a 20-character phase name
      PhasePopupHandler phasePopupMenuHandler = new PhasePopupHandler();
                phasePopupMenu.addActionListener(phasePopupMenuHandler);
      panel2b.add(phasePopupMenu);
      
      panel2c.add(panel2b, BorderLayout.SOUTH);
    panel2.add(panel2a);
    panel2.add(panel2c);
    
    addComponent(cp, panel2, 1, 1,1, 4, GridBagConstraints.VERTICAL);
    
    //************************
    // System Properties Panel
    
    JPanel panel3 = new JPanel(); 
           panel3.setLayout(new GridLayout(0, 2, 5, 5)); 
	   panel3.setBorder(etchedBdr);
    
      JPanel panel3a = new JPanel(); 
             panel3a.setLayout(new GridLayout(0, 2, 6, 6));
	     panel3a.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

        NumberFormat tFormat = NumberFormat.getNumberInstance(); 
                     tFormat.setMaximumFractionDigits(2);
                     tFormat.setMinimumFractionDigits(2);
        NumberFormat pFormat = NumberFormat.getNumberInstance(); 
                     pFormat.setMaximumFractionDigits(3);
                     pFormat.setMinimumFractionDigits(3);
        NumberFormat fO2Format = NumberFormat.getNumberInstance(); 
                     fO2Format.setMaximumFractionDigits(3);
                     fO2Format.setMinimumFractionDigits(3);

        JLabel sL     = new JLabel("System Properties: ");    panel3a.add(sL);
        JLabel sL1    = new JLabel();			      panel3a.add(sL1); 
        JLabel tLabel = new JLabel("T (" + "\u00B0" + "C): "); panel3a.add(tLabel);
        
        tEntry = new JFormattedTextField(tFormat);      
        tEntry.setEditable(false); 
	tEntry.setColumns(7); 
	tEntry.setValue(new Double(1200.0)); 
	tEntry.setHorizontalAlignment(JTextField.RIGHT);
        panel3a.add(tEntry);
	try {
	  if (rockRef != null) rockRef.setTk(1473.15);
        } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        }
      	  	   
        JLabel pLabel = new JLabel("P (GPa)"); panel3a.add(pLabel);
        
        pEntry = new JFormattedTextField(pFormat);      
        pEntry.setEditable(false); 
	pEntry.setColumns(7); 
	pEntry.setValue(new Double(0.1)); 
	pEntry.setHorizontalAlignment(JTextField.RIGHT);
        panel3a.add(pEntry);
	try {
  	  if (rockRef !=  null) rockRef.setPa(1.0e8);
        } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        }
              
        JPanel panel3a1 = new JPanel(); 
	       panel3a1.setLayout(new FlowLayout(FlowLayout.LEFT));
          JLabel fLabel = new JLabel("fO2"); panel3a1.add(fLabel);
	  	 
          JComboBox fCombo = new JComboBox();
          	    fCombo.addItem("log10");
          	    fCombo.addItem("\u2206" +"HM");
          	    fCombo.addItem("\u2206" +"NNO");
          	    fCombo.addItem("\u2206" +"QFM");
          	    fCombo.addItem("\u2206" +"C-COH");
          	    fCombo.addItem("\u2206" +"IW");
	  fO2DisplayHandler fComboHandler = new fO2DisplayHandler();
          	    fCombo.addActionListener(fComboHandler);
	  fO2DisplayMode = Melts.FO2_DISPLAY_NONE;
        panel3a1.add(fCombo);
        
        panel3a.add(panel3a1);
      
        fO2Entry = new JFormattedTextField(fO2Format);      
        fO2Entry.setEditable(false); 
        fO2Entry.setColumns(7); 
        fO2Entry.setValue(new Double(0.0)); 
        fO2Entry.setHorizontalAlignment(JTextField.RIGHT);
        panel3a.add(fO2Entry);
      
      JPanel panel3b = new JPanel(); 
             panel3b.setLayout(new GridLayout(0, 2, 6, 6));
	     panel3b.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
      
        int minimum = 0;
        int maximum = 100;
      
        JLabel lLabel = new JLabel("Liquid Mass Fraction:");											panel3b.add(lLabel);
        liqProgress = new JProgressBar(minimum, maximum); 
        liqProgress.setValue(100); 
        liqProgress.setStringPainted(true); 
      panel3b.add(liqProgress);
        JLabel solids = new JLabel("Solid Mass Fraction:");										      panel3b.add(solids);
        solProgress = new JProgressBar(minimum, maximum);
	solProgress.setStringPainted(true); 
      panel3b.add(solProgress);
        JLabel aLabel = new JLabel("Assimilant Mass Added:"); 									      panel3b.add(aLabel);
        assimProgress = new JProgressBar(minimum, maximum);
	assimProgress.setStringPainted(true); 
      panel3b.add(assimProgress);
        JLabel frLabel = new JLabel("Mass Fractionated:");									      panel3b.add(frLabel);
        fracProgress = new JProgressBar(minimum, maximum);
	fracProgress.setStringPainted(true); 
    panel3b.add(fracProgress);
    
    panel3.add(panel3a);
    panel3.add(panel3b);
    
    addComponent(cp, panel3, 2, 1, 1, 1, GridBagConstraints.BOTH);

    //*************
    // Status Panel
    
    JPanel panel4 = new JPanel();
           panel4.setLayout(new GridLayout(0, 2, 5, 5));
           panel4.setBorder(etchedBdr);
    NumberFormat intFormat = NumberFormat.getNumberInstance(); 

      JPanel panel4a = new JPanel(); 
             panel4a.setLayout(new GridLayout(0, 2, 6, 6));
	     panel4a.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
      
      JLabel cLabel = new JLabel("Status of Calculation:"); panel4a.add(cLabel);
      JLabel cL     = new JLabel();			    panel4a.add(cL);
      JLabel iLabel = new JLabel("Calls to server: ");	    panel4a.add(iLabel);
        iterEntry = new JFormattedTextField(intFormat);     
        iterEntry.setEditable(false); 
        iterEntry.setColumns(6); 
        iterEntry.setValue(new Integer(0)); 
        iterEntry.setHorizontalAlignment(JTextField.RIGHT);
        panel4a.add(iterEntry);
      JLabel qLabel = new JLabel("   Quadratic Iters:");
        panel4a.add(qLabel);
        quadEntry = new JFormattedTextField(intFormat);     
        quadEntry.setEditable(false); 
        quadEntry.setColumns(6); 
        quadEntry.setValue(new Integer(0)); 
        quadEntry.setHorizontalAlignment(JTextField.RIGHT);
        panel4a.add(quadEntry);
      JLabel nLabel = new JLabel("   Linear Iters: ");		    panel4a.add(nLabel);
        linEntry = new JFormattedTextField(intFormat);      
        linEntry.setEditable(false); 
        linEntry.setColumns(6); 
        linEntry.setValue(new Integer(0)); 
        linEntry.setHorizontalAlignment(JTextField.RIGHT);
        panel4a.add(linEntry);
  
      JPanel panel4b = new JPanel(); 
             panel4b.setLayout(new GridLayout(0, 4));
	     panel4b.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

      JRadioButton rb1  = new JRadioButton("Wait");    panel4b.add(rb1);  rb1.setEnabled(false); 
      JRadioButton rb2  = new JRadioButton("Blk Cmp"); panel4b.add(rb2);  rb2.setEnabled(false);
      JRadioButton rb3  = new JRadioButton("T/P");     panel4b.add(rb3);  rb3.setEnabled(false);
      JRadioButton rb4  = new JRadioButton("Satn Ck"); panel4b.add(rb4);  rb4.setEnabled(false);
      JRadioButton rb5  = new JRadioButton("Add Ph");  panel4b.add(rb5);  rb5.setEnabled(false);
      JRadioButton rb6  = new JRadioButton("Proj");    panel4b.add(rb6);  rb6.setEnabled(false);
      JRadioButton rb7  = new JRadioButton("Pre-Q");   panel4b.add(rb7);  rb7.setEnabled(false);
      JRadioButton rb8  = new JRadioButton("Con-Q");   panel4b.add(rb8);  rb8.setEnabled(false);
      JRadioButton rb9  = new JRadioButton("Quad");    panel4b.add(rb9);  rb9.setEnabled(false);
      JRadioButton rb10 = new JRadioButton("Soln");    panel4b.add(rb10); rb10.setEnabled(false);
      JRadioButton rb11 = new JRadioButton("Linear");  panel4b.add(rb11); rb11.setEnabled(false);
      JRadioButton rb12 = new JRadioButton("Satn Ck"); panel4b.add(rb12); rb12.setEnabled(false);
      JRadioButton rb13 = new JRadioButton("Conv");    panel4b.add(rb13); rb13.setEnabled(false);
      JRadioButton rb14 = new JRadioButton("Verify");  panel4b.add(rb14); rb14.setEnabled(false);
      JRadioButton rb15 = new JRadioButton("Output");  panel4b.add(rb15); rb15.setEnabled(false);
      JRadioButton rb16 = new JRadioButton("Update");  panel4b.add(rb16); rb16.setEnabled(false);
      
      ButtonGroup g = new ButtonGroup();
      g.add(rb1);  g.add(rb2);  g.add(rb3);  g.add(rb4);  g.add(rb5);  g.add(rb6);  g.add(rb7);  g.add(rb8);  
      g.add(rb9);  g.add(rb10); g.add(rb11); g.add(rb12); g.add(rb13); g.add(rb14); g.add(rb15); g.add(rb16);
      
    panel4.add(panel4a);
    panel4.add(panel4b);
    
    addComponent(cp, panel4, 2, 2, 1, 1, GridBagConstraints.BOTH);

    //*************
    // Output Panel

    JPanel panel5 = new JPanel();
           panel5.setLayout(new BorderLayout());
           panel5.setBorder(BorderFactory.createTitledBorder(etchedBdr, "Error Message and Status Display:",
	                    TitledBorder.LEADING, TitledBorder.BELOW_TOP));
    
    statusDisplay = new JTextArea("Waiting for user input ...\n", 5, 1);
    statusDisplay.setEditable(false);
    JScrollPane pane  = new JScrollPane(statusDisplay);
    panel5.add(pane);
    
    addComponent(cp, panel5, 2, 3, 1, 1, GridBagConstraints.BOTH);
    
    //*********************
    // Launch Options Panel

    JPanel panel6 = new JPanel();
    panel6.setLayout(new FlowLayout());
    panel6.setBorder(BorderFactory.createTitledBorder(etchedBdr, "Click on Icon to Launch Option:",
                     TitledBorder.LEADING, TitledBorder.BELOW_TOP));
    
    LaunchHandler handler16 = new LaunchHandler();
    
    URL url1 = Melts.class.getResource("images/xmgr_icon.gif"); ImageIcon icon1 = new ImageIcon(url1); 
    JButton button1 = new JButton(icon1);
            button1.setActionCommand("Graphics");
	    button1.addActionListener(handler16);
	    button1.setToolTipText("Click to launch a graphics display window.");
    panel6.add(button1);
    String htmlLabel1 = "<html>Graphics<br>Display<br>Window</html>"; JLabel iL1 = new JLabel(htmlLabel1); 
    panel6.add(iL1);
    
    URL url2 = Melts.class.getResource("images/graph_icon.gif"); ImageIcon icon2 = new ImageIcon(url2); 
    JButton button2 = new JButton(icon2); 
            button2.setActionCommand("Options");
	    button2.addActionListener(handler16);
	    button2.setToolTipText("Click to launch a graphics display options dialog.");
    panel6.add(button2);
    String htmlLabel2 = "<html>Graphics<br>Options<br>Dialog</html>"; JLabel iL2 = new JLabel(htmlLabel2); 
    panel6.add(iL2);
    
    URL url3 = Melts.class.getResource("images/calculator_icon.gif"); ImageIcon icon3 = new ImageIcon(url3); 
    JButton button3 = new JButton(icon3);
            button3.setActionCommand("Calculator");
	    button3.addActionListener(handler16);
	    button3.setToolTipText("Click to launch a Phase Properties calculator.");
    panel6.add(button3);
    String htmlLabel3 = "<html>Supplemental<br>Calculator</html>"; JLabel iL3 = new JLabel(htmlLabel3); 
    panel6.add(iL3);
    
    URL url4 = Melts.class.getResource("images/terminal_icon.gif"); ImageIcon icon4 = new ImageIcon(url4); 
    JButton button4 = new JButton(icon4); 
            button4.setActionCommand("Output");
	    button4.addActionListener(handler16);
	    button4.setToolTipText("Click to generate an Excel" + "\u2122" + " compatible output file.");
    panel6.add(button4);
    String htmlLabel4 = "<html>View<br>Output<br>File</html>"; JLabel iL4 = new JLabel(htmlLabel4); 
    panel6.add(iL4);
    
    addComponent(cp, panel6, 2, 4, 1, 1, GridBagConstraints.BOTH);
    
    //******************************
    // Detail Phase Properties Panel
    
    JPanel panel7  = new JPanel(); 
           panel7.setBorder(etchedBdr); 	   
	   panel7.setLayout(new GridLayout(0, 2));

      JPanel panel7a = new JPanel();
             panel7a.setLayout(new FlowLayout(FlowLayout.LEFT));
      JLabel dLabel  = new JLabel("Double-click on phase name for physical properties display"); panel7a.add(dLabel);
      JPanel panel7b = new JPanel();
             panel7b.setLayout(new FlowLayout(FlowLayout.RIGHT));
      JLabel uLabel  = new JLabel("Phase units: "); panel7b.add(uLabel);
      
      String units[] ={"grams", "wt%", "vol%"}; 
      JComboBox punits = new JComboBox(units); 
      UnitDisplayHandler punitsHandler = new UnitDisplayHandler();
                punits.addActionListener(punitsHandler);
      panel7b.add(punits);
    
    panel7.add(panel7a);
    panel7.add(panel7b);
    addComponent(cp, panel7, 0, 5, 3, 1, GridBagConstraints.BOTH);
    	
    pTableModel = new PhaseTableModel();
    updatePT    = new UpdatePhaseTable(rockRef, pTableModel, phasePopupMenu);
    
    JTable pTable = new JTable(pTableModel);
           pTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    ListSelectionModel rowSM = pTable.getSelectionModel();
    rowSM.addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        ListSelectionModel lsm = (ListSelectionModel) e.getSource();
	if (lsm.isSelectionEmpty()) {
	  System.out.println("No rows selected.");
	} else {
	  ptSelectedRow = lsm.getMinSelectionIndex();
	}
      }
    });
    pTable.setCellSelectionEnabled(true);
    ListSelectionModel colSM = pTable.getColumnModel().getSelectionModel();
    colSM.addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        ListSelectionModel lsm = (ListSelectionModel) e.getSource();
	if (lsm.isSelectionEmpty()) {
	  System.out.println("No columns selected.");
	} else {
	  ptSelectedCol = lsm.getMinSelectionIndex();
	}
      }
    });
    pTable.addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
	if (e.getClickCount() > 1 && ptSelectedCol == 0) {
	  String name = (String) pTableModel.getValueAt(ptSelectedRow, ptSelectedCol);
	  PhasePropertiesDialog ppDialog = new PhasePropertiesDialog(rockRef, name);
	}
      }
    });
    
    pTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
    pTable.setPreferredScrollableViewportSize(new Dimension(1000,100));
    JPanel panel7c = new JPanel();
           panel7c.setLayout(new BorderLayout());
    int h = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS;
    int v = ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS;
    JScrollPane pane1 = new JScrollPane(pTable, v, h);
                pane1.setBorder(etchedBdr);
	   panel7c.add(pane1);
	   panel7c.setBorder(BorderFactory.createEmptyBorder(5, 0, 5, 0));
    
    addComponent(cp, panel7c, 0, 6, 3, 1, GridBagConstraints.BOTH);
  
    //**********************************************************************
    // A file that holds run results will be created in the FindLiquidus and
    // Equilibrate ActionListener Handlers defined below
    //**********************************************************************
    
    mOutput = new MeltsOutput();
  
    //************************************
    // Realize the applet and set its size
    //************************************
  
    cp.add(applet);
    frame.setSize(1024, 768);
    frame.setLocation(50, 50);
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
  }

  //*********************
  // Class public methods
  //*********************
  
  /**
   * Gets property from Applet manager or from the system.
   * @param key Property label.
   * @param def Property definition
   * @return Value of the specified property.
   */
  public String getParameter(String key, String def) {
    return isStandalone ? System.getProperty(key, def) 
                        : (getParameter(key) != null ? getParameter(key) : def);
  }
  
  /**
   * Applet method.
   * @return null.
   */
  public String[][] getParameterInfo() {
    return null;
  }
  
  /**
   * Applet method.
   * @return String with brief description of the applet.
   */
  public String getAppletInfo() {
    return "MELTS/pMELTS CORBA client. v.0.8, August 2007";
  }
  
  /**
   * Applet method.
   */
  public void start() { 
    System.out.println("The applet start method has been called!");
  }
  
  /**
   * Applet method.
   */
  public void stop() { 
    System.out.println("The applet stop method has been called!");
  }
  
  /**
   * Applet method. Server-side reference to rock object is removed.  Local reference is set to null.
   */
  public void destroy() {
    System.out.println("The applet destroy method has been called!");
    try {
      if (rockRef != null) { rockRef.remove(); rockRef = null; }
    } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
      rockRef = null;
    } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
      rockRef = null;
    }
  }
  
  /**
   * Method to invoke an instance of the class as a standalone application.  
   * Both the applet init() and start() methods are called.
   * @param args String array of command line arguments, which are passed to class initializer.
   */
  public static void main(String[] args) {
    Melts applet = new Melts(args);
    applet.init();
    applet.start();
  }
 
  //**********************
  // Class private methods
  //**********************
  
  private void addComponent(Container container, Component component, int gx, int gy, int gw, int gh, int fill){
    GridBagConstraints gbc = new GridBagConstraints();
    gbc.gridx      = gx;
    gbc.gridy      = gy;
    gbc.gridwidth  = gw;
    gbc.gridheight = gh;
    gbc.fill       = fill;
    container.add(component, gbc);
  }
  
  //*************************************
  // actionListeners for the Command Menu
  //*************************************
   
  private class FindLiquidusHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
      if (rockRef != null) {      
        try {
          Melts.printStatus("Calling findRockLiquidus server function...");
          int result = (int) rockRef.findRockLiquidus();
	  Melts.printStatus("...Returning from findRockLiquidus with status: " + result);
	  if (findRockLiquidusStatus.from_int(result) == findRockLiquidusStatus.frl_success) 
	    Melts.printStatus("...Calculation successful.");
	  else {
	    if (findRockLiquidusStatus.from_int(result) == findRockLiquidusStatus.frl_max_t)   
	      Melts.printStatus("...Calculation unsuccessful. Maximum temperature exceeded. Repose Problem.");
	    if (findRockLiquidusStatus.from_int(result) == findRockLiquidusStatus.frl_min_t)   
	      Melts.printStatus("...Calculation unsuccessful. Minimum temperature reached. Repose Problem.");
	    if (findRockLiquidusStatus.from_int(result) == findRockLiquidusStatus.frl_time)    
	      Melts.printStatus("...Calculation unsuccessful. Time limit exceeded. Repose Problem.");
	    JOptionPane.showMessageDialog(frame, "Find Rock Liquidus method returned an error.",
	      "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
	  }
	  Melts.printStatus("...Temperature is " + rockRef.getTk() + " K");
	
	  tEntry.setValue(new Double(rockRef.getTk()-273.15));
	  pEntry.setValue(new Double(rockRef.getPa()/1.0e9));
  	
  	  if	  (fO2DisplayMode == FO2_DISPLAY_NONE) fO2Entry.setValue(new Double(rockRef.getlogfo2())); 
  	  else if (fO2DisplayMode == FO2_DISPLAY_HM)   fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_hm))); 
  	  else if (fO2DisplayMode == FO2_DISPLAY_NNO)  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_nno))); 
  	  else if (fO2DisplayMode == FO2_DISPLAY_QFM)  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_qfm))); 
  	  else if (fO2DisplayMode == FO2_DISPLAY_CCOH) fO2Entry.setValue(new Double(rockRef.getlogfo2())); 
  	  else if (fO2DisplayMode == FO2_DISPLAY_IW)   fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_iw))); 

          updatePT.update();	
	  mOutput.putResultsToOutputFile();

        } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        }
      } else Melts.printStatus("No ORB. Cannot contact server.");       
    }
  }

  private class EquilibrateHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
      if (rockRef != null) {
      
        final SwingWorker worker = new SwingWorker() {
	  public java.lang.Object construct() {
            boolean loop = false;
	    boolean up = false;
	    if      ( isenthalpic && (tphsvDialog.hStopVal > tphsvDialog.hStartVal) ) up = true;
	    else if ( isentropic  && (tphsvDialog.sStopVal > tphsvDialog.sStartVal) ) up = true;
	    else if ( isochoric   && (tphsvDialog.vStopVal > tphsvDialog.vStartVal) ) up = true;
	    else if (                 tphsvDialog.tStopVal > tphsvDialog.tStartVal  ) up = true;
	    
      
            do {  // loop on t, p, h, s, v
	      try {
                Melts.printStatus("Calling equalibrateRock server function...");
                int result = (int) rockRef.equilibrateRock();
	        Melts.printStatus("...Returning from equilibrateRock with status: " + result);
	        if (equilibrateStatus.from_int(result) == equilibrateStatus.equil_success) 
	  	  Melts.printStatus("...Calculation successful.");
	        else {
	  	  if (equilibrateStatus.from_int(result) == equilibrateStatus.equil_quad_max)   
	  	    Melts.printStatus("...Calculation unsuccessful. Quadratic iteration limit exceeded. Repose Problem.");
	  	  if (equilibrateStatus.from_int(result) == equilibrateStatus.equil_lin_zero)   
	  	    Melts.printStatus("...Calculation unsuccessful. Linear search iteration limit exceeded. Repose Problem.");
	  	  if (equilibrateStatus.from_int(result) == equilibrateStatus.equil_time)    
	  	    Melts.printStatus("...Calculation unsuccessful. Time limit exceeded. Repose Problem.");
	  	  JOptionPane.showMessageDialog(frame, "Equilibrate Rock method returned an error.",
	  	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
		  return (java.lang.Object) null;
	        }
	      
	        tEntry.setValue(new Double(rockRef.getTk()-273.15));
	        pEntry.setValue(new Double(rockRef.getPa()/1.0e9));
  	  	
  	        if      (fO2DisplayMode == FO2_DISPLAY_NONE) fO2Entry.setValue(new Double(rockRef.getlogfo2())); 
  	        else if (fO2DisplayMode == FO2_DISPLAY_HM)   fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_hm))); 
  	        else if (fO2DisplayMode == FO2_DISPLAY_NNO)  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_nno))); 
  	        else if (fO2DisplayMode == FO2_DISPLAY_QFM)  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_qfm))); 
  	        else if (fO2DisplayMode == FO2_DISPLAY_CCOH) fO2Entry.setValue(new Double(rockRef.getlogfo2())); 
  	        else if (fO2DisplayMode == FO2_DISPLAY_IW)   fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_iw))); 

                updatePT.update();
	        mOutput.putResultsToOutputFile();
	        
	        if (fracSolids) {
	          rockRef.fractionateSolids(0.99);
                  Melts.printStatus("...99% of solids fractionated from the system.");
	      	  doServerUpdates = false;
	      	  double wtBulk[] = new double[nc];
	      	  wtBulk = rockRef.getBulkCompW();
	      	  for (int i=0; i<nc; i++) bcEntry[i].setValue(new Double(wtBulk[i]));
	      	  doServerUpdates = true;
	        }
	        
	        if (isenthalpic) {
	      	  if	  ( up && (tphsvDialog.hStopVal <= tphsvDialog.hStartVal)) loop = false;
	      	  else if (!up && (tphsvDialog.hStopVal >= tphsvDialog.hStartVal)) loop = false;
	      	  else {
	      	    if (up) tphsvDialog.hStartVal +=  Math.abs(tphsvDialog.hIncVal);
	      	    else    tphsvDialog.hStartVal += -Math.abs(tphsvDialog.hIncVal);
	      	    rockRef.setEnthalpy(tphsvDialog.hStartVal*1000.0);
	      	    loop = true;
	      	  }
	        } else if (isentropic)  {
	      	  if	  ( up && (tphsvDialog.sStopVal <= tphsvDialog.sStartVal)) loop = false;
	      	  else if (!up && (tphsvDialog.sStopVal >= tphsvDialog.sStartVal)) loop = false;
	      	  else {
	      	    if (up) tphsvDialog.sStartVal +=  Math.abs(tphsvDialog.sIncVal);
	      	    else    tphsvDialog.sStartVal += -Math.abs(tphsvDialog.sIncVal);
	      	    rockRef.setEntropy(tphsvDialog.sStartVal);
	      	    loop = true;
	      	  }
	        } else if (isochoric)	{
	      	  if	  ( up && (tphsvDialog.vStopVal <= tphsvDialog.vStartVal)) loop = false;
	      	  else if (!up && (tphsvDialog.vStopVal >= tphsvDialog.vStartVal)) loop = false;
	      	  else {
	      	    if (up) tphsvDialog.vStartVal +=  Math.abs(tphsvDialog.vIncVal);
	      	    else    tphsvDialog.vStartVal += -Math.abs(tphsvDialog.vIncVal);
	      	    rockRef.setVolume(tphsvDialog.vStartVal/1.0e6);
	      	    loop = true;
	      	  }
	        } else  		{
	      	  if	  ( up && (tphsvDialog.tStopVal <= tphsvDialog.tStartVal)) loop = false;
	      	  else if (!up && (tphsvDialog.tStopVal >= tphsvDialog.tStartVal)) loop = false;
	      	  else {
	      	    if (up) tphsvDialog.tStartVal +=  Math.abs(tphsvDialog.tIncVal);
	      	    else    tphsvDialog.tStartVal += -Math.abs(tphsvDialog.tIncVal);
	      	    rockRef.setTk(tphsvDialog.tStartVal+273.15);
	      	    loop = true;
	      	  }
	        }
              } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
          	JOptionPane.showMessageDialog(null, 
          	  "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	  	  "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
                loop = false;
              } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
          	JOptionPane.showMessageDialog(null, 
          	  "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	  	  "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
                loop = false;
              }
	    } while (loop);
	
	    return (java.lang.Object) null;
	  }
	};
	worker.start();
	
      } else Melts.printStatus("No ORB. Cannot contact server.");       
    }
  }

  private class OpenHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
      if (rockRef == null) {
        JOptionPane.showMessageDialog(frame, "Cannot process file. No contact with server.",
	    "ORB Not Found Exception", JOptionPane.ERROR_MESSAGE);
	return;
      }
      openSaveDialog.addChoosableFileFilter(new MeltsFileFilter());      
      int returnValue = openSaveDialog.showOpenDialog(frame);
      if (returnValue == JFileChooser.APPROVE_OPTION) {
        File inputFile = openSaveDialog.getSelectedFile();
        Melts.printStatus("Trying to open: " + inputFile.getName() + ".");
	try {
	  BufferedReader br = new BufferedReader(new FileReader(inputFile));
	  boolean hasContent = true;
	  
	  // it would be best to reset all system properties at this point
	  // keep track of which bulkcomposition oxides were initialized 
	  boolean setOxide[] = new boolean[nc]; for (int i=0; i<nc; i++) { setOxide[i] = false; }
	  
          Melts.printStatus("Reading file: " + inputFile.getName() + ".");
	  do {
	    try {
  	      String line = br.readLine();
	      if (line == null) {
	        hasContent = false;
                Melts.printStatus("Closing file: " + inputFile.getName() + ".");
		br.close();
	      } else {
	        Melts.printStatus("...line: " + line);
		String[] token = line.toLowerCase().trim().split(":"); 
		
		try {
		  if	    (token[0].equals("title")) {
		  } else if (token[0].equals("initial composition")) {
		    // formula value
		    String[] identity = token[1].trim().split(" ");
		    int i;
		    for (i=0; i<nc; i++) if (identity[0].equalsIgnoreCase(rockRef.getCompName((short) i))) break;
		    // potential array out-of-bounds exception dealt with below
		    bcEntry[i].setValue(new Double(identity[1]));
		    setOxide[i] = true;
		  } else if (token[0].equals("initial temperature")) {
		    Double value = new Double(token[1]);
		    tEntry.setValue(value);
		    tphsvDialog.tStartFTF.setValue(value);
		  } else if (token[0].equals("final temperature")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.tStopFTF.setValue(value);
		  } else if (token[0].equals("increment temperature")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.tIncFTF.setValue(value);
		  } else if (token[0].equals("initial pressure")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.pStartFTF.setValue(new Double(value.doubleValue()/10000.0));
		  } else if (token[0].equals("final pressure")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.pStopFTF.setValue(new Double(value.doubleValue()/10000.0));
		  } else if (token[0].equals("increment pressure")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.pIncFTF.setValue(new Double(value.doubleValue()/10000.0));
		  } else if (token[0].equals("dp/dt")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.dpdtFTF.setValue(new Double(value.doubleValue()/10000.0));
		  } else if (token[0].equals("increment enthalpy")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.hIncFTF.setValue(new Double(value.doubleValue()/1000.0));
		  } else if (token[0].equals("increment entropy")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.sIncFTF.setValue(value);
		  } else if (token[0].equals("increment volume")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.vIncFTF.setValue(value);
		  } else if (token[0].equals("dp/dh")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.dpdhFTF.setValue(new Double(value.doubleValue()/10.0));
		  } else if (token[0].equals("dp/ds")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.dpdsFTF.setValue(new Double(value.doubleValue()/10000.0));
		  } else if (token[0].equals("dt/dv")) {
		    Double value = new Double(token[1]);
		    tphsvDialog.dtdvFTF.setValue(value);
		  } else if (token[0].equals("log fo2 path")) {
		    // DO NOT change this indexing without re-indexing the fO2Choice array abbove
		    String path = token[1].trim();
		    if      (path.equals("none" )) { fO2Choice[ 0].doClick(); } 
		    else if (path.equals("hm"   )) { fO2Choice[ 1].doClick(); }
		    else if (path.equals("nno"  )) { fO2Choice[ 2].doClick(); }
		    else if (path.equals("fmq"  )) { fO2Choice[ 3].doClick(); }
		    else if (path.equals("coh"  )) { fO2Choice[ 4].doClick(); }
		    else if (path.equals("iw"   )) { fO2Choice[ 5].doClick(); }
		    else if (path.equals("+3fmq")) { fO2Choice[ 6].doClick(); }
		    else if (path.equals("+2fmq")) { fO2Choice[ 7].doClick(); }
		    else if (path.equals("+1fmq")) { fO2Choice[ 8].doClick(); }
		    else if (path.equals("-1fmq")) { fO2Choice[ 9].doClick(); }
		    else if (path.equals("-2fmq")) { fO2Choice[10].doClick(); }
		    else if (path.equals("-3fmq")) { fO2Choice[11].doClick(); }
		    else if (path.equals("-4fmq")) { fO2Choice[12].doClick(); }
		    else if (path.equals("-5fmq")) { fO2Choice[13].doClick(); }
		    else if (path.equals("-6fmq")) { fO2Choice[14].doClick(); }
		    else if (path.equals("-7fmq")) { fO2Choice[15].doClick(); }
		    else if (path.equals("-8fmq")) { fO2Choice[16].doClick(); }
		    else if (path.equals("-9fmq")) { fO2Choice[17].doClick(); }
		  } else if (token[0].equals("suppress")) {
		    short n = rockRef.getPhaseNo(token[1].toLowerCase().trim());
		    if (n < 0) {
                      hasContent = false;
	              JOptionPane.showMessageDialog(frame, "Suppressed phase <" + 
		      token[1].toLowerCase().trim() + "> not found. Corrupt input file.",
	                "I/O Exception", JOptionPane.ERROR_MESSAGE);
		      br.close();		    
		    } else phaseDialog.disablePhase(n);
		  } else if (token[0].equals("mode")) {
                    if      (token[1].toLowerCase().trim().equals("fractionate solids" ))     fracSolRBMI.doClick();
                    else if (token[1].toLowerCase().trim().equals("fractionate liquids"))     fracLiqRBMI.doClick();
                    else if (token[1].toLowerCase().trim().equals("multiple liquids"   ))      mulLiqRBMI.doClick();
                    else if (token[1].toLowerCase().trim().equals("isenthalpic"	       )) isoEnthalpyRBMI.doClick();
                    else if (token[1].toLowerCase().trim().equals("isentropic"	       ))  isoEntropyRBMI.doClick(); 
                    else if (token[1].toLowerCase().trim().equals("isochoric"	       ))   isoVolumeRBMI.doClick();   
		  } else if (token[0].equals("assimilant")) {
		    JOptionPane.showMessageDialog(frame, "Assimilant option not yet implemented. Input discarded.");
		    // <phase name>  % value 
		    // <component name of last phase> X value
		    // <oxide formula> value
		    String[] identity = token[1].trim().split(" ");
		    if      (identity[0].equals("units")) {}       // String [ "vol %" "wt %" ]
		    else if (identity[0].equals("temperature")) {} // value
		    else if (identity[0].equals("mass"))        {} // value
		    else if (identity[0].equals("increments"))  {} // value
		    else if (identity[0].equals("liquid mass")) {} // value
		    // <phase name>  % value 
		    // <component name of last phase> X value
		    // <oxide formula> value
		  } else {
		    hasContent = false;
	            JOptionPane.showMessageDialog(frame, "Unrecognizable input flag. Corrupt input file.",
	              "I/O Exception", JOptionPane.ERROR_MESSAGE);
		    br.close();
		  }
		} catch (ArrayIndexOutOfBoundsException aioobe) {
		  hasContent = false;
	          JOptionPane.showMessageDialog(frame, "Array index out of bounds. Corrupt input file.",
	            "I/O Exception", JOptionPane.ERROR_MESSAGE);
		  br.close();
		} catch (NumberFormatException nfe) {
		  hasContent = false;
	          JOptionPane.showMessageDialog(frame, "Number format invalid. Corrupt input file.",
	            "I/O Exception", JOptionPane.ERROR_MESSAGE);
		  br.close();
                } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
                  JOptionPane.showMessageDialog(null, 
                    "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	            "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
                } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
                  JOptionPane.showMessageDialog(null, 
                    "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	            "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
                }
	      }
	    } catch (IOException ioe) {
	      hasContent = false;
	      JOptionPane.showMessageDialog(frame, "Error on reading file " + inputFile.getName() + ".",
	        "I/O Exception", JOptionPane.ERROR_MESSAGE);
	    }
	  } while (hasContent);
	  
	  // zero bulkcomposition entries not explicitely set
	  for (int i=0; i<nc; i++) if(!setOxide[i]) bcEntry[i].setValue(new Double(0.0));
	} catch (FileNotFoundException fnfe) {
	  JOptionPane.showMessageDialog(frame, "Cannot open file " + inputFile.getName() + ".",
	    "File Not Found Exception", JOptionPane.ERROR_MESSAGE);
	} catch (SecurityException se) {
	  JOptionPane.showMessageDialog(frame, "Cannot open file " + inputFile.getName() + ".",
	    "Security Exception", JOptionPane.ERROR_MESSAGE);
	}
      }
    }
  }
  
  private class SaveHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
      JMenuItem source = (JMenuItem) e.getSource();
      String item = source.getText();
      int returnValue;
      
      if (rockRef == null) {
        JOptionPane.showMessageDialog(frame, "Cannot create file. No contact with server.",
	    "ORB Not Found Exception", JOptionPane.ERROR_MESSAGE);
	return;
      }
      
      if (item.equals("Save as...") || !hasSaveFile) { 
        openSaveDialog.addChoosableFileFilter(new MeltsFileFilter());      
        returnValue = openSaveDialog.showSaveDialog(frame);
	if (returnValue == JFileChooser.APPROVE_OPTION) {
	  saveFile    = openSaveDialog.getSelectedFile();
	  hasSaveFile = true;
	} 
      } else returnValue = JFileChooser.APPROVE_OPTION;
      
      if (returnValue == JFileChooser.APPROVE_OPTION) {
        Melts.printStatus("Trying to create: " + saveFile.getName() + ".");
	try {
	  PrintWriter pr = new PrintWriter(new BufferedWriter(new FileWriter(saveFile)), true);
          Melts.printStatus("Writing file: " + saveFile.getName() + ".");
	  
          pr.println("Title: " + "File created by MELTS/pMELTS CORBA client. v.0.8, August 2007.");

          /* -> initial composition record */
	  for (int i=0; i<nc; i++) 
            pr.println("Initial Composition: " + rockRef.getCompName((short) i) + " " + 
	      ((Number) bcEntry[i].getValue()).doubleValue());
	  
          pr.println( "Initial Temperature: "   + ((Number) tphsvDialog.tStartFTF.getValue()).doubleValue());
          pr.println( "Final Temperature: "     + ((Number) tphsvDialog.tStopFTF.getValue()).doubleValue());
          pr.println( "Increment Temperature: " + ((Number) tphsvDialog.tIncFTF.getValue()).doubleValue());
          pr.println( "Initial Pressure: "      + ((Number) tphsvDialog.pStartFTF.getValue()).doubleValue()*10000.0); // GPa -> bars
          pr.println( "Final Pressure: "        + ((Number) tphsvDialog.pStopFTF.getValue()).doubleValue()*10000.0);  // GPa -> bars
          pr.println( "Increment Pressure: "    + ((Number) tphsvDialog.pIncFTF.getValue()).doubleValue()*10000.0);   // GPa -> bars
          pr.println( "dp/dt: "                 + ((Number) tphsvDialog.dpdtFTF.getValue()).doubleValue()*10000.0);   // GPa/K -> bars/K
          pr.println( "Increment Enthalpy: "    + ((Number) tphsvDialog.hIncFTF.getValue()).doubleValue()*1000.0);    // kJ -> J
          pr.println( "dp/dH: "                 + ((Number) tphsvDialog.dpdhFTF.getValue()).doubleValue()*10.0);      // Gpa/kJ -> bars/J
          pr.println( "Increment Entropy: "     + ((Number) tphsvDialog.sIncFTF.getValue()).doubleValue());
          pr.println( "dp/dS: "                 + ((Number) tphsvDialog.dpdsFTF.getValue()).doubleValue()*10000.0);   // Gpa-K/J -> bars-K/J
          pr.println( "Increment Volume: "      + ((Number) tphsvDialog.vIncFTF.getValue()).doubleValue());
          pr.println( "dt/dV: "                 + ((Number) tphsvDialog.dtdvFTF.getValue()).doubleValue());


          pr.print( "log fo2 Path: ");
           // DO NOT change this indexing without re-indexing the fO2Choice array abbove
   	   if	   (fO2Choice[ 0].isSelected()) pr.println( "None");
   	   else if (fO2Choice[ 1].isSelected()) pr.println( "HM");
   	   else if (fO2Choice[ 2].isSelected()) pr.println( "NNO");
   	   else if (fO2Choice[ 3].isSelected()) pr.println( "FMQ");
   	   else if (fO2Choice[ 4].isSelected()) pr.println( "COH");
   	   else if (fO2Choice[ 5].isSelected()) pr.println( "IW");
   	   else if (fO2Choice[ 6].isSelected()) pr.println( "+3FMQ");
   	   else if (fO2Choice[ 7].isSelected()) pr.println( "+2FMQ");
   	   else if (fO2Choice[ 8].isSelected()) pr.println( "+1FMQ");
   	   else if (fO2Choice[ 9].isSelected()) pr.println( "-1FMQ");
   	   else if (fO2Choice[10].isSelected()) pr.println( "-2FMQ");
   	   else if (fO2Choice[11].isSelected()) pr.println( "-3FMQ");
   	   else if (fO2Choice[12].isSelected()) pr.println( "-4FMQ");
   	   else if (fO2Choice[13].isSelected()) pr.println( "-5FMQ");
   	   else if (fO2Choice[14].isSelected()) pr.println( "-6FMQ");
   	   else if (fO2Choice[15].isSelected()) pr.println( "-7FMQ");
   	   else if (fO2Choice[16].isSelected()) pr.println( "-8FMQ");
   	   else if (fO2Choice[17].isSelected()) pr.println( "-9FMQ");

           /* -> suppress a solid phase record */
	   for (short i=0; i<rockRef.getNSolPhases(); i++) 
	     if (!phaseDialog.getPhaseState(i)) pr.println( "Suppress: " + rockRef.getSolPhaseName(i));

   	   if (    fracSolRBMI.isSelected()) pr.println( "Mode: Fractionate Solids");
   	   if (    fracLiqRBMI.isSelected()) pr.println( "Mode: Fractionate Liquids");
   	   if (     mulLiqRBMI.isSelected()) pr.println( "Mode: Multiple Liquids");
   	   if (isoEnthalpyRBMI.isSelected()) pr.println( "Mode: Isenthalpic");
   	   if ( isoEntropyRBMI.isSelected()) pr.println( "Mode: Isentropic");
   	   if (  isoVolumeRBMI.isSelected()) pr.println( "Mode: Isochoric");

           /* -> assimilant phase record */
           if (false) {
     	     pr.println( "Assimilant: Temperature " + 0.0);
     	     pr.println( "Assimilant: Mass "        + 0.0); 
     	     pr.println( "Assimilant: Increments "  + 0.0);
     	     pr.println( "Assimilant: Liquid Mass " + 0.0);
     	     if      (false) pr.println( "Assimilant: Units Vol %");
     	     else if (true ) pr.println( "Assimilant: Units Wt %");

             // solids as phases
             pr.println( "Assimilant: " + "phase" + " " + 0.0);

             // solids/liquid as bulk
             pr.println( "Assimilant: " + "bulk oxide" + " " + 0.0);
           }
	   
	   pr.close();
	  
	} catch (IOException ioe) {
	  JOptionPane.showMessageDialog(frame, "Cannot create file " + saveFile.getName() + ".",
	    "I/O Exception", JOptionPane.ERROR_MESSAGE);
	} catch (SecurityException se) {
	  JOptionPane.showMessageDialog(frame, "Cannot create file " + saveFile.getName() + ".",
	    "Security Exception", JOptionPane.ERROR_MESSAGE);
        } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        }
      }
    }
  }
  
  private class ExitHandler implements ActionListener{
    public void actionPerformed(ActionEvent e){
      if (isStandalone) {
        try {
          if (rockRef != null) rockRef.remove();
        } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
        } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        }
        System.exit(0);
      } 
    }
  }

  //*****************************************
  // actionListeners for the Composition Menu
  //*****************************************
   
  private class RedoxHandler implements ActionListener{
    public void actionPerformed(ActionEvent ae){
      System.out.println("Entering the Redox ActionListener.");
      
      // TODO - Call the redox recalculation routine
      
    }
  }
  
  private class NormalizeHandler implements ActionListener {
    public void actionPerformed(ActionEvent e){
      System.out.println("Entering the Normalize ActionListener.");
      
      // TODO - Call the normalize recalculation routine
      
    }
  }
   
  //*************************************************
  // actionListeners for the Intensive Variables Menu
  //*************************************************

  // TPHandler implemented as a public class
     
  private class fO2Handler implements ActionListener{
    public void actionPerformed(ActionEvent e){
      JRadioButtonMenuItem source = (JRadioButtonMenuItem) e.getSource();
      java.lang.Object entry[] = source.getSelectedObjects();
      String item = (String) entry[0];
      Melts.printStatus("Oxygen fugacity constraint set to " + item);
      
      if (rockRef != null) {
        try {
          if	  (item.equals("Absent")   ) rockRef.setlogfo2(fO2Type.fo2_none, 0.0);
          else if (item.equals("Hm-Mt")    ) rockRef.setlogfo2(fO2Type.fo2_hm,   0.0);  
          else if (item.equals("Ni-NiO")   ) rockRef.setlogfo2(fO2Type.fo2_nno,  0.0);
          else if (item.equals("Q-Fa-Mt")  ) rockRef.setlogfo2(fO2Type.fo2_qfm,  0.0);
          else if (item.equals("C-COH")    ) JOptionPane.showMessageDialog(frame, "Option not yet implemented.");   
          else if (item.equals("Fe-FeO")   ) rockRef.setlogfo2(fO2Type.fo2_iw,   0.0);  
          else if (item.equals("Q-Fa-Mt+3")) rockRef.setlogfo2(fO2Type.fo2_qfm,  3.0);
          else if (item.equals("Q-Fa-Mt+2")) rockRef.setlogfo2(fO2Type.fo2_qfm,  2.0);
          else if (item.equals("Q-Fa-Mt+1")) rockRef.setlogfo2(fO2Type.fo2_qfm,  1.0);
          else if (item.equals("Q-Fa-Mt-1")) rockRef.setlogfo2(fO2Type.fo2_qfm, -1.0);
          else if (item.equals("Q-Fa-Mt-2")) rockRef.setlogfo2(fO2Type.fo2_qfm, -2.0);
          else if (item.equals("Q-Fa-Mt-3")) rockRef.setlogfo2(fO2Type.fo2_qfm, -3.0);
          else if (item.equals("Q-Fa-Mt-4")) rockRef.setlogfo2(fO2Type.fo2_qfm, -4.0);
          else if (item.equals("Q-Fa-Mt-5")) rockRef.setlogfo2(fO2Type.fo2_qfm, -5.0);
          else if (item.equals("Q-Fa-Mt-6")) rockRef.setlogfo2(fO2Type.fo2_qfm, -6.0);
          else if (item.equals("Q-Fa-Mt-7")) rockRef.setlogfo2(fO2Type.fo2_qfm, -7.0);
          else if (item.equals("Q-Fa-Mt-8")) rockRef.setlogfo2(fO2Type.fo2_qfm, -8.0);
          else if (item.equals("Q-Fa-Mt-9")) rockRef.setlogfo2(fO2Type.fo2_qfm, -9.0);
        } catch (org.omg.CORBA.COMM_FAILURE	noServer) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
          JOptionPane.showMessageDialog(null, 
            "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
      	    "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        }
      }
      
    }
  }
  
  //*************************************
  // actionListeners for the Options Menu
  //*************************************
   
  private class IsenthalpicHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JCheckBoxMenuItem source = (JCheckBoxMenuItem) e.getSource();
      if (rockRef == null) return;
      try {
        if (source.isSelected()) { rockRef.setIsenthalpic(true);  isenthalpic = true;  }
        else                     { rockRef.setIsenthalpic(false); isenthalpic = false; }
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      }
    }
  }
  
  private class IsentropicHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JCheckBoxMenuItem source = (JCheckBoxMenuItem) e.getSource();
      if (rockRef == null) return;
      try {
        if (source.isSelected()) { rockRef.setIsentropic(true);   isentropic = true;  }
        else                     { rockRef.setIsentropic(false);  isentropic = false; }
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      }
    }
  }
  
  private class IsochoricHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JCheckBoxMenuItem source = (JCheckBoxMenuItem) e.getSource();
      if (rockRef == null) return;
      try {
        if (source.isSelected()) { rockRef.setIsochoric(true);   isochoric = true;  }
        else                     { rockRef.setIsochoric(false);  isochoric = false; }
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      }
    }
  }
  
  private class FracSolidsHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JCheckBoxMenuItem source = (JCheckBoxMenuItem) e.getSource();
      if (source.isSelected()) fracSolids = true; 
      else                     fracSolids = false;
    }
  }

  private class FracLiquidHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      System.out.println("Entering the FracLiquid ActionListener.");
      JOptionPane.showMessageDialog(frame, "Option not yet implemented.");
    }
  }

  private class MultLiquidsHandler implements ActionListener {
    public void actionPerformed(ActionEvent ie) {
      System.out.println("Entering the MultLiquids ActionListener.");
      JOptionPane.showMessageDialog(frame, "Option not yet implemented.");
    }
  }
  
  // AssimHandler is implemented as a public class

  // PhaseHandler is implemented as a public class
  
  //************************************
  // actionListeners for the main window
  //************************************
  
  private class TextHandler implements PropertyChangeListener {
    public void propertyChange(PropertyChangeEvent e) {
      JFormattedTextField source = (JFormattedTextField) e.getSource();
      
      if (!doServerUpdates) return;
      
      for (int i=0; i<nc; i++) {
        if      (source == bcEntry[i]) {
	  bulkComp[i] = ((Number) source.getValue()).doubleValue();
	  try {
	    if (rockRef != null) rockRef.setBulkCompW(bulkComp);
	    Melts.printStatus("Bulk composition entry [" + i + "] updated on server.");
          } catch (org.omg.CORBA.COMM_FAILURE	  noServer) {
            JOptionPane.showMessageDialog(null, 
              "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
              "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
          } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
            JOptionPane.showMessageDialog(null, 
              "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
              "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
          }
	  return;
        }
      }

    }
  }
  
  private class PhasePopupHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JComboBox jb = (JComboBox) e.getSource();
      String entry = (String) jb.getSelectedItem();
      System.out.println("Entering the PhasePopup ActionListener. Entry = " + entry);
      
      if (entry   == null) return;
      if (rockRef == null) return;
      if (entry.equals("none")) return;
      
      try {
        double wt[] = new double[nc]; 
        if (entry.equals("liquid")) {
          wt = rockRef.getLiqCompWt();
          for (int i=0; i<nc; i++) ppEntry[i].setValue(new Double(wt[i]));
        } else {
          String[] entries = entry.split(":");
          short iphase = rockRef.getPhaseNo(entries[0]);
      	  short pInstance = 0;
      	  if (entries[0].length() != entry.length()) {
      	    Integer x = new Integer(entries[1]);
      	    pInstance = (short) x.intValue();
      	  }
      	  System.out.println("...entry = " + entries[0] + ", iphase = " + iphase + ", pInstance = " + pInstance);
      	  DoubleSeqHolder wtDS = new DoubleSeqHolder(wt);
          rockRef.getSolCompWt(iphase, pInstance, wtDS);
          for (int i=0; i<nc; i++) ppEntry[i].setValue(new Double(wtDS.value[i]));
        }
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      }
      
    }
  }
  
  private class fO2DisplayHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JComboBox jb = (JComboBox) e.getSource();
      String entry = (String) jb.getSelectedItem();
      if (rockRef == null) return;
      
      try {
        if (entry.equals("log10")) { 
          fO2DisplayMode = FO2_DISPLAY_NONE; 
      	  fO2Entry.setValue(new Double(rockRef.getlogfo2())); 
        } else if (entry.equals("\u2206" +"HM")) { 
          fO2DisplayMode = FO2_DISPLAY_HM;
      	  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_hm))); 
        } else if (entry.equals("\u2206" +"NNO")) { 
          fO2DisplayMode = FO2_DISPLAY_NNO;
      	  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_nno))); 
        } else if (entry.equals("\u2206" +"QFM")) { 
          fO2DisplayMode = FO2_DISPLAY_QFM;
      	  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_qfm))); 
        } else if (entry.equals("\u2206" +"C-COH")) { 
          fO2DisplayMode = FO2_DISPLAY_CCOH;
      	  fO2Entry.setValue(new Double(rockRef.getlogfo2())); 
        } else if (entry.equals("\u2206" +"IW")) { 
          fO2DisplayMode = FO2_DISPLAY_IW;
      	  fO2Entry.setValue(new Double(rockRef.getlogfo2relative(fO2Type.fo2_iw))); 
        }
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
      }
    
    }
  }
  
  private class LaunchHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      System.out.println("Entering the Launch ActionListener.");
      
      if        ("Graphics".equals(e.getActionCommand())) {
      // TODO - Implementation
      } else if ("Options".equals(e.getActionCommand())) {
      // TODO - Implementation
      } else if ("Calculator".equals(e.getActionCommand())) {
      // TODO - Implementation
      } else if ("Output".equals(e.getActionCommand())) {
      // TODO - Implementation
      } else {
        System.out.println("Fatal error in Launch ActionListener.");
      }
    }
  }
  
  private class UnitDisplayHandler implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      JComboBox source = (JComboBox) e.getSource();
      String entry = (String) source.getSelectedItem();
      System.out.println("Entering the Unit Display ActionListener.");
      
      if      (entry.equals("grams")) pTableModel.setDisplayUnit(PhaseTableModel.UNIT_GRAMS);
      else if (entry.equals("wt%")  ) pTableModel.setDisplayUnit(PhaseTableModel.UNIT_WEIGHT_PERCENT);
      else if (entry.equals("vol%") ) pTableModel.setDisplayUnit(PhaseTableModel.UNIT_VOLUME_PERCENT);
      
    }
  }
  
  // PhaseTableModel is implemented as a public class

  private class MeltsOutput {
    private PrintWriter output, tableLiq, tableSol[];
    private double gLiqFrac, hLiqFrac, sLiqFrac, vLiqFrac, cpLiqFrac, mLiqFrac; 
    private double wtLiqFrac[];
    private double mSolFrac, gSolFrac, hSolFrac, sSolFrac, vSolFrac, cpSolFrac;
    private double wtSolFrac[];
    private int rowIndex, nlc, np;
    private String dirName;
    
    private String cf (String pattern, double value) {
      DecimalFormat myFormatter = new DecimalFormat(pattern);
      String result = myFormatter.format(value);
      int diff = pattern.length() - result.length();
      if (diff > 0) {
        StringBuffer sb= new StringBuffer(pattern.length());
	for (int i=0; i<diff; i++) sb.append(" ");
	return sb.append(result).toString();
      } else return result;
    }
    
    public MeltsOutput() { 
      output   = null;
      tableLiq = null;
      rowIndex = 0;
      try {
        nlc      = (rockRef != null) ? rockRef.getNLiqComp()   : 1;
        np       = (rockRef != null) ? rockRef.getNSolPhases() : 1;
      } catch (org.omg.CORBA.COMM_FAILURE     noServer) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server is most likely down.\nPlease wait a few minutes and reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        np = 0; nlc = 0; 
      } catch (org.omg.CORBA.OBJECT_NOT_EXIST noObject) {
        JOptionPane.showMessageDialog(null, 
          "Lost contact with server. Server has deleted your process.\nPlease reload applet or restart application.",
          "CORBA Server Error", JOptionPane.ERROR_MESSAGE);
        np = 0; nlc = 0;
      }
      tableSol = new PrintWriter[np];
      for (int i=0; i<np; i++) tableSol[i] = null;
       
      gLiqFrac  = 0.0; 
      hLiqFrac  = 0.0; 
      sLiqFrac  = 0.0; 
      vLiqFrac  = 0.0; 
      cpLiqFrac = 0.0; 
      mLiqFrac  = 0.0;
      wtLiqFrac = new double[nc]; 
      for (int i=0; i<nc; i++) wtLiqFrac[i] = 0.0;

      mSolFrac  = 0.0;
      gSolFrac  = 0.0;
      hSolFrac  = 0.0;
      sSolFrac  = 0.0;
      vSolFrac  = 0.0;
      cpSolFrac = 0.0;
      wtSolFrac = new double[nc]; 
      for (int i=0; i<nc; i++) wtSolFrac[i] = 0.0;
    }
    
    // CORBA exceptions generated in this method are caught in the calling block
    public boolean putResultsToOutputFile() {
    
      if (output == null) {
        openSaveDialog.addChoosableFileFilter(new MeltsFileFilter(".out"));
    	int returnValue = openSaveDialog.showSaveDialog(frame);
    	if (returnValue == JFileChooser.APPROVE_OPTION) {
    	  File outputFile = openSaveDialog.getSelectedFile();
    	  Melts.printStatus("Trying to create: " + outputFile.getName() + ".");
	  dirName = outputFile.getParent();
	  
  	  try {
  	    output = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)), true); // automatically flushes
    	    Melts.printStatus("Writing to output file: " + outputFile.getName() + ".");
    	  } catch (IOException ioe) {
  	    JOptionPane.showMessageDialog(frame, "Cannot create file " + outputFile.getName() + ".",
  	      "I/O Exception", JOptionPane.ERROR_MESSAGE);
  	    return false;
  	  } catch (SecurityException se) {
  	    JOptionPane.showMessageDialog(frame, "Cannot create file " + outputFile.getName() + ".",
  	      "Security Exception", JOptionPane.ERROR_MESSAGE);
  	    return false;
  	  }
	  
	  String tableLiqName = dirName + File.separator + "melts-liquid.tbl";
	  try {
  	    tableLiq = new PrintWriter(new BufferedWriter(new FileWriter(tableLiqName)), true); // automatically flushes
    	    Melts.printStatus("Writing to output file: " + tableLiqName + ".");
    	  } catch (IOException ioe) {
  	    JOptionPane.showMessageDialog(frame, "Cannot create file " + tableLiqName + ".",
  	      "I/O Exception", JOptionPane.ERROR_MESSAGE);
  	    return false;
  	  } catch (SecurityException se) {
  	    JOptionPane.showMessageDialog(frame, "Cannot create file " + tableLiqName + ".",
  	      "Security Exception", JOptionPane.ERROR_MESSAGE);
  	    return false;
  	  }
          tableLiq.print("Index,T (C),P (kbars),log(10) f O2");
          tableLiq.print(",liq mass (gm),liq rho (gm/cc)");
          for (short i=0; i<nc; i++) tableLiq.print(",wt% " + rockRef.getCompName(i));
          tableLiq.print(",liq G (kJ),liq H (kJ),liq S (J/K),liq V (cc),liq Cp (J/K)");
          for (short i=0; i<nlc; i++) tableLiq.print(",activity " + rockRef.getLiqCompName(i));
          tableLiq.print(",liq vis (log 10 poise),sol mass (gm),sol rho (gm/cc)");
          tableLiq.print(",sol G (kJ),sol H (kJ),sol S (J/K),sol V (cc),sol Cp (J/K)");
          tableLiq.println();

    	}
    	else {
    	  JOptionPane.showMessageDialog(frame, "Cannot create output file. No contact with server.",
  	  				"ORB Not Found Exception", JOptionPane.ERROR_MESSAGE);
  	  return false;
    	}
      }
      
      rowIndex++;

      output.println();
      output.println("**********----------**********");
      output.println("Title: " + "File created by MELTS/pMELTS CORBA client. v.0.8, August 2007.");
      output.println();
      
      output.print  ("T = " + cf("0.00",   ((Number) tEntry.getValue()).doubleValue()) + " (C)  ");
      output.print  ("P = " + cf("0.0000", ((Number) pEntry.getValue()).doubleValue()) + " (GPa)  ");
      output.print  ("log(10) f O2 = " + cf("0.00", ((Number) fO2Entry.getValue()).doubleValue()) + "  ");
      output.print  ("delta HM = " + cf("0.00", rockRef.getlogfo2relative(fO2Type.fo2_hm))   + "  ");   
      output.print  (     "NNO = " + cf("0.00", rockRef.getlogfo2relative(fO2Type.fo2_nno))  + "  ");
      output.print  (     "QFM = " + cf("0.00", rockRef.getlogfo2relative(fO2Type.fo2_qfm))  + "  ");
    //output.print  (     "COH = " + cf("0.00", rockRef.getlogfo2relative(fO2Type.fo2_none)) + "  ");
      output.println(      "IW = " + cf("0.00", rockRef.getlogfo2relative(fO2Type.fo2_iw))   + "  ");	
      output.println();
      
      tableLiq.print(rowIndex);
      tableLiq.print("," + ((Number) tEntry.getValue()).doubleValue());
      tableLiq.print("," + ((Number) pEntry.getValue()).doubleValue());
      tableLiq.print("," + ((Number) fO2Entry.getValue()).doubleValue());

      output.print  ("Constraint Flags: ");
      
      if      (fO2Choice[ 1].isSelected()) output.println("fO2 path = HM  "   );
      else if (fO2Choice[ 2].isSelected()) output.println("fO2 path = NNO  "  );
      else if (fO2Choice[ 3].isSelected()) output.println("fO2 path = QFM  "  );
      else if (fO2Choice[ 4].isSelected()) output.println("fO2 path = C-COH  ");
      else if (fO2Choice[ 5].isSelected()) output.println("fO2 path = IW  "   );
      else if (fO2Choice[ 6].isSelected()) output.println("fO2 path = QFM+3  ");
      else if (fO2Choice[ 7].isSelected()) output.println("fO2 path = QFM+2  ");
      else if (fO2Choice[ 8].isSelected()) output.println("fO2 path = QFM+1  ");
      else if (fO2Choice[ 9].isSelected()) output.println("fO2 path = QFM-1  ");
      else if (fO2Choice[10].isSelected()) output.println("fO2 path = QFM-2  ");
      else if (fO2Choice[11].isSelected()) output.println("fO2 path = QFM-3  ");
      else if (fO2Choice[12].isSelected()) output.println("fO2 path = QFM-4  ");
      else if (fO2Choice[13].isSelected()) output.println("fO2 path = QFM-5  ");
      else if (fO2Choice[14].isSelected()) output.println("fO2 path = QFM-6  ");
      else if (fO2Choice[15].isSelected()) output.println("fO2 path = QFM-7  ");
      else if (fO2Choice[16].isSelected()) output.println("fO2 path = QFM-8  ");
      else if (fO2Choice[17].isSelected()) output.println("fO2 path = QFM-9  ");

      if (    fracSolRBMI.isSelected()) output.println("Fractionate Solids  " );
      if (    fracLiqRBMI.isSelected()) output.println("Fractionate Liquids " );
      if (     mulLiqRBMI.isSelected()) output.println("Multiple Liquids  "   );
      if (isoEnthalpyRBMI.isSelected()) output.println("Isenthalpic Path  "   );
      if ( isoEntropyRBMI.isSelected()) output.println("Isentropic Path  "    );
      if (  isoVolumeRBMI.isSelected()) output.println("Isochoric Path  "     );
      if (                   false    ) output.println("Assimilation  "       );

      output.println();
      output.println();

      double gLiq  = 0.0; 
      double hLiq  = 0.0; 
      double sLiq  = 0.0; 
      double vLiq  = 0.0; 
      double cpLiq = 0.0; 
      double mLiq  = rockRef.getLiquidMass();
      double viscosity = rockRef.getLiquidViscosity();

      if (mLiq > 0.0) {
        gLiq  = rockRef.getLiquidGibbsFreeEnergy();
        hLiq  = rockRef.getLiquidEnthalpy();
        sLiq  = rockRef.getLiquidEntropy();
        vLiq  = rockRef.getLiquidVolume()*1000000.0; // J/Pa -> J/bar -> cc
        cpLiq = rockRef.getLiquidHeatCapacity();
	
	if (fracLiquids) {
	  gLiqFrac  += 0.99*gLiq;
          hLiqFrac  += 0.99*hLiq;
          sLiqFrac  += 0.99*sLiq;
          vLiqFrac  += 0.99*vLiq;
          cpLiqFrac += 0.99*cpLiq;
          mLiqFrac  += 0.99*mLiq;
	}
    	
    	{  // Do once for each liquid instance in the system
	  double rhoLiq = (vLiq != 0.0) ? mLiq/vLiq : 0.0;

    	  output.print  ("Liquid           ");
	  output.print  ("mass = "      + cf("0.00", mLiq)      + " (gm)  ");
	  output.print  ("density = "   + cf("0.00", rhoLiq)    + " (gm/cc)  ");
    	  output.print  ("viscosity = " + cf("0.00", viscosity) + " (log 10 poise)  ");
    	  output.println("(analysis in wt % oxides)");
	  
	  tableLiq.print("," + mLiq + "," + rhoLiq);

    	  output.print  ("                 ");
    	  output.print  ("G = "  + cf("0.00",  gLiq) + " (J)  ");
    	  output.print  ("H = "  + cf("0.00",  hLiq) + " (J)  ");
    	  output.print  ("S = "  + cf("0.00",  sLiq) + " (J/K)  ");
    	  output.print  ("V = "  + cf("0.00",  vLiq) + " (cc)  ");
    	  output.println("Cp = " + cf("0.00", cpLiq) + " (J/K)  ");
     
    	  output.print("        ");
    	  for (int i=0; i<nc; i++) {  // emulate %7.7s
	    String label = rockRef.getCompName((short) i);
	    int len = label.length();
	    for (int j=0; j<(7-len); j++) output.print(" ");
	    output.print(label);
	  }
    	  output.println();
	  
	  double wt[] = new double[nc];
	  wt = rockRef.getLiqCompWt();
    	  output.print("        ");
    	  for (int i=0; i<nc; i++) { // emulate %5.2f
	    output.print("  " + cf("#0.00", wt[i]));
	    if (fracLiquids) wtLiqFrac[i] += 0.99*(mLiq/100.0)*wt[i];
	    tableLiq.print("," + wt[i]);
	  }
    	  output.println();
    	  
    	  tableLiq.print("," + gLiq/1000.0 + "," + hLiq/1000.0 + "," + sLiq + "," + vLiq + "," + cpLiq);
	  
	  double act[] = new double[nlc];
	  act = rockRef.getLiqActivity();
    	  for (int i=0; i<nlc; i++) tableLiq.print("," + act[i]);
    	  tableLiq.print("," + viscosity);
     
    	} // End block for multiple liquids
      }
      
      double mSol  = 0.0;
      double gSol  = 0.0;
      double hSol  = 0.0;
      double sSol  = 0.0;
      double vSol  = 0.0;
      double cpSol = 0.0;
      
      for (short j=0; j<rockRef.getNSolPhases(); j++) {
        for (short ns=0; ns<rockRef.getNumberCoexistPhase(j); ns++) { 
    	  double mass	       = rockRef.getSolPhaseMass(j, ns);
    	  double gibbsEnergy   = rockRef.getSolidGibbsFreeEnergy(j, ns);
    	  double enthalpy      = rockRef.getSolidEnthalpy(j, ns);
    	  double entropy       = rockRef.getSolidEntropy(j, ns);
    	  double volume        = rockRef.getSolidVolume(j, ns)*1000000.0; // J/Pa -> J/bar -> cc
    	  double heatCapacity  = rockRef.getSolidHeatCapacity(j, ns);
	  
	  mSol  += mass;
          gSol  += gibbsEnergy;
          hSol  += enthalpy;
          sSol  += entropy;
          vSol  += volume;
          cpSol += heatCapacity;
	  
	  if (fracSolids) {
	    gSolFrac  += 0.99*gibbsEnergy;
            hSolFrac  += 0.99*enthalpy;
            sSolFrac  += 0.99*entropy;
            vSolFrac  += 0.99*volume;
            cpSolFrac += 0.99*heatCapacity;
            mSolFrac  += 0.99*mass;
	  }
	  
	  if (tableSol[j] == null) {
	    String fileName = dirName + File.separator + rockRef.getSolPhaseName(j).replace(' ', '-') + ".tbl";
	    try {
  	      tableSol[j] = new PrintWriter(new BufferedWriter(new FileWriter(fileName)), true); // automatically flushes
    	      Melts.printStatus("Writing to output file: " + fileName + ".");
    	    } catch (IOException ioe) {
  	      JOptionPane.showMessageDialog(frame, "Cannot create file " + fileName + ".",
  	    	"I/O Exception", JOptionPane.ERROR_MESSAGE);
  	      return false;
  	    } catch (SecurityException se) {
  	      JOptionPane.showMessageDialog(frame, "Cannot create file " + fileName + ".",
  	    	"Security Exception", JOptionPane.ERROR_MESSAGE);
  	      return false;
  	    }
    	    tableSol[j].print("Index,T (C),P (kbars),log(10) f O2");
    	    tableSol[j].print(",mass (gm),rho (gm/cc)");
    	    for (short i=0; i<nc; i++) tableSol[j].print(",wt% " + rockRef.getCompName(i));
    	    tableSol[j].print(",G (kJ),H (kJ),S (J/K),V (cc),Cp (J/K)");
	    if (!rockRef.isSingleComponent(j))
	      for (short i=0; i<rockRef.getNSolComp(j); i++) tableSol[j].print("," + rockRef.getSolPhaseCompName(j, i));
    	    tableSol[j].println();
	  }	  

          output.println();
	  String name = rockRef.getSolPhaseName(j); // emulate %-15.15s
	  int len = name.length();
	  if (len > 15) output.print(name.substring(0, 14));
	  else {
	    output.print(name);
	    for (int k=0; k<(15-len); k++) output.print(" ");
	  }
	  output.print("  mass = "  + cf("0.00", mass) + " (gm)  ");
	  output.print("density = " + cf("0.00", (volume == 0.0) ? 0.0 : mass/volume) + " (gm/cc)"); 
    	  output.println("	  (analysis in mole fraction and wt% oxides)");
    	  output.println("                 " + rockRef.getSolPhaseFormula(j, ns));	  
    	  output.print  ("                 "); 
    	  output.print  ("G = "  + cf("0.00", gibbsEnergy)  + " (J)  "  );
    	  output.print  ("H = "  + cf("0.00", enthalpy)	    + " (J)  "  );
    	  output.print  ("S = "  + cf("0.00", entropy)	    + " (J/K)  ");
    	  output.print  ("V = "  + cf("0.00", volume)	    + " (cc)  " );
    	  output.print  ("Cp = " + cf("0.00", heatCapacity) + " (J/K)  ");
    	  output.println();

	  tableSol[j].print(rowIndex);
          tableSol[j].print("," + ((Number) tEntry.getValue()).doubleValue());
          tableSol[j].print("," + ((Number) pEntry.getValue()).doubleValue());
          tableSol[j].print("," + ((Number) fO2Entry.getValue()).doubleValue());
	  tableSol[j].print("," + mass + "," + ((volume == 0.0) ? 0.0 : mass/volume));
	  
	  if (!rockRef.isSingleComponent(j)) {
	    short na = rockRef.getNSolComp(j);
	    double X[] = new double[na];
	    DoubleSeqHolder XDS = new DoubleSeqHolder(X);
            rockRef.getSolComp(j, ns, XDS);
	    
    	    output.print("        "); 
	    for (short i=0; i<na; i++) {
	      String component = rockRef.getSolPhaseCompName(j, i); // emulate %-13.13s
	      int cLen = component.length();
	      output.print(" ");
	      if (cLen > 13) output.print(component.substring(0, 13));
	      else {
	        for (int k=0; k<(13-cLen); k++) output.print(" ");
	        output.print(component);
	      }
	    }
    	    output.println();
	    
    	    output.print("        "); 
	    double sum = 0.0;
	    for (short i=0; i<na; i++) sum += XDS.value[i];
    	    for (short i=0; i<na; i++) output.print(" " + cf("#####0.000000", XDS.value[i]/sum));
    	    output.println();
	  }

	  double wt[] = new double[nc];
	  DoubleSeqHolder wtDS = new DoubleSeqHolder(wt);
          rockRef.getSolCompWt(j, ns, wtDS);
	  
    	  output.print("	");
    	  for (int i=0; i<nc; i++) {  // emulate %7.7s
	    String label = rockRef.getCompName((short) i);
	    int cLen = label.length();
	    for (int k=0; k<(7-cLen); k++) output.print(" ");
	    output.print(label);
	  }
    	  output.println();
	  
    	  output.print("	");
    	  for (int i=0; i<nc; i++) { // emulate %5.2f
	    output.print("  " + cf("#0.00", wtDS.value[i]));
	    if (fracSolids) wtSolFrac[i] += 0.99*(mSol/100.0)*wtDS.value[i];
	    tableSol[j].print("," + wtDS.value[i]);
	  }
    	  output.println();
	  
	  tableSol[j].print("," + gibbsEnergy/1000.0);
	  tableSol[j].print("," + enthalpy/1000.0   );
	  tableSol[j].print("," + entropy           );
	  tableSol[j].print("," + volume            );
	  tableSol[j].print("," + heatCapacity      );
	  
    	  if (!rockRef.isSingleComponent(j)) {
	    short na = rockRef.getNSolComp(j);
	    double X[] = new double[na];
	    DoubleSeqHolder XDS = new DoubleSeqHolder(X);
            rockRef.getSolComp(j, ns, XDS);
	    double sum = 0.0;
	    for (short i=0; i<na; i++) sum += XDS.value[i];
	    for (short i=0; i<na; i++) tableSol[j].print("," + XDS.value[i]/sum);
	  }
	  
	  tableSol[j].println();

	}
      }
      
      output.println();
      output.print  ("Total solids     ");
      output.print  ("mass = " + cf("0.00", mSol) + " (gm)  ");
      output.println("density = " + cf("0.00",(vSol == 0.0) ? 0.0 : mSol/vSol) + " (gm/cc)");
      output.print  ("                 "); 
      output.print  ("G = "  + cf("0.00", gSol)  + " (J)  ");
      output.print  ("H = "  + cf("0.00", hSol)  + " (J)  ");
      output.print  ("S = "  + cf("0.00", sSol)  + " (J/K)  ");
      output.print  ("V = "  + cf("0.00", vSol)  + " (cc)  ");
      output.print  ("Cp = " + cf("0.00", cpSol) + " (J/K)  ");
      output.println();

      if (mLiq > 0) {
    	tableLiq.print("," + mSol + "," + ((vSol == 0.0) ? 0.0 : mSol/vSol));
    	tableLiq.print("," + gSol/1000.0 + "," + hSol/1000.0 + "," + sSol + "," + vSol + "," + cpSol);
    	tableLiq.println();
      }

      if (fracSolids) {
        output.println();
        output.print  ("Fractionated sol ");
        output.print  ("mass = " + cf("0.00", mSolFrac) + " (gm)  ");
        output.println("density = " + cf("0.00",(vSolFrac == 0.0) ? 0.0 : mSolFrac/vSolFrac) + " (gm/cc)");
        output.print  ("		 "); 
        output.print  ("G = "  + cf("0.00", gSolFrac)  + " (J)  ");
        output.print  ("H = "  + cf("0.00", hSolFrac)  + " (J)  ");
        output.print  ("S = "  + cf("0.00", sSolFrac)  + " (J/K)  ");
        output.print  ("V = "  + cf("0.00", vSolFrac)  + " (cc)  ");
        output.print  ("Cp = " + cf("0.00", cpSolFrac) + " (J/K)  ");
        output.println();

    	output.print("        ");
	double sum = 0.0;
    	for (int i=0; i<nc; i++) {  // emulate %7.7s
	  String label = rockRef.getCompName((short) i);
	  int len = label.length();
	  for (int j=0; j<(7-len); j++) output.print(" ");
	  output.print(label);
	  sum += wtSolFrac[i];
	}
    	output.println();
	
    	output.print("        ");
    	for (int i=0; i<nc; i++) { // emulate %5.2f
	  output.print("  " + cf("#0.00", (sum != 0.0) ? 100.0*wtSolFrac[i]/sum : 0.0));
	}
    	output.println();
      }
      
      if (fracLiquids) {
        output.println();
        output.print  ("Fractionated Liq ");
        output.print  ("mass = " + cf("0.00", mLiqFrac) + " (gm)  ");
        output.println("density = " + cf("0.00",(vLiqFrac == 0.0) ? 0.0 : mLiqFrac/vLiqFrac) + " (gm/cc)");
        output.print  ("		 "); 
        output.print  ("G = "  + cf("0.00", gLiqFrac)  + " (J)  ");
        output.print  ("H = "  + cf("0.00", hLiqFrac)  + " (J)  ");
        output.print  ("S = "  + cf("0.00", sLiqFrac)  + " (J/K)  ");
        output.print  ("V = "  + cf("0.00", vLiqFrac)  + " (cc)  ");
        output.print  ("Cp = " + cf("0.00", cpLiqFrac) + " (J/K)  ");
        output.println();

    	output.print("        ");
	double sum = 0.0;
    	for (int i=0; i<nc; i++) {  // emulate %7.7s
	  String label = rockRef.getCompName((short) i);
	  int len = label.length();
	  for (int j=0; j<(7-len); j++) output.print(" ");
	  output.print(label);
	  sum += wtLiqFrac[i];
	}
    	output.println();
	
    	output.print("        ");
    	for (int i=0; i<nc; i++) { // emulate %5.2f
	  output.print("  " + cf("#0.00", (sum != 0.0) ? 100.0*wtLiqFrac[i]/sum : 0.0));
	}
    	output.println();
      }

      if (vLiq > vSol) {
        output.println();
        output.print  ("Viscosity of the System: ");
        output.print  (cf("0.00",viscosity - 2.0*Math.E*Math.log(1.0-2.0*vSol/(vSol+vLiq))));
	output.print  (" (log 10 poise)");
        output.println();
      } else {
        output.println();
        output.print  ("Viscosity of the System cannot be computed.");
        output.println();
      }

      output.println();
      output.print  ("System           ");
      output.print  ("mass = " + cf("0.00", mLiq+mSol) + " (gm)  ");
      output.println("density = " + cf("0.00",(vLiq+vSol == 0.0) ? 0.0 : (mLiq+mSol)/(vLiq+vSol)) + " (gm/cc)");
      output.print  ("                 "); 
      output.print  ("G = "  + cf("0.00", gLiq+gSol)  + " (J)  ");
      output.print  ("H = "  + cf("0.00", hLiq+hSol)  + " (J)  ");
      output.print  ("S = "  + cf("0.00", sLiq+sSol)  + " (J/K)  ");
      output.print  ("V = "  + cf("0.00", vLiq+vSol)  + " (cc)  ");
      output.print  ("Cp = " + cf("0.00", cpLiq+cpSol) + " (J/K)  ");
      output.println();

      if (!fO2Choice[0].isSelected()) {
        double mO2 = rockRef.getDeltaOxygen();
        output.println();
        output.print  ("Oxygen           ");
        output.print  ("delta moles = " + cf("0.000000", mO2) + "  ");
        output.println("delta grams = " + cf("0.000000", mO2*31.9988));
        output.print  ("                 "); 
        output.print  ("G = "  + cf("0.00", mO2*rockRef.getOxygenGibbsFreeEnergy())  + " (J)  "  );
        output.print  ("H = "  + cf("0.00", mO2*rockRef.getOxygenEnthalpy())         + " (J)  "  );
        output.print  ("S = "  + cf("0.00", mO2*rockRef.getOxygenEntropy())          + " (J/K)  ");
        output.print  ("V = "  + cf("0.00", mO2*rockRef.getOxygenVolume()*1000000.0) + " (cc)  " );
        output.print  ("Cp = " + cf("0.00", mO2*rockRef.getOxygenHeatCapacity())     + " (J/K)  ");
        output.println();
      }
/*
      if (silminState->assimilate) {
    	output.println("\nSummary of assimilant: ");
    	output.println("(total mass = %.2f grams, temperature = %.2f)\n", silminState->assimMass, silminState->assimT);
    	for (j=0; j<npc; j++) if (solids[j].type == PHASE)
    	for (ns=0; ns<(silminState->nAssimComp)[j]; ns++) {
    	  if (solids[j].na == 1) {
    	    mass = (silminState->assimComp)[j][ns]*solids[j].mw*silminState->assimMass/silminState->dspAssimMass;
    	    output.println("\n%-15.15s  mass = %.2f (gm)", solids[j].label, mass);
    	    output.println("	  (analysis in mole %%)\n");
    	  } else {
    	    for (i=0, mass=0.0; i<solids[j].na; i++) mass += (silminState->assimComp)[j+1+i][ns]*solids[j+1+i].mw;
    	    mass *= silminState->assimMass/silminState->dspAssimMass;
    	    output.println("\n%-15.15s  mass = %.2f (gm)", solids[j].label, mass);
    	    output.println("	  (analysis in mole %%)\n");
    	    output.println("	  "); 
    	    for (i=0; i<solids[j].na; i++) output.println(" %13.13s", solids[j+1+i].label);
    	    output.println("\n");
    	    output.println("	  "); 
    	    for (i=0; i<solids[j].na; i++) output.println(" %13.2f", 100.0*(silminState->assimComp)[j+1+i][ns]/(silminState->assimComp)[j][ns]);
    	    output.println("\n");
    	  }
    	}
      }
*/

      double totMass = mLiq + mSol + mSolFrac;
      if (totMass != 0.0) {
        liqProgress.setValue( (int) (100.0*mLiq/totMass));
        solProgress.setValue( (int) (100.0*mSol/totMass));
        fracProgress.setValue((int) (100.0*mSolFrac/totMass));
      }

      return true;
    }
  }  // end definition of private class MeltsOutput

}
  

