package edu.sc.seis.sod.source.event; import java.io.FileNotFoundException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.w3c.dom.Element; import com.csvreader.CsvReader; import edu.iris.Fissures.FlinnEngdahlRegion; import edu.iris.Fissures.FlinnEngdahlType; import edu.iris.Fissures.Location; import edu.iris.Fissures.LocationType; import edu.iris.Fissures.Time; import edu.iris.Fissures.Unit; import edu.iris.Fissures.IfEvent.Magnitude; import edu.iris.Fissures.IfParameterMgr.ParameterRef; import edu.iris.Fissures.event.EventAttrImpl; import edu.iris.Fissures.event.OriginImpl; import edu.iris.Fissures.model.FlinnEngdahlRegionImpl; import edu.iris.Fissures.model.ISOTime; import edu.iris.Fissures.model.QuantityImpl; import edu.iris.Fissures.model.UnitImpl; import edu.iris.Fissures.model.UnsupportedFormat; import edu.sc.seis.fissuresUtil.cache.CacheEvent; import edu.sc.seis.fissuresUtil.display.configuration.DOMHelper; import edu.sc.seis.sod.ConfigurationException; import edu.sc.seis.sod.UserConfigurationException; import edu.sc.seis.sod.subsetter.AreaSubsetter; /** * @author oliverpa * * Created on Jul 1, 2005 */ public class CSVEventSource extends SimpleEventSource { private static final String DEFAULT_CSV_SOURCE_NAME = "CSVEventSource"; public CSVEventSource(Element config) throws ConfigurationException { super(config, DEFAULT_CSV_SOURCE_NAME); if (DOMHelper.hasElement(config, "filename")) { initFromFile(DOMHelper.extractText(config, "filename")); if (getName().equals(DEFAULT_CSV_SOURCE_NAME)) { name += " "+csvFilename; } } else if (DOMHelper.hasElement(config, "events")) { try { events = getEventsFromReader(new StringReader(DOMHelper.extractText(config, "events").trim())); } catch(IOException e) { throw new ConfigurationException("Unable to read events from:" + DOMHelper.extractText(config, "events"), e); } } else { throw new ConfigurationException("Can't find filename or events in configuration."); } } public CSVEventSource(String filename) throws ConfigurationException { super(filename); initFromFile(filename); } protected void initFromFile(String filename) throws ConfigurationException { this.csvFilename = filename; try { events = getEventsFromCSVFile(csvFilename); } catch(FileNotFoundException e) { throw new UserConfigurationException(e.getMessage() + " as a event CSV file."); } catch(IOException e) { throw new ConfigurationException("Unable to read " + csvFilename, e); } } public String getDescription() { return "CSVEventSource: "+csvFilename; } public CacheEvent[] getEvents() { return events; } public static CacheEvent[] getEventsFromCSVFile(String filename) throws FileNotFoundException, IOException, ConfigurationException { return getEventsFromReader(AreaSubsetter.makeRelativeOrRecipeDirReader(filename)); } public static CacheEvent[] getEventsFromReader(Reader reader) throws IOException, FileNotFoundException, ConfigurationException { List events = new ArrayList(); CsvReader csvReader = new CsvReader(reader); csvReader.readHeaders(); List headers = Arrays.asList(csvReader.getHeaders()); for(int i = 0; i < headers.size(); i++) { String cur = (String)headers.get(i); if(!isValidField(cur)) { throw new UserConfigurationException(cur + " is not a known CSV field. " + concatenateValidFields() + " are valid options."); } } while(csvReader.readRecord()) { // time to start populating field values // first up: the only required field... Time time = new Time(csvReader.get(TIME), 0); try { new ISOTime(time.date_time); } catch(UnsupportedFormat uf) { throw new UserConfigurationException("The time '" + time.date_time + "' in record " + csvReader.getCurrentRecord() + " is invalid."); } float latitude = 0f; if(headers.contains(LATITUDE)) { latitude = Float.parseFloat(csvReader.get(LATITUDE)); } float longitude = 0f; if(headers.contains(LONGITUDE)) { longitude = Float.parseFloat(csvReader.get(LONGITUDE)); } double depth = 0f; if(headers.contains(DEPTH)) { depth = Double.parseDouble(csvReader.get(DEPTH)); } Unit depthUnit = UnitImpl.KILOMETER; if(headers.contains(DEPTH_UNITS)) { String unitName = csvReader.get(DEPTH_UNITS); try { depthUnit = UnitImpl.getUnitFromString(unitName); } catch(NoSuchFieldException e) { throw new UserConfigurationException(unitName + " in record " + csvReader.getCurrentRecord() + " is not a valid unit name. Try KILOMETER or METER"); } } Location location = new Location(latitude, longitude, new QuantityImpl(0.0, UnitImpl.METER), new QuantityImpl(depth, depthUnit), LocationType.GEOGRAPHIC); String defaultString = "csvEvent"; String catalog = defaultString; if(headers.contains(CATALOG)) { catalog = csvReader.get(CATALOG); } String contributor = defaultString; if(headers.contains(CONTRIBUTOR)) { contributor = csvReader.get(CONTRIBUTOR); } Magnitude[] magnitudes = new Magnitude[0]; String[] magValues, magTypes, magContribs; if(headers.contains(MAGNITUDE)) { magValues = csvReader.get(MAGNITUDE).split(":"); } else { magValues = new String[] {"0"}; } if(magValues.length > 1 || (headers.contains(MAGNITUDE_TYPE))) { magTypes = csvReader.get(MAGNITUDE_TYPE).split(":"); if(magTypes.length != magValues.length) { throw new UserConfigurationException("count of magnitude types does not match count of magnitude values in record " + csvReader.getCurrentRecord()+", "+magTypes.length +"!="+ magValues.length); } } else { magTypes = new String[] {"M"}; } if(magValues.length > 1 || headers.contains(MAGNITUDE_CONTRIBUTOR)) { magContribs = csvReader.get(MAGNITUDE_CONTRIBUTOR).split(":"); if(magContribs.length != magValues.length) { String[] tmp = magContribs; magContribs = new String[magValues.length]; System.arraycopy(tmp, 0, magContribs, 0, tmp.length); for(int i = tmp.length; i<magContribs.length; i++) { magContribs[i] = UNKNOWN; } } } else { magContribs = new String[] {UNKNOWN}; } magnitudes = new Magnitude[magValues.length]; for(int i = 0; i < magValues.length; i++) { magnitudes[i] = new Magnitude(magTypes[i], Float.parseFloat(magValues[i]), magContribs[i]); } OriginImpl origin = new OriginImpl("", catalog, contributor, time, location, magnitudes, new ParameterRef[0]); String name = defaultString; if(headers.contains(NAME)) { name = csvReader.get(NAME); } FlinnEngdahlType feType = FlinnEngdahlType.SEISMIC_REGION; if(headers.contains(FE_REGION_TYPE)) { int type = Integer.parseInt(csvReader.get(FE_REGION_TYPE)); if(type == FlinnEngdahlType._SEISMIC_REGION) { feType = FlinnEngdahlType.SEISMIC_REGION; } else if(type == FlinnEngdahlType._GEOGRAPHIC_REGION) { feType = FlinnEngdahlType.GEOGRAPHIC_REGION; } } FlinnEngdahlRegion feRegion = new FlinnEngdahlRegionImpl(feType, 0); if(headers.contains(FE_REGION)) { feRegion = new FlinnEngdahlRegionImpl(feType, Integer.parseInt(csvReader.get(FE_REGION))); } events.add(new CacheEvent(new EventAttrImpl(name, feRegion), origin)); } return (CacheEvent[])events.toArray(new CacheEvent[0]); } public static String concatenateValidFields() { String allFields = ""; for(int i = 0; i < FIELDS.length - 1; i++) { allFields += FIELDS[i] + ", "; } return allFields + FIELDS[FIELDS.length - 1]; } private static boolean isValidField(String field) { for(int i = 0; i < FIELDS.length; i++) { if(field.equals(FIELDS[i])) { return true; } } return false; } public String toString() { return "CSVEventSource using " + csvFilename; } private CacheEvent[] events; // required public static final String TIME = "time"; // optional public static final String LONGITUDE = "longitude"; public static final String LATITUDE = "latitude"; public static final String DEPTH = "depth"; public static final String MAGNITUDE = "magnitude"; public static final String CATALOG = "catalog"; public static final String CONTRIBUTOR = "contributor"; public static final String NAME = "name"; public static final String FE_SEIS_REGION = "flinnEngdahlSeismicRegion"; public static final String FE_GEO_REGION = "flinnEngdahlGeographicRegion"; public static final String FE_REGION = "flinnEngdahlRegion"; public static final String FE_REGION_TYPE = "flinnEngdahlRegionType"; // defaultable public static final String DEPTH_UNITS = "depthUnits"; public static final String MAGNITUDE_TYPE = "magnitudeType"; public static final String MAGNITUDE_CONTRIBUTOR = "magnitudeContributor"; private static final String[] FIELDS = new String[] {TIME, LONGITUDE, LATITUDE, DEPTH, DEPTH_UNITS, MAGNITUDE, MAGNITUDE_TYPE, MAGNITUDE_CONTRIBUTOR, CATALOG, CONTRIBUTOR, NAME, FE_SEIS_REGION, FE_GEO_REGION, FE_REGION, FE_REGION_TYPE}; public static final String UNKNOWN = "unknown"; private String csvFilename; }