package com.isti.xmax;
import java.io.File;
import java.util.Objects;
import java.util.Set;
import javax.swing.JOptionPane;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.RollingFileAppender;
import org.reflections.Reflections;
import com.isti.traceview.TraceView;
import com.isti.traceview.common.TimeInterval;
import com.isti.traceview.filters.IFilter;
import com.isti.traceview.gui.ColorModeBySegment;
import com.isti.traceview.transformations.ITransformation;
import com.isti.xmax.data.XMAXDataModule;
import com.isti.xmax.gui.XMAXframe;
/**
* Main class for XMAX. Keeps command line parsing logic, handles with plugins, initialize data and
* graphics.
*
* @author Max Kokoulin
*/
public class XMAX extends TraceView {
private static final Logger logger = Logger.getLogger(XMAX.class);
public static final String version = "2.0.7";
public static final String releaseDate = "February 2016";
/**
* Parsed command line
*/
private static CommandLine cmd;
private static Options options;
private static Set<Class<? extends IFilter>> filters;
private static Set<Class<? extends ITransformation>> transformations;
public XMAX() {
super();
setUndoAdapter(new XMAXUndoAdapter());
try {
boolean dump = false;
System.out.println(" XMAX ver." + getVersionMessage() );
System.out.println("===============");
if (cmd.getOptions().length == 0) {
System.out.println("[ Quick Examples ]\n");
System.out.println("* Read from -d 'data/path':");
System.out.println(" >java -Xms512M -Xmx512M -jar xmax.jar -d '/xs0/seed/IU_PTGA/2014_1{93,94}/00_LHZ*seed'\n");
System.out.println("* Read from BOTH -d 'data/path' AND existing serialized data in DATA_TEMP:");
System.out.println(" >java -Xms512M -Xmx512M -jar xmax.jar -t -d '/xs0/seed/IU_ANMO/2012/2012_1{59,60}_*/00_LHZ*seed'\n");
System.out.println("* Overwrite Serialized data in DATA_TEMP:");
System.out.println(" >java -Xms512M -Xmx512M -jar xmax.jar -T -d '/xs0/seed/IU_ANMO/2012/2012_1{59,60}_*/00_LHZ*seed'\n");
System.out.println("* Append to Serialized data in DATA_TEMP:");
System.out.println(" >java -Xms512M -Xmx512M -jar xmax.jar -T -t -d '/xs0/seed/IU_ANMO/2012/2012_1{59,60}_*/00_LHZ*seed'");
}
System.out.println("===============");
if (cmd.hasOption("h")) {
if (cmd.getOptions().length > 1) {
throw new XMAXException("It isn't allowed to use any other options with -h");
}
HelpFormatter formatter = new HelpFormatter();
formatter
.printHelp(
"xmax [-h | -v | -T] {-t -u<units> -o<order>} [-c<config file> -d<data mask> -s<station file> -k<earthquakes mask> -q<QC file> -b<begin time> -e<end time> -f<units count>]",
options);
} else if (cmd.hasOption("v")) {
if (cmd.getOptions().length > 1) {
throw new XMAXException("It isn't allowed to use any other options with -v");
}
System.out.println("XMAX version " + getVersionMessage() + ". Instrumental Software Technologies, " + getReleaseDateMessage());
} else {
if (cmd.hasOption("g")) {
XMAXconfiguration.confFileName = cmd.getOptionValue("g").trim();
}
setConfiguration(XMAXconfiguration.getInstance()); // if -g not given load current config.xml
if (cmd.hasOption("T")) {
dump = true;
getConfiguration().setDumpData(true);
/** MTH: This has changed
if (cmd.hasOption("t")) {
throw new XMAXException("It isn't allowed to use -T and -t options together");
}
**/
}
if (cmd.hasOption("t")) {
getConfiguration().setUseTempData(true);
/**
if (cmd.hasOption("T")) {
throw new XMAXException("It isn't allowed to use -T and -t options together");
}
**/
}
if (cmd.hasOption("d")) {
getConfiguration().setUseDataPath(true);
getConfiguration().setDataPath(dequote(cmd.getOptionValue("d")).trim());
}
if (cmd.hasOption("i")) {
getConfiguration().setStationInfoFileName(cmd.getOptionValue("i").trim());
}
if (cmd.hasOption("q")) {
getConfiguration().setQCdataFileName(cmd.getOptionValue("q").trim());
}
if (cmd.hasOption("p")) {
getConfiguration().setPickPath(dequote(cmd.getOptionValue("p")).trim());
}
if (cmd.hasOption("u")) {
getConfiguration().setPanelCountUnit(XMAXconfiguration.PanelCountUnit.values()[new Integer(cmd.getOptionValue("u").trim())]);
}
if (cmd.hasOption("o")) {
getConfiguration().setPanelOrder(XMAXconfiguration.ChannelSortType.values()[new Integer(cmd.getOptionValue("o").trim())]);
}
if (cmd.hasOption("f")) {
getConfiguration().setUnitsInFrame(new Integer(cmd.getOptionValue("f").trim()));
}
if (cmd.hasOption("F")) {
getConfiguration().setDefaultCompression(cmd.getOptionValue("F").trim());
}
if (cmd.hasOption("k")) {
getConfiguration().setEarthquakeFileMask(dequote(cmd.getOptionValue("k")));
}
if (cmd.hasOption("b")) {
getConfiguration().setStartTime(
TimeInterval.parseDate(cmd.getOptionValue("b").trim(), TimeInterval.DateFormatType.DATE_FORMAT_MIDDLE));
}
if (cmd.hasOption("e")) {
getConfiguration().setEndTime(
TimeInterval.parseDate(cmd.getOptionValue("e").trim(), TimeInterval.DateFormatType.DATE_FORMAT_MIDDLE));
}
if (cmd.hasOption("m")) {
getConfiguration().setMergeLocations(true);
}
if (cmd.hasOption("s")) {
getConfiguration().setFilterStation(cmd.getOptionValue("s").trim());
}
if (cmd.hasOption("n")) {
getConfiguration().setFilterNetwork(cmd.getOptionValue("n").trim());
}
if (cmd.hasOption("c")) {
getConfiguration().setFilterChannel(cmd.getOptionValue("c").trim());
}
if (cmd.hasOption("l")) {
getConfiguration().setFilterLocation(cmd.getOptionValue("l").trim());
}
if (cmd.hasOption("L")) {
getConfiguration().setDefaultBlockLength(new Integer(cmd.getOptionValue("L").trim()));
}
if (dump) {
// -T option in command line, make dump
setConfiguration(XMAXconfiguration.getInstance());
setDataModule(XMAXDataModule.getInstance());
getDataModule().dumpData(new ColorModeBySegment());
} else {
// Find all classes that implement IFilter and ITransformation.
Reflections reflect = new Reflections("com.isti");
filters = reflect.getSubTypesOf(IFilter.class);
transformations = reflect.getSubTypesOf(ITransformation.class);
setDataModule(XMAXDataModule.getInstance());
getDataModule().loadData();
if (getDataModule().getAllChannels().size() > 0) {
setFrame(XMAXframe.getInstance());
if (XMAXconfiguration.getInstance().getTimeInterval() != null) {
getFrame().setShouldManageTimeRange(false);
getFrame().setTimeRange(XMAXconfiguration.getInstance().getTimeInterval());
}
try {
// Wait while frame will be created to correct repaint
Thread.sleep(200);
} catch (InterruptedException e) {
logger.error("InterruptedException:", e);
}
getFrame().setVisible(true);
getFrame().setShouldManageTimeRange(true);
} else {
JOptionPane.showMessageDialog(null, "No data found at path " + XMAXconfiguration.getInstance().getDataPath(), "Alert",
JOptionPane.WARNING_MESSAGE);
}
}
}
} catch (Exception e) {
logger.error("Exception:", e);
System.exit(0);
}
}
/**
* Getter for configuration.
*/
public static XMAXconfiguration getConfiguration() {
return (XMAXconfiguration) TraceView.getConfiguration();
}
/**
* Getter for data module.
*/
public static XMAXDataModule getDataModule() {
return (XMAXDataModule) TraceView.getDataModule();
}
/**
* Getter for main frame
*/
public static XMAXframe getFrame() {
return (XMAXframe) TraceView.getFrame();
}
/**
* Get all plugins-filters
*/
public static Set<Class<? extends IFilter>> getFilters() {
return filters;
}
/**
* Get plugin-filter by id
*/
public static IFilter getFilter(String id)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for (Class<? extends IFilter> curClass : filters) {
try {
if (Objects.equals(curClass.getField("NAME").get(null), id)) {
IFilter filter = (IFilter) curClass.newInstance();
return filter;
}
} catch (NoSuchFieldException | SecurityException e) {
// Field doesn't exist, move to next
}
}
return null;
}
/**
* Get all transformations
*/
public static Set<Class<? extends ITransformation>> getTransformations() {
return transformations;
}
/**
* Get transformation by id.
*
* @return the matching ITransformation or null if none matches
*/
public static ITransformation getTransformation(String id)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
for (Class<? extends ITransformation> curClass : transformations) {
try {
if (Objects.equals(curClass.getField("NAME").get(null), id)) {
ITransformation transform = (ITransformation) curClass.newInstance();
return transform;
}
} catch (IllegalArgumentException | NoSuchFieldException | SecurityException e) {
// Field has issues, move to next field
}
}
return null;
}
/**
* @return filled and initialized CLI options object
*/
private static Options getOptions() {
Options opt = new Options();
opt.addOption(new Option("h", "help", false, "print this message"));
opt.addOption(new Option("v", "version", false, "print xmax version"));
opt.addOption(new Option("g", "config", true, "configuration file"));
opt.addOption(new Option("d", "data", true, "wildcarded mask of data files to load"));
opt.addOption(new Option("T", "make_dump", false, "dumps temporary file storage"));
opt.addOption(new Option("t", "use_dump", false, "adds temporary file storage content to data found by wildcarded mask (see -d)"));
opt.addOption(new Option("i", "stations", true, "stations description file"));
opt.addOption(new Option("k", "earthquakes", true, "wildcarded mask of earthquekes files"));
opt.addOption(new Option("q", "qcdata", true, "QC data file name"));
opt.addOption(new Option("b", "bdate", true, "begin date at yyyy,DDD,HH:mm:ss format"));
opt.addOption(new Option("e", "edate", true, "end date at yyyy,DDD,HH:mm:ss format"));
opt.addOption(new Option("u", "unit", true, "panel count unit: 0 - trace, 1 - station, 2 - channel, 3 - channel type, 4 - all"));
opt.addOption(new Option("o", "order", true,
"panel order: 0 - trace name, 1 - network/station/samplerate, 2 - channel, 3 - channel type, 4 - event"));
opt.addOption(new Option("f", "unitsframe", true, "units count (from -u option) in frame to display"));
opt.addOption(new Option("p", "picks", true, "picks database path"));
opt.addOption(new Option("m", "merge", false, "merge different locations of channel into one graphical panel"));
opt
.addOption(new Option("F", "Format", true,
"default block compression format, possible values are SHORT, INT24, INT32, FLOAT, DOUBLE, STEIM1, STEIM2, CDSN, RSTN, DWW, SRO, ASRO, HGLP"));
opt.addOption(new Option("L", "Length", true, "default block length"));
opt.addOption(new Option("n", "flt_network", true, "semicolon-separated wildcarded filter by network"));
opt.addOption(new Option("s", "flt_station", true, "semicolon-separated wildcarded filter by station"));
opt.addOption(new Option("l", "flt_location", true, "semicolon-separated wildcarded filter by location"));
opt.addOption(new Option("c", "flt_channel", true, "semicolon-separated wildcarded filter by channel"));
return opt;
}
/**
* Dequote string, i.e remove wrapping ' and ".
*/
public static String dequote(String str) {
if ((str.charAt(0) == '"' && str.charAt(str.length() - 1) == '"') || (str.charAt(0) == '\'' && str.charAt(str.length() - 1) == '\'')) {
return str.substring(1, str.length() - 1);
} else {
return str;
}
}
/**
* Get version message
*/
public static String getVersionMessage() {
return version;
}
/**
* Get release date
*/
public static String getReleaseDateMessage() {
return releaseDate;
}
@SuppressWarnings("unused")
public static void main(String[] args) {
options = getOptions();
try {
CommandLineParser parser = new PosixParser();
cmd = parser.parse(options, args);
XMAX xyz = new XMAX();
} catch (ParseException e) {
//System.err.println("Command line parsing failed. Reason: " + e.getMessage());
String message = "Command line parsing failed. Reason:";
logger.error(message, e);
}
}
/**
* Set configuration
*/
public static void setConfiguration(XMAXconfiguration cn) {
RollingFileAppender apd = new RollingFileAppender();
apd.setName("FILELOG");
apd.setFile(cn.getLogFile());
apd.setMaxFileSize("1000KB");
apd.setMaxBackupIndex(10);
apd.setLayout(new PatternLayout("%d %5p %m%n"));
apd.setAppend(false);
apd.activateOptions();
Logger.getRootLogger().addAppender(apd);
Runtime.getRuntime().addShutdownHook(new ClearLogShutDownHook());
TraceView.setConfiguration(cn);
}
}
/**
* Clears logs after program shutdown.
*/
class ClearLogShutDownHook extends Thread {
public void run() {
RollingFileAppender apd = (RollingFileAppender) (Logger.getRootLogger().getAppender("FILELOG"));
apd.close();
File f = new File(XMAXconfiguration.getInstance().getLogFile());
if (f.length() == 0) {
f.deleteOnExit();
}
}
}