package hr.fer.zemris.ecf.gui.layout;
import hr.fer.zemris.ecf.console.IObserver;
import hr.fer.zemris.ecf.console.ISubject;
import hr.fer.zemris.ecf.console.Job;
import hr.fer.zemris.ecf.gui.ECFLab;
import hr.fer.zemris.ecf.gui.Utils;
import hr.fer.zemris.ecf.gui.model.conf.ConfigurationKey;
import hr.fer.zemris.ecf.param.AlgGenRegUser;
import hr.fer.zemris.ecf.param.Algorithm;
import hr.fer.zemris.ecf.param.Entry;
import hr.fer.zemris.ecf.param.Genotype;
import hr.fer.zemris.ecf.param.Registry;
import hr.fer.zemris.ecf.tasks.TaskMannager;
import hr.fer.zemris.ecf.xmldom.XmlWriting;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.SwingUtilities;
/**
* Panel that displays available parameters for the selected ECF executable
* file. When all the parameters are selected, configuration can be ran.
* Configuration and log files are created on the specified paths.
*
* @author Domagoj Stanković
* @version 1.0
*/
public class ParametersSelection extends JPanel implements IObserver {
private static final long serialVersionUID = 1L;
private static final boolean DAEMON = false;
private ECFLab parent;
private EntryBlockSelection<Algorithm> algSel;
private EntryBlockSelection<Genotype> genSel;
private EntryListPanel regList;
private String ecfPath;
private DefinePanel definePanel;
private String lastLogFilePath = null;
/**
* Creates new {@link ParametersSelection} object for choosing ECF
* parameters.
*
* @param parent
* {@link ECFLab} frame that displays this panel
*/
public ParametersSelection(ECFLab parent) {
super(new BorderLayout());
this.parent = parent;
ecfPath = parent.getEcfPath();
if (ecfPath == null) {
throw new NullPointerException("ECF executable file undefined!");
}
algSel = new EntryBlockSelection<>(new DropDownPanel<>(parent.getParDump().algorithms));
genSel = new EntryBlockSelection<>(new DropDownPanel<>(parent.getParDump().genotypes));
regList = EntryListPanel.getComponent(parent.getParDump().registry.getEntryList());
String file = parent.getConfiguration().getValue(ConfigurationKey.DEFAULT_PARAMS_PATH);
String log = parent.getConfiguration().getValue(ConfigurationKey.DEFAULT_LOG_PATH);
// add(new JScrollPane(new TempPanel(algSel, genSel, regList)),
// BorderLayout.CENTER);
// add(new TempPanel(new JScrollPane(algSel), new JScrollPane(genSel),
// new JScrollPane(regList)), BorderLayout.CENTER);
add(new TempPanel(algSel, genSel, new JScrollPane(regList)), BorderLayout.CENTER);
JButton button = new JButton(new AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
clicked();
}
});
button.setText("Run");
int cores = Runtime.getRuntime().availableProcessors();
definePanel = new DefinePanel(file, log, cores, button);
add(definePanel, BorderLayout.SOUTH);
}
/**
* Action performed when the "Run" button is clicked. Configuration file is
* created under the specified path. Then the ECF exe is run and the results
* are written to the log file under the specified path.
*/
protected void clicked() {
try {
AlgGenRegUser temp = getParameters();
String file = definePanel.getParamsPath();
String log = definePanel.getLogPath();
lastLogFilePath = log;
int pn = definePanel.getThreadsCount();
boolean change = false;
int repeats = 1;
List<Entry> list = temp.registry.getEntryList();
Entry e = Utils.findEntry(list, "batch.repeats");
if (pn > 1) {
if (e != null) {
repeats = Integer.parseInt(e.value);
if (repeats > 1) {
// N repeats, N threads -> separate repeats in N jobs (1 repeat per job)
e.value = "1";
change = true;
} else {
// 1 job (1 repeat), N threads -> change to 1 thread
pn = 1;
}
} else {
// 1 job, N threads -> change to 1 thread
pn = 1;
}
} else {
if (e != null) {
repeats = Integer.parseInt(e.value);
if (repeats > 1) {
Entry l = Utils.findEntry(list, "log.filename");
if (l != null) {
String value = l.value;
FileWriter fw = new FileWriter(log + Utils.LOG_EXT);
fw.write(repeats + "\n");
fw.write(value);
fw.close();
}
}
}
}
XmlWriting.write(file, temp);
final List<Job> jobs;
if (change) {
jobs = new ArrayList<>(repeats);
for (int i = 0; i < repeats; i++) {
String newLog = Utils.addBeforeExtension(log, (i + 1), String.valueOf(repeats).length());
Job job = new Job(ecfPath, newLog, file);
job.setObserver(this);
jobs.add(job);
}
} else {
jobs = new ArrayList<>(1);
Job job = new Job(ecfPath, log, file);
job.setObserver(this);
jobs.add(job);
}
final int tCount = pn;
Thread t = new Thread(new Runnable() {
@Override
public void run() {
TaskMannager tm = new TaskMannager();
try {
tm.startTasks(jobs, tCount);
} catch (Exception e) {
e.printStackTrace();
}
}
});
t.setDaemon(DAEMON);
t.start();
} catch (Exception e) {
String message = e.getMessage();
if (message.startsWith("java.lang.Exception: ")) {
message = message.substring(21);
}
parent.reportError(message);
parent.getLogger().log(e);
}
}
/**
* Collects all the selected parameters from the selected
* {@link ParametersSelection} panel.
*
* @return {@link AlgGenRegUser} object containing all the selected
* parameters
*/
public AlgGenRegUser getParameters() {
// Algorithm filling
List<EntryFieldDisplay<Algorithm>> algList = algSel.getAddedEntries();
List<Algorithm> algs = new ArrayList<>(algList.size());
for (EntryFieldDisplay<Algorithm> a : algList) {
algs.add(new Algorithm(a.getBlock().getName(), a.getBlockDisplay().getSelectedEntries()));
}
// Genotype filling
List<EntryFieldDisplay<Genotype>> genList = genSel.getAddedEntries();
List<Genotype> gens = new ArrayList<>(genList.size());
for (EntryFieldDisplay<Genotype> g : genList) {
gens.add(new Genotype(g.getBlock().getName(), g.getBlockDisplay().getSelectedEntries()));
}
List<List<Genotype>> genBlock = new ArrayList<>(1);
genBlock.add(gens);
// Registry filling
int size = regList.getEntriesCount();
List<Entry> entries = new ArrayList<>();
for (int i = 0; i < size; i++) {
if (regList.isSelected(i)) {
entries.add(new Entry(regList.getKeyAt(i), regList.getDescriptionAt(i), regList.getValueAt(i)));
}
}
Registry reg = new Registry(entries);
AlgGenRegUser temp = new AlgGenRegUser();
temp.algorithm = algs;
temp.genotypes = genBlock;
temp.registry = reg;
return temp;
}
/**
* @return {@link AlgorithmSelection} from the selected
* {@link ParametersSelection} panel
*/
public EntryBlockSelection<Algorithm> getAlgSel() {
return algSel;
}
/**
* @return {@link GenotypeSelection} from the selected
* {@link ParametersSelection} panel
*/
public EntryBlockSelection<Genotype> getGenSel() {
return genSel;
}
/**
* @return {@link EntryFieldPanel} representing Registry from the selected
* {@link ParametersSelection} panel
*/
public EntryListPanel getRegList() {
return regList;
}
/**
* @return Selected {@link Algorithm} from the selected
* {@link ParametersSelection} panel
*/
public Algorithm getSelectedAlgorithm() {
return algSel.getSelectedItem();
}
/**
* @return Selected {@link Genotype} from the selected
* {@link ParametersSelection} panel
*/
public Genotype getSelectedGenotype() {
return genSel.getSelectedItem();
}
/**
* @return {@link DefinePanel} containing information about configuration
* and log files paths
*/
public DefinePanel getDefinePanel() {
return definePanel;
}
@Override
public void update(final ISubject subject) throws Exception {
// String logFile = subject.getMessage();
// parent.getResultDisplay().displayResult(logFile);
// subject.removeObserver();
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
String logFile = subject.getMessage();
synchronized (parent) {
try {
parent.getResultDisplay().displayResult(logFile);
} catch (Exception e) {
parent.getLogger().log(e);
parent.reportError(e.getMessage());
}
}
subject.removeObserver();
}
});
}
/**
* Panel used for grouping {@link AlgorithmSelection},
* {@link GenotypeSelection} and {@link EntryFieldPanel} panels.
*
* @author Domagoj Stanković
* @version 1.0
*/
private static class TempPanel extends JPanel {
private static final long serialVersionUID = 1L;
public TempPanel(Component algSel, Component genSel, Component regList) {
super();
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(algSel);
add(new JSeparator(JSeparator.VERTICAL));
add(genSel);
add(new JSeparator(JSeparator.VERTICAL));
add(regList);
}
}
/**
* @return <code>true</code> if "Run" button was ever run before,
* <code>false</code> otherwise
*/
public boolean wasRunBefore() {
return lastLogFilePath == null ? false : true;
}
/**
* @return Path to the log file created during last experiment,
* <code>null</code> if selected experiment was never run before
*/
public String getLastLogFilePath() {
return lastLogFilePath;
}
}