package center.task.prm;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import ru.vassaev.core.XMLPath;
import ru.vassaev.core.base.Null;
import ru.vassaev.core.exception.SysException;
import ru.vassaev.core.types.Range;
import ru.vassaev.core.types.TimeList;
import ru.vassaev.core.util.Strings;
import ru.vassaev.core.util.Xml;
import center.task.CalculateException;
import center.task.Context;
/**
* Модификация значений
* Экземпляр создаётся на основе XML следующего вида:
* <modify>
* <set><if .../><path></path><value></value><set>
* <del><if type="[case's method]" name="[param's name]" grp="[gropup's name]"/><path></path><set>
* </modify>
* значения path и value могут быть ссылками на параметры
* Количество if не ограничено, if - всегда ссылка на параметр, все if объединяются
* в группу AND. Если условие AND = true или пусто, то операция преобразования выполняется
* Модифицирование выполняется последовательно, от первой инструкции к последней
* @author Vassaev A.V.
* @version 1.0 05/05/2012
*
*/
public class Modify {
public static abstract class Operation {
Object path;
ArrayList<Object> _ifs;
Operation(NodeList _if, Object path) {
this.path = path;
if(_if == null)
return;
int l = _if.getLength();
if (l > 0) {
_ifs = new ArrayList<Object>();
for(int i = 0; i < l; i++) {
Element e = (Element)_if.item(i);
Prm p = Prm.getLink(e);
String type = e.getAttribute("type");
if (p != null && type != null) {
try {
Method m = Case.getMethod(type);
_ifs.add(m);
_ifs.add(p);
} catch (SecurityException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NoSuchMethodException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
}
/**
* Проверка возможности преобразования (логическое AND)
* @param cntx - контекст
* @return - true, если выражение истинно.
* @throws CalculateException
*/
public final boolean check_case(Context cntx) throws CalculateException {
if (_ifs == null)
return true;
boolean r = true;
Object[] prms = new Object[1];
for (int i = 0, l = _ifs.size(); (i < l) && r;) {
Method m = (Method)_ifs.get(i++);
Prm p = (Prm)_ifs.get(i++);
try {
prms[0] = p.getObject(cntx);
Object res = m.invoke(Case.class, prms);
if (Null.equ(res))
return false;
r = r & (Boolean) res;
} catch (SysException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
return r;
}
/**
* Выполнение преобразования над объектом
* @param cntx - контекст текущей задачи
* @param o - объект, над которым производится преобразование
* @return - преобразованный объект
* @throws SysException - в случае ошибки при преобразовании
* @throws CalculateException
*/
abstract Object exec(Context cntx, Object o) throws SysException, CalculateException;
}
private final class DelPath extends Operation {
DelPath(NodeList _if, Object path) {
super(_if, path);
}
void exec0(Context cntx, Element e, String p) throws SysException {
XMLPath pth = new XMLPath(p);
Object n = pth.getXMLObject(e);
if (n == null)
return;
Node node = (Node)n;
Node pn = node.getParentNode();
if (pn == null)
return;
pn.removeChild(node);
}
void exec0(Context cntx, StringBuffer s, String p) throws SysException {
Range r = new Range(p);
r.delete(s);
}
public Object exec(Context cntx, Object o) throws SysException, CalculateException {
if (Null.equ(o))
return o;
String p = null;
if (path instanceof Prm)
p = ((Prm)path).getString(cntx);
else
p = Strings.getString(path);
Object m = o;
if (m instanceof Element) {
if (check_case(cntx))
exec0(cntx, (Element)m, p);
return m;
}
if(m instanceof String)
m = new StringBuffer().append(m);
if(m instanceof StringBuffer) {
if (check_case(cntx))
exec0(cntx, (StringBuffer)m, p);
return m;
}
return m;
}
}
private final class SetPath extends Operation {
Object value;
SetPath(NodeList _if, Object path, Object value) {
super(_if, path);
this.value = value;
}
void exec0(Context cntx, Element e, String p) throws SysException, CalculateException {
XMLPath pth = new XMLPath(p);
String v = null;
if (value instanceof Prm)
v = ((Prm)value).getString(cntx);
else
v = Strings.getString(value);
pth.setXMLValue(e, v);
}
void exec0(Context cntx, StringBuffer s, String p) throws SysException, CalculateException {
String v = null;
if (value instanceof Prm)
v = ((Prm)value).getString(cntx);
else
v = Strings.getString(value);
Range r = new Range(p);
r.insert(s, v);
}
Object exec(Context cntx, Object o) throws SysException, CalculateException {
if (Null.equ(o))
return o;
String p = null;
if (path instanceof Prm)
p = ((Prm)path).getString(cntx);
else
p = Strings.getString(path);
Object m = o;
if (m instanceof Element) {
if (check_case(cntx))
exec0(cntx, (Element)m, p);
return m;
}
if(m instanceof String)
m = new StringBuffer().append(m);
if(m instanceof StringBuffer) {
if (check_case(cntx))
exec0(cntx, (StringBuffer)m, p);
return m;
}
return m;
}
}
private final List<Operation> opers = new ArrayList<Operation>();
protected final void addOperation(Operation oper) {
opers.add(oper);
}
public Modify(Element e) {
if (e == null)
return;
NodeList nl = e.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node n = nl.item(i);
if (n.getNodeType() != Node.ELEMENT_NODE)
continue;
Element el = (Element) n;
if (el.getTagName().equals("set")) {
Attr apath = el.getAttributeNode("path");
Object path;
if (apath == null) {
Element epath = (Element)Strings.getXMLObject(el, "path");
path = Prm.getPrm(epath);
}
else
path = apath.getValue();
Object value;
Attr avalue = el.getAttributeNode("value");
if (avalue == null) {
Element evalue = (Element)Strings.getXMLObject(el, "value");
value = Prm.getPrm(evalue);
} else
value = avalue.getValue();
NodeList _if = Xml.getElementsByTagName(el, "if");
opers.add(new SetPath(_if, path, value));
} else if (el.getTagName().equals("del")) {
Object path = el.getAttribute("path");
if (path == null)
path = Prm.getPrm(el, "path");
NodeList _if = Xml.getElementsByTagName(el, "if");
opers.add(new DelPath(_if, path));
}
}
}
public final Object exec(TimeList tl, Context cntx, Object value) throws CalculateException {
Object v = value;
for (Operation o : opers) try {
v = o.exec(cntx, v);
} catch (SysException e) {
e.printStackTrace();
}
return v;
}
private static class Case {
private static final Class<?>[] prms = new Class[]{Object.class};
public static Method getMethod(String str) throws SecurityException, NoSuchMethodException {
return Case.class.getMethod(str, prms);
}
public static Boolean ifPrm(Object val) {
return Strings.parseBooleanNvl(val, false);
}
public static Boolean ifNotPrm(Object val) {
return !Strings.parseBooleanNvl(val, false);
}
public static Boolean ifPrmIsEmpty(Object val) {
if (Null.equ(val))
return false;
if (val instanceof StringBuffer)
return ((StringBuffer)val).length() == 0;
String v = Strings.getString(val);
return v.isEmpty();
}
public static Boolean ifNotPrmIsEmpty(Object val) {
if (Null.equ(val))
return true;
if (val instanceof StringBuffer)
return ((StringBuffer)val).length() != 0;
String v = Strings.getString(val);
return !v.isEmpty();
}
public static Boolean ifPrmIsNull(Object val) {
return Null.equ(val);
}
public static Boolean ifNotPrmIsNull(Object val) {
return !Null.equ(val);
}
}
}