package org.opensha2.eq.model;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static java.util.logging.Level.FINE;
import static org.opensha2.gmm.GmmAttribute.ID;
import static org.opensha2.gmm.GmmAttribute.MAX_DISTANCE;
import static org.opensha2.gmm.GmmAttribute.VALUES;
import static org.opensha2.gmm.GmmAttribute.WEIGHT;
import static org.opensha2.gmm.GmmAttribute.WEIGHTS;
import static org.opensha2.internal.Parsing.readDouble;
import static org.opensha2.internal.Parsing.readDoubleArray;
import static org.opensha2.internal.Parsing.readEnum;
import org.opensha2.gmm.Gmm;
import org.opensha2.gmm.GmmElement;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Map;
import java.util.logging.Logger;
import javax.xml.parsers.SAXParser;
/*
* Non-validating gmm.xml parser. SAX parser 'Attributes' are stateful and
* cannot be stored. This class is not thread safe.
*
* Support is included for a second Gmm map for distance splits.
*
* @author Peter Powers
*/
@SuppressWarnings("incomplete-switch")
class GmmParser extends DefaultHandler {
static final String FILE_NAME = "gmm.xml";
private final Logger log = Logger.getLogger(GmmParser.class.getName());
private final SAXParser sax;
private boolean used = false;
private Locator locator;
private int mapCount = 0;
private GmmSet gmmSet;
private GmmSet.Builder setBuilder;
private Map<Gmm, Double> gmmWtMap;
private GmmParser(SAXParser sax) {
this.sax = sax;
}
static GmmParser create(SAXParser sax) {
return new GmmParser(checkNotNull(sax));
}
GmmSet parse(InputStream in) throws SAXException, IOException {
checkState(!used, "This parser has expired");
sax.parse(checkNotNull(in), this);
used = true;
return gmmSet;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes atts)
throws SAXException {
GmmElement e = null;
try {
e = GmmElement.fromString(qName);
} catch (IllegalArgumentException iae) {
throw new SAXParseException("Invalid element <" + qName + ">", locator, iae);
}
try {
switch (e) {
case GROUND_MOTION_MODELS:
setBuilder = new GmmSet.Builder();
break;
case UNCERTAINTY:
double[] uncValues = readDoubleArray(VALUES, atts);
double[] uncWeights = readDoubleArray(WEIGHTS, atts);
setBuilder.uncertainty(uncValues, uncWeights);
log.fine("");
log.fine("Uncertainty...");
log.fine(" Values: " + Arrays.toString(uncValues));
log.fine(" Weights: " + Arrays.toString(uncWeights));
break;
case MODEL_SET:
mapCount++;
checkState(mapCount < 3, "Only two ground motion model sets are allowed");
gmmWtMap = Maps.newEnumMap(Gmm.class);
double rMax = Double.NaN;
if (mapCount == 1) {
rMax = readDouble(MAX_DISTANCE, atts);
setBuilder.primaryMaxDistance(rMax);
} else {
rMax = readDouble(MAX_DISTANCE, atts);
setBuilder.secondaryMaxDistance(rMax);
}
log.fine("");
log.fine(" Set: " + mapCount + " [rMax = " + rMax + "]");
break;
case MODEL:
Gmm model = readEnum(ID, atts, Gmm.class);
double weight = readDouble(WEIGHT, atts);
gmmWtMap.put(model, weight);
if (log.isLoggable(FINE)) {
log.fine(" Model [wt]: " + Strings.padEnd(model.toString(), 44, ' ') +
" [" + weight + "]");
}
break;
}
} catch (Exception ex) {
throw new SAXParseException("Error parsing <" + qName + ">", locator, ex);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
GmmElement e = null;
try {
e = GmmElement.fromString(qName);
} catch (IllegalArgumentException iae) {
throw new SAXParseException("Invalid element <" + qName + ">", locator, iae);
}
try {
switch (e) {
case MODEL_SET:
if (mapCount == 1) {
setBuilder.primaryModelMap(gmmWtMap);
} else {
setBuilder.secondaryModelMap(gmmWtMap);
}
log.fine("");
break;
case GROUND_MOTION_MODELS:
gmmSet = setBuilder.build();
break;
}
} catch (Exception ex) {
throw new SAXParseException("Error parsing <" + qName + ">", locator, ex);
}
}
@Override
public void setDocumentLocator(Locator locator) {
this.locator = locator;
}
}