package edu.colostate.vchill;
import edu.colostate.vchill.ChillDefines.Mode;
import edu.colostate.vchill.bookmark.BookmarkControl;
import edu.colostate.vchill.gui.*;
import javax.swing.*;
import javax.swing.filechooser.FileSystemView;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
/**
* The class containing the main() method used to run VCHILL.
*
* @author Justin Carlson
* @author Jochen Deyke
* @author jpont
* @author Joseph C. Hardin
* @version 2014-11-24
*/
public class Loader {
/**
* Private default constructor prevents instantiation
*/
private Loader() {
}
private static final int adminPort = 2500;
private static final String eduBookmarkURL = "http://chill.colostate.edu/java/bookmarks-edu.xml";
private static final String sysBookmarkURL = "http://chill.colostate.edu/java/bookmarks-sys.xml";
/**
* Prints usage message and exits.
*/
private static void die() {
System.err.println("Usage: java -jar vchill.jar [-bookmark <category>,\"<name> <scantype>\"]");
System.err.println(" [-plot <list>] [-ascope <list>] [-numerical <list>]");
System.err.println(" [-realtime server:port] [-save off|<format>,<tilt>,<to>]");
System.err.println(" [-gui on|off] [-noisered on|off] [-range <km>] [-grid <km>]");
System.err.println(" [-smoothing on|off] [-mode <mode>] [-center <x>,<y>]");
System.err.println(" [-range <km>] [-rhistretch <factor> [-sweep <sweep>]");
System.err.println(" list: comma separated moment names (eg. \"dBZ,NCP\")");
System.err.println(" format: png|kmz|both");
System.err.println(" tilt: sweeps to save: all|web");
System.err.println(" to: ram|<path>");
System.err.println(" mode: Ray|Sweep|Volume|Continuous");
System.err.println(" factor: desired magnification, decimal OK");
System.err.println(" sweep: desired sweep, including complete '*' separated path");
System.err.println(" Do NOT specify a bookmark if using realtime mode");
System.exit(1);
}
/**
* Parse command line arguments and load specified settings into config
*
* @param args the command line arguments to parse
* @param config the Config instance to store settings in
* @return an array of arrays containing bookmark, plot, ascope, numeric, and sweep details:
* bookmark: {category, name}
* plot: plot windows to open
* ascope: ascope windows to open
* numeric: numerical windows to open
* sweep: sweeps to display
*/
private static String[][] parseCommandLineArguments(final String[] args, final Config config) {
final String[][] a = new String[5][]; //bookmark, plot, ascope, numeric, sweep
// So many times no...why not just use something like optparse? TODO: Fix this Monstrosity!
if (args.length % 2 != 0) die();
for (int i = 0; i < args.length; i += 2) {
if (args[i].equals("-bookmark")) {
a[0] = args[i + 1].split(",");
assert a[0].length == 2;
} else if (args[i].equals("-sweep")) {
a[4] = args[i + 1].split(",");
} else if (args[i].equals("-plot")) {
a[1] = args[i + 1].split(",");
} else if (args[i].equals("-ascope")) {
a[2] = args[i + 1].split(",");
} else if (args[i].equals("-numerical")) {
a[3] = args[i + 1].split(",");
} else if (args[i].equals("-realtime")) {
config.setDirName(null);
config.setSocketName(null);
config.setControlName(null);
config.setRealtimeName(args[i + 1]);
} else if (args[i].equals("-mode")) {
try {
Mode mode = Mode.valueOf(Mode.class, args[i + 1]);
config.setPlottingMode(mode);
} catch (IllegalArgumentException iae) {
System.out.println("Bad mode: " + args[i + 1]);
die();
}
} else if (args[i].equals("-range")) {
config.setPlotRange(Double.parseDouble(args[i + 1]));
} else if (args[i].equals("-grid")) {
config.setGridSpacing(Integer.parseInt(args[i + 1]));
} else if (args[i].equals("-center")) {
String[] tmp = args[i + 1].split(",");
config.setCenterX(Double.parseDouble(tmp[0]));
config.setCenterY(Double.parseDouble(tmp[1]));
} else if (args[i].equals("-rhistretch")) {
config.setRHIHVFactor(Double.parseDouble(args[i + 1]));
} else if (args[i].equals("-smoothing")) {
if (args[i + 1].equals("off")) config.setSmoothingEnabled(false);
else if (args[i + 1].equals("on")) config.setSmoothingEnabled(true);
else die();
} else if (args[i].equals("-noisered")) {
if (args[i + 1].equals("off")) config.setNoiseReductionEnabled(false);
else if (args[i + 1].equals("on")) config.setNoiseReductionEnabled(true);
else die();
} else if (args[i].equals("-gui")) {
if (args[i + 1].equals("off")) config.setGUIEnabled(false);
else if (args[i + 1].equals("on")) config.setGUIEnabled(true);
} else if (args[i].equals("-save")) {
String[] tmp = args[i + 1].split(",");
if (tmp.length == 1 && tmp[0].equals("off")) {
config.setImageAutosaveEnabled(false);
} else if (tmp.length == 3) {
config.setImageAutosaveEnabled(tmp[0].equals("png") || tmp[0].equals("both"));
config.setImageAutoExportEnabled(tmp[0].equals("kmz") || tmp[0].equals("both"));
config.setSaveAllEnabled(tmp[1].equals("all"));
if (tmp[2].equals("ram")) {
config.setSaveToDiskEnabled(false);
} else {
config.setSaveToDiskEnabled(true);
config.setSaveToDiskPath(tmp[2]);
}
} else {
die();
}
} else {
die();
}
}
return a;
}
/**
* Process the result of the parseCommandLineArguments method.
* Separate due to need to connect first.
*
* @param a an array of arrays containing bookmark, plot, ascope, numeric, and sweep details:
* bookmark: {category, name}
* plot: plot windows to open
* ascope: ascope windows to open
* numeric: numerical windows to open
* sweep: sweeps to display
*/
private static final void processArguments(final String[][] a) {
Config config = Config.getInstance();
WindowManager wm = WindowManager.getInstance();
wm.getMainWindow().setVisible(config.isGUIEnabled());
if (a[1] != null) for (String name : a[1]) wm.createPlotWindow(name);
if (a[2] != null) for (String name : a[2]) wm.createAScopeWindow(name);
if (a[3] != null) for (String name : a[3]) wm.createNumDumpWindow(name);
if (a[0] != null) { //bookmark to load
if (a[0].length == 2) {
ViewBookmarkBrowser.getInstance().selectBookmark(a[0][0], a[0][1]);
} else {
System.err.println("Can't load bookmark; bad format");
}
} else {
//ensure center etc are applied properly
wm.setCenterInKm();
wm.clearScreen();
}
if (a[4] != null) for (String tmp : a[4]) {
ControlMessage newMessage = new ControlMessage(tmp);
ViewFileBrowserActions actions = ViewFileBrowser.getInstance().getActions();
newMessage = actions.findSweep(newMessage);
if (newMessage != null) {
actions.changeSelection(newMessage);
}
}
}
/**
* The start point for Java VCHILL. Run this to start the display.
*
* @param args command line arguments to override default values or open windows/bookmarks/servers
*/
public static void main(final String args[]) throws Exception {
final BookmarkControl bmc = BookmarkControl.getInstance();
final Config config = Config.getInstance();
/*TODO: This part is causing issues. I need to rework it to fail more gracefully*/
//check to see if VCHILL is already running
/* try {
final ServerSocket socket = new ServerSocket(adminPort, 50, InetAddress.getByName("localhost"));
new Thread(new Runnable() { public void run () {
while (true) { try { //check to see if another instance gets started
Socket inSocket = socket.accept();
ObjectInputStream inStream = new ObjectInputStream(inSocket.getInputStream());
String[] newArgs = (String[])inStream.readObject();
final String[][] a = parseCommandLineArguments(newArgs, config);
inStream.close();
inSocket.close();
EventQueue.invokeLater(new Runnable() { public void run () {
processArguments(a);
}});
} catch (Exception e) { throw new Error(e); }}
}}, "ServerThread").start();
} catch (BindException be) { //socket in use -> already running
//attempt to connect to already-running instance
try{
Socket socket = new Socket("localhost", adminPort);
System.out.println("connected to already running VCHILL instance");
ObjectOutputStream outStream = new ObjectOutputStream(socket.getOutputStream());
outStream.writeObject(args);
outStream.flush();
outStream.close();
socket.close();
System.exit(0);
}catch(SocketTimeoutException e){
System.err.println("Could not pass arguments to currently running VCHILL session.\n)" +
"Additionally, could not bind to current server port. There may be some erratic behavior. Attempting to continue");
}
}
*/
//parse commandline args
final String[][] a = parseCommandLineArguments(args, config); //bookmark, plot, ascope, numeric
final ProgressMonitor progressMon = new ProgressMonitor(null, "Java VCHILL Startup", "Connecting...", 0, 3);
final boolean[] loadFailed = new boolean[1];
loadFailed[0] = false;
EventQueue.invokeAndWait(new Runnable() {
public void run() {
GUIUtil.setLnF();
ViewMain vm = new ViewMain();
DialogUtil.parent = vm.getDesktop();
JFrame win = vm.getWindow();
//Quit this app when the big window closes.
win.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent e) {
exit();
}
});
final edu.colostate.vchill.gui.Config gcc = edu.colostate.vchill.gui.Config.getInstance();
win.pack();
win.setBounds(gcc.getInset(), gcc.getInset(), gcc.getDefaultWidth(), gcc.getDefaultHeight());
win.setExtendedState(Frame.MAXIMIZED_BOTH);
System.out.println("VCHILL: " + Version.string + " Build Date: " + Version.buildDate);
WindowManager wm = WindowManager.getInstance();
wm.setMain(vm);
}
});
EventQueue.invokeAndWait(new Runnable() {
public void run() {
progressMon.setMillisToDecideToPopup(500);
progressMon.setProgress(0);
}
});
if (!progressMon.isCanceled()) {
ViewControl vc = ViewControl.getInstance();
//connect before trying to load bookmarks
int connectionType = config.getLastConnectionType();
String archive = config.getDefaultSocketName();
if (connectionType == Config.REALTIME_CONN || archive == null) { //realtime mode
//Trigger the realtime connect action as if the user had selected
//it from the file menu. This is done instead of calling the
//appropriate connect method so that the user has a chance to cancel.
ViewFileBrowserPopup.realtimeAction.actionPerformed(null);
} else {
if (archive.length() > 0) vc.connect(archive);
String dir = config.getDefaultDirName();
if (dir != null && dir.length() > 0) vc.addDirectory(dir);
}
}
if (!progressMon.isCanceled()) EventQueue.invokeAndWait(new Runnable() {
public void run() {
progressMon.setNote("Loading edu bookmarks...");
progressMon.setProgress(1);
}
});
if (!progressMon.isCanceled()) {
try {
URLConnection urlConn = new URL(eduBookmarkURL).openConnection();
urlConn.setReadTimeout(5000);
urlConn.setConnectTimeout(5000);
urlConn.connect();
bmc.load(urlConn.getInputStream(), "edu:");
} catch (IOException ioe) {
//progressMon.setNote("Loading edu bookmarks...Failed");
loadFailed[0] = true;
System.err.println("Failed to load bookmarks from " + eduBookmarkURL);
} catch (IllegalArgumentException iae) {
loadFailed[0] = true;
System.err.println("Failed to load bookmarks: Java 8 Error. Hopefully fixed in future.");
}
}
if (!progressMon.isCanceled() && loadFailed[0]) {
progressMon.setNote("Loading edu bookmarks...Failed");
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
loadFailed[0] = false;
}
if (!progressMon.isCanceled()) EventQueue.invokeAndWait(new Runnable() {
public void run() {
progressMon.setProgress(2);
progressMon.setNote("Loading sys bookmarks...");
}
});
if (!progressMon.isCanceled()) {
try {
URLConnection urlConn = new URL(sysBookmarkURL).openConnection();
urlConn.setReadTimeout(5000);
urlConn.setConnectTimeout(5000);
urlConn.connect();
bmc.load(urlConn.getInputStream(), "sys:");
} catch (IOException ioe) {
//progressMon.setNote("Loading sys bookmarks...Failed");
loadFailed[0] = true;
System.err.println("Failed to load bookmarks from " + sysBookmarkURL);
}catch (IllegalArgumentException iae) {
loadFailed[0] = true;
System.err.println("Failed to load bookmarks: Java 8 Error. Hopefully fixed in future.");
}
}
if (!progressMon.isCanceled() && loadFailed[0]) {
progressMon.setNote("Loading sys bookmarks...Failed");
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
loadFailed[0] = false;
}
EventQueue.invokeAndWait(new Runnable() {
public void run() {
progressMon.setProgress(3);
ViewControl vc = ViewControl.getInstance();
bmc.load(new File(FileSystemView.getFileSystemView().getHomeDirectory(), "bookmarks.xml"));
vc.loadColors(edu.colostate.vchill.color.Config.getInstance().getColorFileName());
vc.loadMaps();
processArguments(a);
}
});
}
/**
* Saves the user's bookmarks and display settings
* and terminates the program
*/
public static void exit() {
BookmarkControl.getInstance().save(new File(
FileSystemView.getFileSystemView().getHomeDirectory(), "bookmarks.xml"));
Config.getInstance().savePreferences();
ScaleManager.getInstance().savePreferences();
System.exit(0);
}
/**
* Method to allow shortened lines when getting resources
*/
public static URL getResource(final String resourceName) {
return Loader.class.getClassLoader().getResource(resourceName);
}
}