package org.autoplot.html;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.das2.datum.EnumerationUnits;
import org.das2.datum.TimeParser;
import org.das2.datum.Units;
import org.das2.qds.AbstractDataSet;
import org.das2.qds.DDataSet;
import org.das2.qds.QDataSet;
import org.das2.qds.ops.Ops;
import org.das2.qds.util.AsciiParser;
import org.das2.qds.util.AsciiParser.FieldParser;
import org.das2.qds.util.DataSetBuilder;
/**
* Generic class for converting a table of ASCII strings to datums.
* @author jbf
*/
public class AsciiTableMaker {
DataSetBuilder builder = null;
QDataSet desc = null; // bundle descriptor
List units = null;
Units defaultUnits= null;
List labels = null;
List names = null;
List format= null;
List fieldParsers= null;
int fieldCount= -1;
boolean initializedFields= false;
void setUnits(String units) {
this.defaultUnits= Units.lookupUnits(units);
}
private void setUnitsAndFormat( List values ) {
for (int i = 0; i < fieldCount; i++) {
String field = values.get(i).trim();
boolean isTime= false;
try {
if ( TimeParser.isIso8601String(field) ) { // allow ISO8601 times.
Units.cdfTT2000.parse(field);
isTime= true;
} else if ( field.matches("\\d+/\\d+/\\d+") ) {
Units.cdfTT2000.parse(field);
isTime= true;
}
} catch (ParseException ex) {
Logger.getLogger(AsciiTableMaker.class.getName()).log(Level.SEVERE, null, ex);
}
if ( units.get(i)==null ) {
if ( isTime ) {
units.set(i,Units.us2000);
format.set(i,null);
} else {
if ( field.contains("$") ) {
units.set(i,Units.dollars);
format.set(i,"%.2f");
} else if ( field.endsWith("%") ) {
units.set(i,Units.percent);
format.set(i,null);
} else {
try {
Integer.parseInt(field);
units.set(i,Units.dimensionless);
format.set(i,"%d");
} catch ( NumberFormatException ex ) {
try {
Double.parseDouble(field);
units.set(i,Units.dimensionless);
format.set(i,null);
} catch ( NumberFormatException ex2 ) {
String[] ss= field.split("\\s",-2); // "3.4 sec"
if ( ss.length>1 ) {
try {
Double.parseDouble(ss[0]);
units.set(i,Units.lookupUnits( field.substring( ss[0].length() ).trim() ) );
format.set(i,null);
} catch ( NumberFormatException ex3 ) {
units.set( i, new EnumerationUnits("default") );
format.set(i,null);
}
} else {
if ( field.contains(",") && !field.endsWith(",") ) {
try {
double d= Double.parseDouble(field.replace(",","" ) );
this.fieldParsers.set( i, getCommaFieldParser(Units.dimensionless) );
} catch ( NumberFormatException ex4 ) {
units.set( i, new EnumerationUnits("default") );
format.set(i,null);
}
} else {
units.set( i, new EnumerationUnits("default") );
format.set(i,null);
}
}
}
}
}
}
}
}
}
/**
* FieldParser removes the comma to parse things like "1,234" to 1234.
* @param uu
* @return
*/
FieldParser getCommaFieldParser( final Units uu ) {
return new FieldParser() {
@Override
public double parseField(String field, int columnIndex) throws ParseException {
return uu.parse( field.replaceAll(",","") ).doubleValue(uu); // sorry, rest of world
}
};
}
void addRecord(List values) {
if ( fieldCount==-1 ) {
return;
}
if ( initializedFields==false ) {
setUnitsAndFormat(values);
initializedFields= true;
}
for (int i = 0; i < fieldCount; i++) {
String field = values.get(i).trim();
Units u= units.get(i);
if ( field.trim().length()==0 ) {
if ( u instanceof EnumerationUnits ) {
double d= ((EnumerationUnits)u).createDatum(field).doubleValue(u);
builder.putValue(-1, i, d);
} else {
builder.putValue(-1, i, builder.getFillValue() );
}
} else {
try {
double d;
if ( u instanceof EnumerationUnits ) {
d= ((EnumerationUnits)u).createDatum(field).doubleValue(u);
} else {
FieldParser p= fieldParsers.get(i);
if ( p!=null ) {
d= p.parseField(field, i);
} else {
try {
d= u.parse( field ).doubleValue( u );
} catch (ParseException ex ) {
final Units uu= u;
p= new FieldParser() {
@Override
public double parseField(String field, int columnIndex) throws ParseException {
return uu.parse( field.replaceAll(",","") ).doubleValue(uu); // sorry, rest of world
}
};
fieldParsers.set( i, p );
d= p.parseField(field, i);
}
}
}
builder.putValue(-1, i, d);
} catch (ParseException ex) {
builder.putValue(-1, i, builder.getFillValue() );
}
}
}
builder.nextRecord();
}
void initialize(List values) {
fieldCount = values.size();
builder = new DataSetBuilder(2, 100, fieldCount);
units = new ArrayList<>(fieldCount);
for (int i = 0; i < fieldCount; i++) {
units.add(i, defaultUnits ); // null here means we can reset.
}
format= new ArrayList<>(fieldCount);
fieldParsers= new ArrayList<>(fieldCount);
labels = new ArrayList<>(fieldCount);
names = new ArrayList<>(fieldCount);
if (labels.isEmpty()) {
for (int i = 0; i < fieldCount; i++) {
labels.add(i, values.get(i));
names.add(i, Ops.safeName(values.get(i)));
format.add("");
fieldParsers.add(null);
}
}
}
/**
* return true if the header has been set.
* @return true if the header has been set.
*/
public boolean hasHeader() {
return this.fieldCount>-1;
}
void addHeader(List values) {
if (fieldCount == -1) {
initialize(values);
}
}
void addUnits(List units) {
}
void addUnits(int icol, String units) {
}
private QDataSet getBundleDescriptor() {
return new AbstractDataSet() {
@Override
public int rank() {
return 2;
}
@Override
public Object property(String name, int i) {
if ( name.equals(QDataSet.LABEL ) ) {
return labels.get(i);
} else if ( name.equals(QDataSet.NAME ) ) {
return names.get(i);
} else if ( name.equals(QDataSet.FORMAT ) ) {
return format.get(i);
} else if ( name.equals(QDataSet.UNITS ) ) {
return units.get(i);
}
return property(name);
}
@Override
public double value(int i0, int i1) {
return 0;
}
@Override
public int length() {
return labels.size();
}
@Override
public int length(int i) {
return 0;
}
};
}
DDataSet getDataSet() {
if ( builder==null ) {
throw new IllegalArgumentException("no records found");
}
DDataSet result = builder.getDataSet();
desc= getBundleDescriptor();
result.putProperty(QDataSet.BUNDLE_1, desc);
return result;
}
}