content: /*
   *    This program is free software; you can redistribute it and/or modify
   *    it under the terms of the GNU General Public License as published by
   *    the Free Software Foundation; either version 2 of the License, or
   *    (at your option) any later version.
   *
   *    This program is distributed in the hope that it will be useful,
   *    but WITHOUT ANY WARRANTY; without even the implied warranty of
   *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *    GNU General Public License for more details.
   *
   *    You should have received a copy of the GNU General Public License
   *    along with this program; if not, write to the Free Software
   *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  /*
   *    RunPanel.java
   *    Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
   *
   */
  
  package weka.gui.experiment;
  
  import weka.core.SerializedObject;
  import weka.core.Utils;
  import weka.experiment.Experiment;
  import weka.experiment.RemoteExperiment;
  import weka.experiment.RemoteExperimentEvent;
  import weka.experiment.RemoteExperimentListener;
  import weka.gui.LogPanel;
  
  import java.awt.BorderLayout;
  import java.awt.GridBagConstraints;
  import java.awt.GridBagLayout;
  import java.awt.Insets;
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
  import java.awt.event.WindowAdapter;
  import java.awt.event.WindowEvent;
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.ObjectInputStream;
  import java.io.Serializable;
  
  import javax.swing.BorderFactory;
  import javax.swing.JButton;
  import javax.swing.JFrame;
  import javax.swing.JPanel;
  
  /** 
   * This panel controls the running of an experiment.
   *
   * @author Len Trigg (trigg@cs.waikato.ac.nz)
   * @version $Revision: 1.21 $
   */
  public class RunPanel
    extends JPanel
    implements ActionListener {
  
    /** for serialization */
    private static final long serialVersionUID = 1691868018596872051L;
  
    /** The message displayed when no experiment is running */
    protected static final String NOT_RUNNING = "Not running";
  
    /** Click to start running the experiment */
    protected JButton m_StartBut = new JButton("Start");
  
    /** Click to signal the running experiment to halt */
    protected JButton m_StopBut = new JButton("Stop");
  
    protected LogPanel m_Log = new LogPanel();
  
    /** The experiment to run */
    protected Experiment m_Exp;
  
    /** The thread running the experiment */
    protected Thread m_RunThread = null;
  
    /** A pointer to the results panel */
    protected ResultsPanel m_ResultsPanel = null;
  
    /*
     * A class that handles running a copy of the experiment
     * in a separate thread
     */
    class ExperimentRunner
      extends Thread
      implements Serializable {
  
      /** for serialization */
      private static final long serialVersionUID = -5591889874714150118L;
  
      Experiment m_ExpCopy;
      
      public ExperimentRunner(final Experiment exp) throws Exception {
  
        // Create a full copy using serialization
        if (exp == null) {
  	System.err.println("Null experiment!!!");
        } else {
  	System.err.println("Running experiment: " + exp.toString());
        }
        System.err.println("Writing experiment copy");
        SerializedObject so = new SerializedObject(exp);
        System.err.println("Reading experiment copy");
        m_ExpCopy = (Experiment) so.getObject();
        System.err.println("Made experiment copy");
      }
  
      public void abortExperiment() {
        if (m_ExpCopy instanceof RemoteExperiment) {
  	((RemoteExperiment)m_ExpCopy).abortExperiment();
  	//	m_StartBut.setEnabled(true);
  	m_StopBut.setEnabled(false);
  	//	statusMessage(NOT_RUNNING);
        }
      }
  
      /**
       * Starts running the experiment.
       */
      public void run() {
        
        m_StartBut.setEnabled(false);
        m_StopBut.setEnabled(true);
        if (m_ResultsPanel != null) {
  	m_ResultsPanel.setExperiment(null);
        }
        try {
  	if (m_ExpCopy instanceof RemoteExperiment) {
  	  // add a listener
  	  System.err.println("Adding a listener");
  	  ((RemoteExperiment)m_ExpCopy).
  	    addRemoteExperimentListener(new RemoteExperimentListener() {
  		public void remoteExperimentStatus(RemoteExperimentEvent e) {
  		  if (e.m_statusMessage) {
  		    statusMessage(e.m_messageString);
  		  }
  		  if (e.m_logMessage) {
  		    logMessage(e.m_messageString);
  		  }
  		  if (e.m_experimentFinished) {
  		    m_RunThread = null;
  		    m_StartBut.setEnabled(true);
  		    m_StopBut.setEnabled(false);
  		    statusMessage(NOT_RUNNING);
  		  }
  		}
  	      });
  	}
  	logMessage("Started");
  	statusMessage("Initializing...");
  	m_ExpCopy.initialize();
  	int errors = 0;
  	if (!(m_ExpCopy instanceof RemoteExperiment)) {
  	  statusMessage("Iterating...");
  	  while (m_RunThread != null && m_ExpCopy.hasMoreIterations()) {
  	    try {
  	      String current = "Iteration:";
  	      if (m_ExpCopy.getUsePropertyIterator()) {
  		int cnum = m_ExpCopy.getCurrentPropertyNumber();
  		String ctype = m_ExpCopy.getPropertyArray().getClass().getComponentType().getName();
  		int lastDot = ctype.lastIndexOf('.');
  		if (lastDot != -1) {
  		  ctype = ctype.substring(lastDot + 1);
  		}
  		String cname = " " + ctype + "="
  		  + (cnum + 1) + ":"
  		  + m_ExpCopy.getPropertyArrayValue(cnum).getClass().getName();
  		current += cname;
  	      }
  	      String dname = ((File) m_ExpCopy.getDatasets()
  			      .elementAt(m_ExpCopy.getCurrentDatasetNumber()))
  		.getName();
  	      current += " Dataset=" + dname
  		+ " Run=" + (m_ExpCopy.getCurrentRunNumber());
  	      statusMessage(current);
  	      m_ExpCopy.nextIteration();
  	    } catch (Exception ex) {
  	      errors ++;
  	      logMessage(ex.getMessage());
  	      ex.printStackTrace();
  	      boolean continueAfterError = false;
  	      if (continueAfterError) {
  		m_ExpCopy.advanceCounters(); // Try to keep plowing through
  	      } else {
  		m_RunThread = null;
  	      }
  	    }
  	  }
  	  statusMessage("Postprocessing...");
  	  m_ExpCopy.postProcess();
  	  if (m_RunThread == null) {
  	    logMessage("Interrupted");
  	  } else {
  	    logMessage("Finished");
  	  }
  	  if (errors == 1) {
  	    logMessage("There was " + errors + " error");
  	  } else {
  	    logMessage("There were " + errors + " errors");
  	  }
  	  statusMessage(NOT_RUNNING);
  	} else {
  	  statusMessage("Remote experiment running...");
  	  ((RemoteExperiment)m_ExpCopy).runExperiment();
  	}
        } catch (Exception ex) {
  	ex.printStackTrace();
  	System.err.println(ex.getMessage());
  	statusMessage(ex.getMessage());
        } finally {
  	if (m_ResultsPanel != null) {
  	  m_ResultsPanel.setExperiment(m_ExpCopy);
  	}
  	if (!(m_ExpCopy instanceof RemoteExperiment)) {
  	  m_RunThread = null;
  	  m_StartBut.setEnabled(true);
  	  m_StopBut.setEnabled(false);
  	  System.err.println("Done...");
  	}
        }
      }
    }
  
    /**
     * Sets the pointer to the results panel.
     */
    public void setResultsPanel(ResultsPanel rp) {
  
      m_ResultsPanel = rp;
    }
    
    /**
     * Creates the run panel with no initial experiment.
     */
    public RunPanel() {
  
      m_StartBut.addActionListener(this);
      m_StopBut.addActionListener(this);
      m_StartBut.setEnabled(false);
      m_StopBut.setEnabled(false);
      m_StartBut.setMnemonic('S');
      m_StopBut.setMnemonic('t');
      m_Log.statusMessage(NOT_RUNNING);
  
      // Set the GUI layout
      JPanel controls = new JPanel();
      GridBagLayout gb = new GridBagLayout();
      GridBagConstraints constraints = new GridBagConstraints();
      controls.setBorder(BorderFactory.createEmptyBorder(10, 5, 10, 5));
      //    controls.setLayout(new GridLayout(1,2));
      controls.setLayout(gb);
      constraints.gridx=0;constraints.gridy=0;constraints.weightx=5;
      constraints.fill = GridBagConstraints.HORIZONTAL;
      constraints.gridwidth=1;constraints.gridheight=1;
      constraints.insets = new Insets(0,2,0,2);
      controls.add(m_StartBut,constraints);
      constraints.gridx=1;constraints.gridy=0;constraints.weightx=5;
      constraints.gridwidth=1;constraints.gridheight=1;
      controls.add(m_StopBut,constraints);
      setLayout(new BorderLayout());
      add(controls, BorderLayout.NORTH);
      add(m_Log, BorderLayout.CENTER);
    }
      
    /**
     * Creates the panel with the supplied initial experiment.
     *
     * @param exp a value of type 'Experiment'
     */
    public RunPanel(Experiment exp) {
  
      this();
      setExperiment(exp);
    }
  
    /**
     * Sets the experiment the panel operates on.
     *
     * @param exp a value of type 'Experiment'
     */
    public void setExperiment(Experiment exp) {
      
      m_Exp = exp;
      m_StartBut.setEnabled(m_RunThread == null);
      m_StopBut.setEnabled(m_RunThread != null);
    }
    
    /**
     * Controls starting and stopping the experiment.
     *
     * @param e a value of type 'ActionEvent'
     */
    public void actionPerformed(ActionEvent e) {
  
      if (e.getSource() == m_StartBut) {
        if (m_RunThread == null) {
  	try {
  	  m_RunThread = new ExperimentRunner(m_Exp);
  	  m_RunThread.setPriority(Thread.MIN_PRIORITY); // UI has most priority
  	  m_RunThread.start();
  	} catch (Exception ex) {
            ex.printStackTrace();
  	  logMessage("Problem creating experiment copy to run: "
  		     + ex.getMessage());
  	}
        }
      } else if (e.getSource() == m_StopBut) {
        m_StopBut.setEnabled(false);
        logMessage("User aborting experiment. ");
        if (m_Exp instanceof RemoteExperiment) {
  	logMessage("Waiting for remote tasks to "
  		   +"complete...");
        }
        ((ExperimentRunner)m_RunThread).abortExperiment();
        // m_RunThread.stop() ??
        m_RunThread = null;
      }
    }
    
    /**
     * Sends the supplied message to the log panel log area.
     *
     * @param message the message to log
     */
    protected void logMessage(String message) {
  
      m_Log.logMessage(message);
    }
  
    /**
     * Sends the supplied message to the log panel status line.
     *
     * @param message the status message
     */
    protected void statusMessage(String message) {
      
      m_Log.statusMessage(message);
    }
    
    /**
     * Tests out the run panel from the command line.
     *
     * @param args may contain options specifying an experiment to run.
     */
    public static void main(String [] args) {
  
      try {
        boolean readExp = Utils.getFlag('l', args);
        final String expFile = Utils.getOption('f', args);
        if (readExp && (expFile.length() == 0)) {
  	throw new Exception("A filename must be given with the -f option");
        }
        Experiment exp = null;
        if (readExp) {
  	FileInputStream fi = new FileInputStream(expFile);
  	ObjectInputStream oi = new ObjectInputStream(
  			       new BufferedInputStream(fi));
  	Object to = oi.readObject();
  	if (to instanceof RemoteExperiment) {
  	  exp = (RemoteExperiment)to;
  	} else {
  	  exp = (Experiment)to;
  	}
  	oi.close();
        } else {
  	exp = new Experiment();
        }
        System.err.println("Initial Experiment:\n" + exp.toString());
        final JFrame jf = new JFrame("Run Weka Experiment");
        jf.getContentPane().setLayout(new BorderLayout());
        final RunPanel sp = new RunPanel(exp);
        //sp.setBorder(BorderFactory.createTitledBorder("Setup"));
        jf.getContentPane().add(sp, BorderLayout.CENTER);
        jf.addWindowListener(new WindowAdapter() {
  	public void windowClosing(WindowEvent e) {
  	  System.err.println("\nExperiment Configuration\n"
  			     + sp.m_Exp.toString());
  	  jf.dispose();
  	  System.exit(0);
  	}
        });
        jf.pack();
        jf.setVisible(true);
      } catch (Exception ex) {
        ex.printStackTrace();
        System.err.println(ex.getMessage());
      }
    }
  }
  