package org.das2.client;
import java.awt.Dimension;
import java.awt.Component;
import java.io.IOException;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
import javax.swing.JOptionPane;
import javax.swing.JCheckBox;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JList;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import javax.xml.xpath.XPathFactory;
import javax.xml.xpath.XPathConstants;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JComponent;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
* Code for editing a Das2Server parameters argument. This is a somewhat
* arbitary control, but the DSDF may try to describe a GUI, using the
* spec at https://github.com/das-developers/das2docs/wiki/Structured-Sub%E2%80%90values-for-Params
*
*
* Das2ServerGUI x = new Das2ServerGUI();
* String dsdf = "param_01 = '1.5V_REF | Simulate +1.8 monitor'\n"
* + "param_02 = '1.5V_WvFE'\n"
* + "param_03 = '1.5V_Y180'\n"
* + "param_04 = '1.8U | Power Supply'\n"
* + "param_05 = '1.8V_MEM'";
* x.setSpecification(dsdf);
* x.setParameters("1.5V_REF 1.5V_REF 1.8V_MEM");
* if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(null, x.panel)) {
* System.err.println(x.getParameters());
* }
*
* @author jbf
*/
public class Das2ServerGUI {
/**
* Read the Das2Server container for DSDF
*
* @param xmlsrc
* @return string array
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
* @throws XPathExpressionException
*/
private String[] readXML(String xmlsrc) throws SAXException, IOException, ParserConfigurationException, XPathExpressionException {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
InputSource inputsrc = new InputSource(new StringReader(xmlsrc));
Document doc = builder.parse(inputsrc);
XPath xp = XPathFactory.newInstance().newXPath();
Node nn = (Node) xp.evaluate("//properties", doc, XPathConstants.NODE);
LinkedHashMap mm = new LinkedHashMap();
ArrayList ll = new ArrayList(100);
for (int i = 0; i < 100; i++) {
ll.add(i, "");
}
NamedNodeMap aa = nn.getAttributes();
for (int i = 0; i < aa.getLength(); i++) {
Node itm = aa.item(i);
if (itm.getNodeName().startsWith("param_")) {
int idx = Integer.parseInt(itm.getNodeName().substring(6));
ll.set(idx, itm.getNodeValue());
}
}
return (String[]) ll.toArray(new String[ll.size()]);
}
/**
* parse integer which may start with one 0.
*
* @param s
* @return
*/
private static int parseInt(String s) {
s = s.trim();
if (s.startsWith("0")) {
return Integer.parseInt(s.substring(1));
} else {
return Integer.parseInt(s);
}
}
/**
* Read the DSDF source file
*/
private String[] readDsdf(String dsdfsrc) {
ArrayList ll = new ArrayList(100);
for (int i = 0; i < 100; i++) {
ll.add(i, "");
}
for (String line : dsdfsrc.split("\n")) {
if (line.startsWith("param_")) {
int ieq = line.indexOf("=");
int idx = parseInt(line.substring(0, ieq).substring(6));
String vv = line.substring(ieq + 1).trim();
if ((vv.charAt(0) == '\'') && (vv.charAt(vv.length() - 1) == '\'')) {
vv = vv.substring(1, vv.length() - 1);
}
ll.set(idx, vv);
}
}
return (String[]) ll.toArray(new String[ll.size()]);
}
/**
* if template=xxx@bb and sval=xxxJbb then return J otherwise return empty
* string
*
* @param template
* @param sval
* @return
*/
private String checkMatch(String template, String sval) {
template = template.trim();
sval = sval.trim();
if (template.indexOf("@") > -1) {
int idx = template.indexOf("@");
int i = sval.length() - template.length() - idx - 1;
if (template.substring(0, idx).equals(sval.substring(0, idx)) && template.substring(idx + 1).equals(sval.substring(i))) {
return sval.substring(idx, (idx + sval.length() - template.length() + 1));
} else {
return "";
}
} else {
if (template.equals(sval)) {
return sval;
} else {
return "";
}
}
}
private int index(String[] arr, String search) {
for (int i = 0; i < arr.length; i++) {
if (arr[i].equals(search)) {
return i;
}
}
return -1;
}
/**
* return the value from paramsArr or '' (empty string). template can be a
* template or a regex
*
* @param paramsArr
* @param ss0
* @param template
* @return
*/
private String findParamValue(String[] paramsArr, String ss0, String template) {
try {
if (template == null) {
int idx = index(paramsArr, ss0);
if (idx == -1) {
return "";
} else {
paramsArr[idx]= "";
return ss0;
}
} else {
if (template.charAt(0) == '^') {
String regex = template;
Pattern pattern = Pattern.compile(regex);
int idx=0;
for (String item : paramsArr) {
Matcher match = pattern.matcher(item);
if (match != null) {
paramsArr[idx]= "";
return item;
}
idx++;
}
return "";
} else {
String[] templates = template.split("\\s+");
int i = 0;
int ipa = 0;
while (i < templates.length) {
while ((ipa < paramsArr.length) && (i < templates.length)) {
String item = paramsArr[ipa].trim();
String match = checkMatch(templates[i], item);
if (match.length() == 0) {
return "";
} else {
if (templates[i].contains("@")) {
paramsArr[ipa]="";
return match;
} else {
paramsArr[ipa]="";
ipa = ipa + 1;
i = i + 1;
}
}
}
}
return "";
}
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("param not found: " + ss0);
return "";
}
}
private void setSelectedListItems(Component jcomponent, String[] allItems, String[] items) {
// JList handling code removed...
JPanel jPanel = (JPanel) jcomponent;
for (Component b : jPanel.getComponents()) {
JCheckBox tp = (JCheckBox) b;
String item = tp.getName();
try {
int idx = index(items, item);
if (idx > -1) {
tp.setSelected(true);
}
} catch (Exception e) {
continue;
}
}
}
private List getSelectedListItems(Component jcomponent) {
if (jcomponent instanceof JList) {
return ((JList) jcomponent).getSelectedValuesList();
} else {
ArrayList resultList = new ArrayList();
JPanel jList = (JPanel) jcomponent;
for (Component c : jList.getComponents()) {
JCheckBox b = (JCheckBox) c;
if (b.isSelected()) {
resultList.add(b.getText());
}
}
return resultList;
}
}
private String getRegex(String t) {
// "Return the regular expression for the template. The first field will be the @ symbol value";
return t.replaceAll("@", "(\\S+)");
}
private String[] ll;
private String[] tt; // types
private String[] ff; // formats (--dftlen @)
private String[] ss; // special arguments for the GUI type, like sep
private JComponent[] cc;
private JPanel panel;
/**
* set the DSDF specification for the parameters. This can be an XML document
* or a list of IDL name/value pairs.
* @param sss
*/
public void setSpecification(String sss) {
if ( sss.length()<4 ) {
throw new IllegalArgumentException("control string is too short");
}
if ( sss.substring(0, 4).equals("[00]") ){
sss = sss.substring(10);
}
if ( sss.trim().startsWith("<") ) {
try {
ll = readXML(sss);
} catch (SAXException | IOException | ParserConfigurationException | XPathExpressionException ex) {
Logger.getLogger("das2").log(Level.SEVERE, null, ex);
}
} else {
ll = readDsdf(sss);
}
tt = new String[101];
ff = new String[101];
ss = new String[101];
cc = new JComponent[101];
}
public void setParameters(String paramz) {
String delim= "\\s+"; //TODO: delim
String delimRaw=" ";
String[] paramsArr = paramz.split(delim);
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
boolean extra = false;
for (int i = 0; i < 100; i++) {
String itm = ll[i];
if (itm.length() > 0) {
itm = itm.trim();
ss = itm.split("\\s*\\|\\s*", -2);
int narg = ss.length;
JComponent c2 = null;
if (narg == 1) {
JCheckBox c = new JCheckBox(ss[0]);
String vv = findParamValue(paramsArr, ss[0], null);
if (vv.length() > 0) {
c.setSelected(true);
}
tt[i] = "JCheckBox";
panel.add(c);
c2 = c;
} else if (narg == 2) {
JCheckBox c = new JCheckBox(ss[0] + ": " + ss[1]);
String vv = findParamValue(paramsArr, ss[0], null);
if (vv.length() > 0) {
c.setSelected(true);
}
tt[i] = "JCheckBox";
panel.add(c);
c2 = c;
} else if (narg == 3) {
panel.add(new JLabel(ss[0] + ": " + ss[1]));
JTextField c = new JTextField("");
c.setMaximumSize(new Dimension(8000, c.getPreferredSize().height));
String vv = findParamValue(paramsArr, ss[0], null);
ff[i] = ss[2];
vv = findParamValue(paramsArr, ss[0], ss[2]);
if (vv.length() > 0) {
c.setText(vv);
}
tt[i] = "JTextField";
panel.add(c);
c2 = c;
} else if (narg == 4) {
if (ss[3].startsWith("set:")) {
panel.add(new JLabel(ss[0] + ": " + ss[1]));
String[] sepAllItems = ss[3].substring(4).trim().split("\\s+");
String[] allItems = Arrays.copyOfRange(sepAllItems, 1, sepAllItems.length);
String sep = sepAllItems[0];
ss[i] = sep;
JPanel panel1 = new JPanel();
panel1.setLayout(new BoxLayout(panel1, BoxLayout.X_AXIS));
for (String item : allItems) {
JCheckBox b1 = new JCheckBox(item);
b1.setSelected(false);
panel1.add(b1);
}
c2 = panel1;
String itemMatch = String.join("|", allItems);
String regex = String.format("^(%s)(?:%s(%s))*$", itemMatch, sep, itemMatch);
String vv = findParamValue(paramsArr, ss[0], regex);
if (vv.length() > 0) {
String[] items = vv.split(sep);
setSelectedListItems(c2, allItems, items);
}
tt[i] = "JList";
} else {
panel.add(new JLabel(ss[0] + ": " + ss[1] + " (" + ss[3] + ")"));
JTextField c = new JTextField("");
c2 = c;
c.setMaximumSize(new Dimension(8000, c.getPreferredSize().height));
String vv = findParamValue(paramsArr, ss[0], null);
ff[i] = ss[2];
vv = findParamValue(paramsArr, ss[0], ss[2]);
if (vv.length() > 0) {
c.setText(vv);
}
tt[i] = "JTextField";
}
panel.add(c2);
} else {
extra = true;
}
if (c2 != null) {
panel.add(c2);
cc[i] = c2;
c2.setAlignmentX(Component.LEFT_ALIGNMENT);
}
}
}
StringBuilder extraArgs= new StringBuilder();
for ( int i=0; i0 ) {
extraArgs.append(paramsArr[i]);
}
if ( i>0 ) extraArgs.append(delimRaw);
}
if ( extra || extraArgs.length()>0 ) {
panel.add(new JLabel("Text not described in DSDF"));
JTextArea c = new JTextArea();
c.setAlignmentX(Component.LEFT_ALIGNMENT);
c.setText(extraArgs.toString());
c.setRows(4);
panel.add(c);
cc[100] = c;
}
}
public String getParameters() {
String delim = " ";
StringBuilder parametersBuilder = new StringBuilder();
for (int i = 0; i < 100; i++) {
if (cc[i] == null) {
} else if (tt[i].equals("JCheckBox")) {
if (((JCheckBox) cc[i]).isSelected()) {
String txt = ((JCheckBox) cc[i]).getText();
int i2 = txt.indexOf(": ");
if (i2 > -1) {
txt = txt.substring(0, i2);
}
parametersBuilder.append(txt);
parametersBuilder.append(delim);
}
} else if (tt[i].equals("JTextField")) {
String s = ((JTextField) cc[i]).getText();
if (s.length() > 0) {
s = ff[i].replace("@", s);
parametersBuilder.append(s);
parametersBuilder.append(delim);
}
} else if (tt[i].equals("JList")) {
List selectedItems = getSelectedListItems(cc[i]);
String sep = ss[i];
parametersBuilder.append(String.join(sep, selectedItems));
parametersBuilder.append(delim);
}
}
if (cc[100] != null) {
parametersBuilder.append(delim);
String txt = ((JTextArea) cc[100]).getText().replace("\n", delim);
txt = txt.trim();
parametersBuilder.append(txt);
}
return parametersBuilder.toString();
}
/**
* return the panel. See the javadoc for how this is to be called.
* Note this will typically need to be put into a scrollpane.
* @return
*/
public JPanel getPanel() {
return panel;
}
public static void main(String[] args) {
Das2ServerGUI x = new Das2ServerGUI();
int test=2;
String dsdf;
String params0;
switch ( test ) {
case 1:
dsdf = "param_01 = '1.5V_REF | Simulate +1.8 monitor'\n"
+ "param_02 = '1.5V_WvFE'\n"
+ "param_03 = '1.5V_Y180'\n"
+ "param_04 = '1.8U | Power Supply'\n"
+ "param_05 = '1.8V_MEM'";
params0="1.5V_REF 1.8V_MEM Extra-Unrecognized";
break;
case 2:
dsdf = "param_01 = 'packet_ids|Output data from the following packet IDs (defaults to all)|@|set: , x242 x252'\n";
params0="";
break;
default:
throw new IllegalArgumentException("bad test number");
}
x.setSpecification(dsdf);
x.setParameters(params0);
if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(null, x.panel, "Edit params", JOptionPane.OK_CANCEL_OPTION )) {
System.err.println(x.getParameters());
}
}
}