package jas.hist;
import jas.hist.normalization.Normalizer;
import jas.util.xml.XMLNodeTraverser;
import java.lang.reflect.Constructor;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
/**
* Build a DataSource from a DOM node
*/
class Data1DTraverser extends XMLNodeTraverser
{
Data1DTraverser(Node node) throws BadXMLException
{
traverse(node);
}
protected void handleElement(Element node, String name) throws BadXMLException
{
if (name.equals("bins1d")) b1d = new Bins1DNodeTraverser(node);
else if (name.equals("points")) xy = new XYPointsNodeTraverser(node);
else if (name.equals("binnedDataAxisAttributes")) baa = new BinnedDataAxisAttributesNodeTraverser(node);
else if (name.equals("pointDataAxisAttributes")) paa = new PointDataAxisAttributesNodeTraverser(node);
else if (name.equals("class")) ct = new ClassNodeTraverser(node);
else if (name.equals("datasource")) ct = new DataSourceNodeTraverser(node);
else if (name.equals("statistics")) stats = new StatisticsTraverser(node);
else if (name.equals("axisLabels")) labels = new AxisLabelsTraverser(node);
else if (name.equals("style1d")) st.traverse(node,style=new JASHist1DHistogramStyle());
else if (name.equals("normalization")) norm = new NormalizationTraverser(node);
else super.handleElement(node,name);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("axis")) yAxis = toInt(value.substring(1));
else if (name.equals("name")) refName = value;
else super.handleAttributeNode(node,name,value);
}
DataSource getDataSource()
{
if (ct != null) return ct.getDataSource();
else if (b1d != null) return new XML1DHistDataSource(b1d,baa,labels,stats);
else return new XMLXYDataSource(xy,paa,stats);
}
int getYAxis()
{
return yAxis;
}
JASHistStyle getStyle()
{
return style;
}
String getRefName()
{
return refName;
}
Normalizer getNormalizer(DataSource data, Hashtable map) throws BadXMLException
{
return norm == null ? null : norm.getNormalizer(data,map);
}
private int yAxis;
private StatisticsTraverser stats = null;
private AxisLabelsTraverser labels = null;
private NormalizationTraverser norm = null;
private JASHist1DHistogramStyle style = null;
private ConstructorNodeTraverser ct = null;
private Style1DNodeTraverser st = new Style1DNodeTraverser();
private Bins1DNodeTraverser b1d;
private XYPointsNodeTraverser xy;
private PointDataAxisAttributesNodeTraverser paa;
private BinnedDataAxisAttributesNodeTraverser baa;
private String refName;
}
class ClassNodeTraverser extends ConstructorNodeTraverser
{
ClassNodeTraverser(Node node) throws BadXMLException
{
super(node);
if (ds instanceof HasDataSource) return;
throw new BadXMLException("Class is not a HasDataSource");
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("param")) param = value;
else super.handleAttributeNode(node,name,value);
}
DataSource getDataSource()
{
return ((HasDataSource) ds).getDataSource(param);
}
private String param;
}
class DataSourceNodeTraverser extends ConstructorNodeTraverser
{
DataSourceNodeTraverser(Node node) throws BadXMLException
{
super(node);
if (ds instanceof DataSource) return;
throw new BadXMLException("Class is not a DataSource");
}
DataSource getDataSource()
{
return (DataSource) ds;
}
}
abstract class ConstructorNodeTraverser extends XMLNodeTraverser
{
ConstructorNodeTraverser(Node node) throws BadXMLException
{
int maxSize = node.getChildNodes().getLength();
types = new String[maxSize];
values = new String[maxSize];
traverse(node);
try
{
Class c = null;
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl != null) {
c = ccl.loadClass(className);
} else {
c = Class.forName(className);
}
if (vc == 0) ds = c.newInstance();
else
{
Class[] argc = new Class[vc];
Object[] args = new Object[vc];
for (int i=0; i<vc; i++)
{
argc[i] = toClass(types[i]);
args[i] = toObject(values[i],types[i]);
}
Constructor con = c.getConstructor(argc);
ds = con.newInstance(args);
}
}
catch (Throwable t)
{
throw new BadXMLException("Error instantiating class "+className+": "+t);
}
}
protected void handleElement(Element node, String name) throws BadXMLException
{
if (name.equals("param")) traverse(node);
else super.handleElement(node,name);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("name")) className = value;
else if (name.equals("type")) types[tc++] = value;
else if (name.equals("value")) values[vc++] = value;
else super.handleAttributeNode(node,name,value);
}
private Class toClass(String type) throws BadXMLException
{
if (type.equals("int") ) return Integer.TYPE;
else if (type.equals("double")) return Double.TYPE;
else if (type.equals("Color") ) return java.awt.Color.class;
else if (type.equals("String")) return String.class;
else throw new BadXMLException("Unknown type "+type);
}
private Object toObject(String value, String type) throws BadXMLException
{
try
{
if (type.equals("int") ) return new Integer(value);
else if (type.equals("double")) return new Double(value);
else if (type.equals("Color") ) return toColor(value);
else if (type.equals("String")) return value;
else throw new BadXMLException("Unknown type "+type);
}
catch (BadXMLException x) { throw x; }
catch (Throwable t)
{
throw new BadXMLException("Error converting parameter "+value+" to "+type);
}
}
abstract DataSource getDataSource();
protected Object ds;
private String className;
private String[] values;
private String[] types;
private int vc = 0;
private int tc = 0;
}
class AxisLabelsTraverser extends XMLNodeTraverser
{
AxisLabelsTraverser(Node node) throws BadXMLException
{
traverse(node);
}
protected void handleElement(Element node, String name) throws BadXMLException
{
if (name.equals("axisLabel")) traverse(node);
else super.handleElement(node,name);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("value")) labels.addElement(value);
else if (name.equals("type")) type = value;
else super.handleAttributeNode(node,name,value);
}
String[] getLabels()
{
String[] result = new String[labels.size()];
labels.copyInto(result);
return result;
}
String getType()
{
return type;
}
private String type;
private Vector labels = new Vector();
}
class StatisticsTraverser extends XMLNodeTraverser implements Statistics
{
StatisticsTraverser(Node node) throws BadXMLException
{
int maxSize = node.getChildNodes().getLength();
names = new String[maxSize];
values = new double[maxSize];
traverse(node);
if (cn < maxSize)
{
String[] copy = new String[cn];
System.arraycopy(names,0,copy,0,cn);
names = copy;
}
if (cv < maxSize)
{
double[] copy = new double[cn];
System.arraycopy(values,0,copy,0,cv);
values = copy;
}
}
protected void handleElement(Element node, String name) throws BadXMLException
{
if (name.equals("statistic")) traverse(node);
else super.handleElement(node,name);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("value")) values[cv++] = toDouble(value);
else if (name.equals("name")) names[cn++] = value;
else super.handleAttributeNode(node,name,value);
}
public String[] getStatisticNames()
{
return names;
}
public double getStatistic(String name)
{
for (int i=0; i<names.length; i++)
{
if (name.equals(names[i])) return values[i];
}
return 0;
}
private String[] names;
private double[] values;
private int cn = 0;
private int cv = 0;
}
class Bins1DNodeTraverser extends XMLNodeTraverser
{
Bins1DNodeTraverser(Node node) throws BadXMLException
{
traverse(node);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("title")) title = value;
else super.handleAttributeNode(node,name,value);
}
protected void handleTextNode(Text node, String name) throws BadXMLException
{
StringTokenizer lineTokens = new StringTokenizer(node.getData());
int lines = lineTokens.countTokens();
for (int l=0; lineTokens.hasMoreTokens(); l++)
{
StringTokenizer valueTokens = new StringTokenizer(lineTokens.nextToken().trim(),",");
int n = valueTokens.countTokens();
if (data == null) data = new double[n][lines];
else if (n != data.length) throw new BadXMLException("Inconsistent number of entries in bins1d data at line "+l);
for (int i=0; i<n; i++) data[i][l] = toDouble(valueTokens.nextToken());
}
}
String getTitle()
{
return title;
}
double[][] getData()
{
return data;
}
private String title;
private double[][] data;
}
class BinnedDataAxisAttributesNodeTraverser extends XMLNodeTraverser
{
BinnedDataAxisAttributesNodeTraverser(Node node) throws BadXMLException
{
traverse(node);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("axis")) axis = value;
else if (name.equals("min")) min = toDouble(value);
else if (name.equals("max")) max = toDouble(value);
else if (name.equals("numberOfBins")) nBins = toInt(value);
else if (name.equals("type")) type = XMLPrintWriter.convertStringToAxisType(value);
else super.handleAttributeNode(node,name,value);
}
String getAxis() { return axis; }
double getMin() { return min; }
double getMax() { return max; }
int getBins() { return nBins; }
int getType() { return type; }
private String axis;
private double min,max;
private int nBins;
private int type;
}
class XYPointsNodeTraverser extends XMLNodeTraverser
{
XYPointsNodeTraverser(Node node) throws BadXMLException
{
traverse(node);
}
protected void handleAttributeNode(Attr node, String name, String value) throws BadXMLException
{
if (name.equals("title")) title = value;
else if (name.equals("dimensions")) dim = toInt(value);
else super.handleAttributeNode(node,name,value);
}
protected void handleTextNode(Text node, String name) throws BadXMLException
{
StringTokenizer lineTokens = new StringTokenizer(node.getData());
int lines = lineTokens.countTokens();
for (int l=0; lineTokens.hasMoreTokens(); l++)
{
StringTokenizer valueTokens = new StringTokenizer(lineTokens.nextToken().trim(),",");
int n = valueTokens.countTokens();
if (data == null) data = new double[n][lines];
else if (n != data.length) throw new BadXMLException("Inconsistent number of entries in bins1d data at line "+l);
for (int i=0; i<n; i++) data[i][l] = toDouble(valueTokens.nextToken());
}
}
String getTitle()
{
return title;
}
double[][] getData()
{
return data;
}
private String title;
private int dim;
private double[][] data;
}
class XMLXYDataSource implements XYDataSource, HasStatistics
{
XMLXYDataSource(XYPointsNodeTraverser xy,
PointDataAxisAttributesNodeTraverser paa,
Statistics stats)
{
this.xy = xy;
this.paa = paa;
this.stats = stats;
}
public int getAxisType()
{
return paa.getType();
}
public String getTitle()
{
return xy.getTitle();
}
public Statistics getStatistics()
{
return stats;
}
public double getX(int index)
{
return xy.getData()[0][index];
}
public double getY(int index)
{
return xy.getData()[1][index];
}
public double getPlusError(int index)
{
return xy.getData()[2][index];
}
public double getMinusError(int index)
{
return xy.getData()[3][index];
}
public int getNPoints()
{
return xy.getData()[0].length;
}
private Statistics stats;
private XYPointsNodeTraverser xy;
private PointDataAxisAttributesNodeTraverser paa;
}
class XML1DHistDataSource implements Rebinnable1DHistogramData, HasStatistics
{
XML1DHistDataSource(Bins1DNodeTraverser b1d,
BinnedDataAxisAttributesNodeTraverser baa,
AxisLabelsTraverser labels,
Statistics stats)
{
this.b1d = b1d;
this.baa = baa;
this.labels = labels;
this.stats = stats;
}
public double[][] rebin(int bins, double min, double max, boolean wantErrors, boolean hurry)
{
return b1d.getData();
}
public double getMin()
{
return baa.getMin();
}
public double getMax()
{
return baa.getMax();
}
public int getBins()
{
return baa.getBins();
}
public boolean isRebinnable()
{
return false;
}
public int getAxisType()
{
return baa.getType();
}
public String[] getAxisLabels()
{
return labels == null ? null : labels.getLabels();
}
public String getTitle()
{
return b1d.getTitle();
}
public Statistics getStatistics()
{
return stats;
}
private Statistics stats;
private Bins1DNodeTraverser b1d;
private BinnedDataAxisAttributesNodeTraverser baa;
private AxisLabelsTraverser labels;
}