/*******************************************************************************
* Copyright (c) 2009, A. Kaufmann and Elexis
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* A. Kaufmann - initial implementation
*
*******************************************************************************/
package com.hilotec.elexis.pluginstatistiken.config;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ch.elexis.core.ui.util.Log;
import com.hilotec.elexis.pluginstatistiken.Datensatz;
import com.hilotec.elexis.pluginstatistiken.PluginstatistikException;
/**
* Where-Klausel fuer eine Abfrage. (Eigentlich allgemein Bedingungsklauseln, wird beispielsweise
* auch fuer die Join-Bedingung benutzt).
*
* @author Antoine Kaufmann
*/
public class KonfigurationWhere {
private Element element;
public static final String ELEM_OR = "or";
public static final String ELEM_AND = "and";
public static final String ELEM_NOT = "not";
public static final String ELEM_EQUAL = "equal";
public static final String ELEM_GREATERTHAN = "greaterthan";
public static final String ELEM_LESSTHAN = "lessthan";
public static final String ATTR_A = "a";
public static final String ATTR_B = "b";
public static final String REGEX_PLUGINREF = "^\\[.*\\]$";
enum ElementTyp {
E_INVALID,
E_NOT, E_AND, E_OR,
E_EQUAL, E_GREATERTHAN, E_LESSTHAN,
};
/**
* Neue Where-Klausel erstellen
*
* @param e
* DOM—Element der Klausel
*/
public KonfigurationWhere(Element e){
element = e;
}
/**
* Interne Repraesentation des Typs anhand des DOM-Elements ausfindig machen.
*/
private ElementTyp getTyp(Element e){
String n = e.getTagName();
if (n.equals(ELEM_AND)) {
return ElementTyp.E_AND;
} else if (n.equals(ELEM_OR)) {
return ElementTyp.E_OR;
} else if (n.equals(ELEM_NOT)) {
return ElementTyp.E_NOT;
} else if (n.equals(ELEM_EQUAL)) {
return ElementTyp.E_EQUAL;
} else if (n.equals(ELEM_GREATERTHAN)) {
return ElementTyp.E_GREATERTHAN;
} else if (n.equals(ELEM_LESSTHAN)) {
return ElementTyp.E_LESSTHAN;
}
return ElementTyp.E_INVALID;
}
/**
* Hilfsfunktion um eine Liste aller Kindelemente eines DOM-Elements abzurufen (Nimmt nur die
* ELEMENT_NODE aus get Childnodes).
*/
private List<Element> getChildElements(Element parent){
ArrayList<Element> l = new ArrayList<Element>();
NodeList nl = parent.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
l.add((Element) n);
}
}
return l;
}
/**
* Wert eines Attributs eines DOM-Elements auslesen. Wenn dabei Referenzen auf Felder in eckigen
* Klammern enthalten sind, werden diese automatisch ersetzt.
*
* @param e
* Element
* @param name
* Name des Attributs
* @param ds
* Datensatz
*
* @return Wert des Attributs
* @throws PluginstatistikException
*/
private String attrValue(Element e, String name, Datensatz ds) throws PluginstatistikException{
String val = e.getAttribute(name);
// Wenn es sich um Verweise auf Feldnamen handelt, muessen wir
// die erst aufloesen
if (val.matches(REGEX_PLUGINREF)) {
String feld = ds.getFeld(val.substring(1, val.length() - 1));
if (feld == null) {
throw new PluginstatistikException("Ungueltige Referenz: '" + "'");
} else {
val = feld;
}
}
return val;
}
/**
* Hilfsfunktion, die prueft ob es sich bei einem String um einen rein numerischen Wert handelt.
*/
private boolean isNum(String val){
try {
Double.parseDouble(val);
} catch (NumberFormatException e) {
return false;
}
return true;
}
/**
* Hilfsfunktion fuers Abarbeiten der XML-Repraesentation einer Where- Klausel fuer einen
* bestimmten Datensatz. (Der ganze Kram wird rekursiv geparst)
*
* @param e
* Aktuelles DOM-Element das gerade verarbeitet wird.
* @throws PluginstatistikException
*/
private boolean matchesElement(Element e, Datensatz ds) throws PluginstatistikException{
ElementTyp typ = getTyp(e);
List<Element> children;
String a, b;
Double da, db;
switch (typ) {
case E_AND:
children = getChildElements(e);
for (int i = 0; i < children.size(); i++) {
if (!matchesElement(children.get(i), ds)) {
return false;
}
}
return true;
case E_OR:
children = getChildElements(e);
for (int i = 0; i < children.size(); i++) {
if (matchesElement(children.get(i), ds)) {
return true;
}
}
return false;
case E_NOT:
return !matchesElement(getChildElements(e).get(0), ds);
case E_EQUAL:
a = attrValue(e, ATTR_A, ds);
b = attrValue(e, ATTR_B, ds);
// Wenn es sich um Zahlen handelt, koennte ein einfacher
// Stringvergleich nicht das erwuenschte Ergebnis bringen
if (isNum(a) && isNum(b)) {
return (Double.parseDouble(a) == Double.parseDouble(b));
}
return a.equals(b);
case E_GREATERTHAN:
case E_LESSTHAN:
a = attrValue(e, ATTR_A, ds);
b = attrValue(e, ATTR_B, ds);
da = Double.parseDouble(a);
db = Double.parseDouble(b);
if ((typ == ElementTyp.E_GREATERTHAN) && (da > db)) {
return true;
} else if ((typ == ElementTyp.E_LESSTHAN) && (da < db)) {
return true;
}
return false;
case E_INVALID:
default:
Log.get("Messwertstatistiken").log("Ungueltige Operation: " + e.getTagName(),
Log.ERRORS);
return false;
}
}
/**
* Prueft ob der Datensatz zur Where-Klausel passt
*
* @throws PluginstatistikException
*/
public boolean matches(Datensatz ds) throws PluginstatistikException{
return matchesElement(element, ds);
}
}