package de.uni_passau.fim.infosun.prophet.plugin.plugins;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.Vector;
import javax.swing.JOptionPane;
import de.uni_passau.fim.infosun.prophet.experimentViewer.EViewer;
import de.uni_passau.fim.infosun.prophet.plugin.Plugin;
import de.uni_passau.fim.infosun.prophet.util.language.UIElementNames;
import de.uni_passau.fim.infosun.prophet.util.qTree.Attribute;
import de.uni_passau.fim.infosun.prophet.util.qTree.QTreeNode;
import de.uni_passau.fim.infosun.prophet.util.settings.Setting;
import de.uni_passau.fim.infosun.prophet.util.settings.SettingsList;
import de.uni_passau.fim.infosun.prophet.util.settings.components.CheckBoxSetting;
import de.uni_passau.fim.infosun.prophet.util.settings.components.TextFieldSetting;
import static de.uni_passau.fim.infosun.prophet.util.qTree.QTreeNode.Type.CATEGORY;
import static de.uni_passau.fim.infosun.prophet.util.qTree.QTreeNode.Type.EXPERIMENT;
public class MaxTimePlugin implements Plugin {
public class TimeOut implements Runnable {
private long startTime;
private long duration;
private boolean started;
private boolean stopped;
private Thread myThread;
private String message;
private boolean disable;
private boolean submit;
private QTreeNode node;
private TimeOut(QTreeNode node, long duration, String message, boolean disable, boolean submit) {
this.node = node;
this.duration = duration;
this.message = message;
this.disable = disable;
this.submit = submit;
stopped = false;
}
public boolean start() {
if (!started && duration > 0) {
started = true;
startTime = System.currentTimeMillis();
myThread = new Thread(this);
myThread.start();
return true;
}
return false;
}
public boolean stop() {
if (started && !stopped) {
stopped = true;
duration = Math.max(0, duration - (System.currentTimeMillis() - startTime));
myThread.interrupt();
if (duration == 0) {
action();
}
return true;
}
return false;
}
public boolean resume() {
if (started && stopped && duration > 0) {
stopped = false;
startTime = System.currentTimeMillis();
myThread = new Thread(this);
myThread.start();
return true;
}
return false;
}
private void action() {
boolean affected = node == null || isTimeOutAffectedBy(currentNode, node);
if (message != null && message.length() > 0) {
if (affected) {
JOptionPane.showMessageDialog(experimentViewer, message);
} else {
allMessages.put(node, message);
}
}
if (node != null && disable) {
timeOuts.add(node);
if (submit && affected) {
experimentViewer.nextNode(true, true);
}
}
}
@Override
public void run() {
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
return;
}
stop();
}
}
private static final String KEY = "max_time";
private static final String KEY_MAX_TIME = "time";
private static final String KEY_HARD_EXIT = "hard_exit";
private static final String KEY_HARD_EXIT_WARNING = "show_warning";
private static final String KEY_HARD_EXIT_WARNING_TIME = "warning_time";
private static final String KEY_HARD_EXIT_WARNING_MESSAGE = "warning_message";
private static final String KEY_IGNORE_TIMEOUT = "ignore_timeout";
private static final String KEY_MESSAGE = "message";
private EViewer experimentViewer;
private Map<QTreeNode, String> allMessages = new HashMap<>();
private Map<QTreeNode, Vector<TimeOut>> allClocks = new HashMap<>();
private Set<QTreeNode> timeOuts = new HashSet<>();
private QTreeNode experimentNode;
private QTreeNode currentNode;
private boolean activateForExperiment;
@Override
public Setting getSetting(QTreeNode node) {
Attribute resultAttribute = node.getAttribute(KEY);
SettingsList result = new SettingsList(resultAttribute, getClass().getSimpleName(), true);
result.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_TIME_OUT"));
Attribute subAttribute = resultAttribute.getSubAttribute(KEY_MAX_TIME);
Setting subSetting = new TextFieldSetting(subAttribute, null);
switch (node.getType()) {
case EXPERIMENT:
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_MAX_TIME_EXPERIMENT"));
break;
case CATEGORY:
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_MAX_TIME_CATEGORY"));
break;
case QUESTION:
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_MAX_TIME_QUESTION"));
break;
}
result.addSetting(subSetting);
Attribute hardExitAttribute = resultAttribute.getSubAttribute(KEY_HARD_EXIT);
SettingsList hardExit = new SettingsList(hardExitAttribute, null, true);
hardExit.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_HARD_TIME_OUT"));
Attribute warningAttribute = hardExitAttribute.getSubAttribute(KEY_HARD_EXIT_WARNING);
SettingsList warning = new SettingsList(warningAttribute, null, true);
warning.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_TIME_OUT_WARN_SUBJECTS"));
subAttribute = warningAttribute.getSubAttribute(KEY_HARD_EXIT_WARNING_TIME);
subSetting = new TextFieldSetting(subAttribute, null);
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_TIME_OUT_WARNING_TIME") + ':');
warning.addSetting(subSetting);
subAttribute = warningAttribute.getSubAttribute(KEY_HARD_EXIT_WARNING_MESSAGE);
subSetting = new TextFieldSetting(subAttribute, null);
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_TIME_OUT_WARNING_MESSAGE") + ':');
warning.addSetting(subSetting);
hardExit.addSetting(warning);
result.addSetting(hardExit);
subAttribute = resultAttribute.getSubAttribute(KEY_MESSAGE);
subSetting = new TextFieldSetting(subAttribute, null);
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_TIME_OUT_MESSAGE") + ':');
result.addSetting(subSetting);
if (node.getType() == CATEGORY) {
subAttribute = resultAttribute.getSubAttribute(KEY_IGNORE_TIMEOUT);
subSetting = new CheckBoxSetting(subAttribute, null);
subSetting.setCaption(UIElementNames.getLocalized("MENU_TAB_SETTINGS_IGNORE_TIME_OUT"));
result.addSetting(subSetting);
}
return result;
}
@Override
public void experimentViewerRun(EViewer experimentViewer) {
this.experimentViewer = experimentViewer;
}
private boolean isTimeOuted(QTreeNode node) {
while (node != null) {
if (timeOuts.contains(node)) {
return true;
}
if (Boolean.parseBoolean(node.getAttribute(KEY_IGNORE_TIMEOUT).getValue())) {
return false;
}
node = node.getParent();
}
return false;
}
private boolean isTimeOutAffectedBy(QTreeNode node, QTreeNode timeOutNode) {
while (node != null) {
if (node == timeOutNode) {
return true;
}
if (Boolean.parseBoolean(node.getAttribute(KEY_IGNORE_TIMEOUT).getValue())) {
System.out.println("<-- false (hero: " + node.getName() + ')');
return false;
}
node = node.getParent();
}
return false;
}
@Override
public boolean denyEnterNode(QTreeNode node) {
if (allMessages.size() > 0) {
Iterator<Entry<QTreeNode, String>> it = allMessages.entrySet().iterator();
while (it.hasNext()) {
Entry<QTreeNode, String> entry = it.next();
if (isTimeOutAffectedBy(node, entry.getKey())) {
JOptionPane.showMessageDialog(experimentViewer, entry.getValue());
it.remove();
}
}
}
return isTimeOuted(node);
}
private void startTimers(QTreeNode node) {
Vector<TimeOut> nodeClocks = allClocks.get(node);
if (nodeClocks == null) {
boolean enabled = Boolean.parseBoolean(node.getAttribute(KEY).getValue());
if (!enabled) {
return;
}
Attribute pluginNode = node.getAttribute(KEY);
nodeClocks = new Vector<>();
allClocks.put(node, nodeClocks);
long maxTime = Long.parseLong(pluginNode.getSubAttribute(KEY_MAX_TIME).getValue());
if (node.getType() == EXPERIMENT) {
maxTime *= 60;
}
String message = pluginNode.getSubAttribute(KEY_MESSAGE).getValue();
if (maxTime <= 0) {
return;
}
boolean hard = Boolean.parseBoolean(pluginNode.getSubAttribute(KEY_HARD_EXIT).getValue());
TimeOut mainTimeOut = new TimeOut(node, maxTime * 1000, message, true, hard);
nodeClocks.add(mainTimeOut);
mainTimeOut.start();
if (!hard) {
return;
}
Attribute hardNode = pluginNode.getSubAttribute(KEY_HARD_EXIT);
boolean hardWarning = Boolean.parseBoolean(hardNode.getSubAttribute(KEY_HARD_EXIT_WARNING).getValue());
if (!hardWarning) {
return;
}
Attribute hardWarningNode = hardNode.getSubAttribute(KEY_HARD_EXIT_WARNING);
String hardWarningTimeString = hardWarningNode.getSubAttribute(KEY_HARD_EXIT_WARNING_TIME).getValue();
String hardWarningMessage = hardWarningNode.getSubAttribute(KEY_HARD_EXIT_WARNING_MESSAGE).getValue();
if (hardWarningTimeString == null || hardWarningTimeString.length() > 0 ||
hardWarningMessage == null || hardWarningMessage.length() > 0) {
return;
}
long hardWarningTime = maxTime - Long.parseLong(hardWarningTimeString);
if (hardWarningTime <= 0) {
return;
}
TimeOut warningTimeOut = new TimeOut(node, hardWarningTime * 1000, hardWarningMessage, false, false);
nodeClocks.add(warningTimeOut);
warningTimeOut.start();
} else {
for (TimeOut clock : nodeClocks) {
clock.resume();
}
}
}
@Override
public void enterNode(QTreeNode node) {
currentNode = node;
if (node.getType() == EXPERIMENT) {
experimentNode = node;
activateForExperiment = true;
return;
}
if (activateForExperiment) {
startTimers(experimentNode);
activateForExperiment = false;
}
startTimers(node);
}
@Override
public String denyNextNode(QTreeNode currentNode) {
return null;
}
@Override
public void exitNode(QTreeNode node) {
Vector<TimeOut> nodeClocks = allClocks.get(node);
if (nodeClocks != null) {
for (TimeOut clock : nodeClocks) {
clock.stop();
}
}
}
@Override
public String finishExperiment() {
return null;
}
}