package Views;
import java.util.List;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import Listeners.UserManualListener;
import Models.Airport;
import Services.LocalizationService;
import Controllers.*;
public class ConsoleGUI {
private interface Action {
public void doThing(Object[] objs);
}
private class Tuple<X, Y, Z> {
public X fst;
public Y snd;
public Z thd;
public Tuple(X f, Y s, Z t) {
fst = f;
snd = s;
thd = t;
}
}
private enum ParamType {
DOUBLE, INT, STRING
}
private JDialog frame;
private JTextArea console, entry;
private GUI gui;
private ArrayList<String> commands;
private HashMap<String, Tuple<List<ParamType>, Action, String>> actions;
private int currentSelect = 1;
private void addActions() {
actions = new HashMap<>();
StringBuilder allCommands = new StringBuilder();
actions.put(
"airportnew",
new Tuple<List<ParamType>, Action, String>(
Arrays.asList(ParamType.STRING, ParamType.STRING,
ParamType.STRING),
new Action() {
@Override
public void doThing(Object[] objs) {
// strings used for validation
String airportNameText = (String) objs[0];
String runwaySourceText = (String) objs[1];
String obstructionSourceText = (String) objs[2];
// validation on the three necessary fields
if (!(airportNameText
.matches("([a-zA-Z]+ +)*[a-zA-Z]+"))
|| airportNameText.equals("")
|| airportNameText
.equals("Example Text")) {
updateDisplay(LocalizationService
.localizeString("valid_airport"));
return;
}
// serialize airport and write to airport
// name-specific file
Airport airport = new Airport(airportNameText,
runwaySourceText, obstructionSourceText);
// name-specific file
String filename = airportNameText + ".ser";
File check = new File(filename);
// if the file doesn't exist...
if (!check.exists()) {
try {
ObjectOutput output = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(filename)));
output.writeObject(airport);
output.close();
} catch (IOException e1) {
e1.printStackTrace();
}
} else {
updateDisplay(LocalizationService
.localizeString("dupe_airport")
+ airportNameText);
return;
}
// close the WelcomeGUI and open the main
// program
frame.dispose();
gui.dispose();
GUI g = new GUI(airport.getAirportName(),
airport.getRunwayFilename(), airport.getObstructionFilename());
g.init();
}
},
"Usage: airportnew \"Name\" \"Path_To_Runway_File\" \"Path_To_Obstruction_File\""
+ " \n(2 Parameters) Create a new airport with the 2 given .xml files."));
actions.put("airport", new Tuple<List<ParamType>, Action, String>(
Arrays.asList(ParamType.STRING), new Action() {
@Override
public void doThing(Object[] objs) {
Airport airport;
try {
File chosenfile = new File((String) objs[0]);
// deserialize chosen airport.ser file
InputStream file = new FileInputStream(chosenfile.getName());
InputStream buffer = new BufferedInputStream(file);
ObjectInput input = new ObjectInputStream(buffer);
airport = (Airport) input.readObject();
input.close();
} catch (IOException | ClassNotFoundException e1) {
updateDisplay(LocalizationService.localizeString("not_ser"));
airport = new Airport("EmptyAirport", "", "");
return;
}
// close the WelcomeGUI and open the main program
frame.dispose();
gui.dispose();
GUI g = new GUI(airport.getAirportName(), airport.getRunwayFilename(),
airport.getObstructionFilename());
g.init();
}
}, "Usage: airport \"Path_To_Airport_File\""
+ " \n(1 Parameter) Loads an aiport from a .ser file."));
actions.put("lang", new Tuple<List<ParamType>, Action, String>(
Arrays.asList(ParamType.STRING), new Action() {
@Override
public void doThing(Object[] objs) {
gui.changeLanguage((String)objs[0]);
}
},
"Usage: lang language_code \n(1 Parameter) Changes the language to the given country code."));
actions.put("exportvis", new Tuple<List<ParamType>, Action, String>(new ArrayList<ParamType>(),
new Action() {
@Override
public void doThing(Object[] objs) {
gui.exportVisualisation.doClick();
}
},
"Usage: exportvis \n(0 Parameters) Saves a screenshot of the current visualisation to the working dir"
+ "ectory."));
actions.put("resetvis", new Tuple<List<ParamType>, Action, String>(new ArrayList<ParamType>(),
new Action() {
@Override
public void doThing(Object[] objs) {
GUI.ResetVisualisationListener l = ConsoleGUI.this.gui.new ResetVisualisationListener();
l.actionPerformed(null);
}
},
"Usage: resetvis\n(0 Parameters) Resets the visualisation pan, zoom, and rotation."));
actions.put("manual", new Tuple<List<ParamType>, Action, String>(new ArrayList<>(),
new Action() {
@Override
public void doThing(Object[] objs) {
UserManualListener man = new UserManualListener();
man.actionPerformed(null);
}
}, "Usage: manual\n(0 Parameters) Opens the user manual."));
actions.put(
"runway",
new Tuple<List<ParamType>, Action, String>(
Arrays.asList(ParamType.STRING, ParamType.INT,
ParamType.DOUBLE, ParamType.DOUBLE,
ParamType.DOUBLE, ParamType.DOUBLE,
ParamType.DOUBLE, ParamType.DOUBLE),
new Action() {
@Override
public void doThing(Object[] objs) {
Runway runway = new Runway((String) objs[0], (int) objs[1], (double) objs[2],
(double) objs[3], (double) objs[4], (double) objs[5], (double) objs[6],
(double) objs[7], (double) objs[7], (double) objs[8]);
gui.changeRunway(runway);
}
},
"Usage: runway \"Name\" ID TODA_From_Left TODA_From_Right"
+ "TORA ASDA_From_Left ASDA_From_Right LDA"
+ " Plane_Blast_Distance\n(9 Parameters) Create a new runway with the specified parameters."));
actions.put(
"obst",
new Tuple<List<ParamType>, Action, String>(
Arrays.asList(ParamType.STRING, ParamType.DOUBLE,
ParamType.DOUBLE, ParamType.DOUBLE,
ParamType.DOUBLE, ParamType.DOUBLE),
new Action() {
@Override
public void doThing(Object[] objs) {
Obstruction o = new Obstruction((String) objs[0], (double) objs[1], (double) objs[2],
(double) objs[3], (double) objs[4], (double) objs[5]);
gui.runway.addObstruction(o);
}
},
"Usage: obst \"Name\" Width Height Length Position_Along_Runway "
+ "Distance_From_Centreline"
+ "\n (6 Parameters) Create a new obstruction with the specified parameters."));
actions.forEach((k, v) -> {
allCommands.append(k + " (" + v.fst.size() + " parameters)\n");
});
actions.put("help", new Tuple<List<ParamType>, Action, String>(
new ArrayList<ParamType>(), new Action() {
@Override
public void doThing(Object[] objs) {
updateDisplay(LocalizationService.localizeString("further_info") + "\n" + allCommands.toString());
}
}, "no"));
}
public ConsoleGUI(Runway runway, GUI g) {
this.gui = g;
commands = new ArrayList<String>();
frame = new JDialog();
frame.setTitle("Runway Redeclaration Tool Console");
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new escapeListener());
frame.setIconImage(new ImageIcon("src\\assets\\data\\logo.png").getImage());
JPanel main = new JPanel();
frame.setContentPane(main);
console = new JTextArea();
console.setPreferredSize(new Dimension(900, 250));
entry = new JTextArea();
entry.setPreferredSize(new Dimension(900, 50));
console.setEditable(false);
console.setLineWrap(true);
console.setWrapStyleWord(true);
entry.setEditable(true);
addActions();
entry.addKeyListener(new KeyListener() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
e.consume();
currentSelect = 1;
updateDisplay(entry.getText());
handleCommand(entry.getText());
entry.setText("");
}
if (e.getKeyCode() == KeyEvent.VK_UP) {
e.consume();
try {
entry.setText(commands.get(commands.size()
- (1 + currentSelect)));
currentSelect += 2;
} catch (Exception ex) {
currentSelect = 1;
}
}
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
});
main.add(new JScrollPane(console), BorderLayout.NORTH);
main.add(entry, BorderLayout.SOUTH);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent event) {
frame.setVisible(false);
frame.dispose();
}
});
// Setting Colors
ArrayList<Color> backgroundColors = gui.getColourScheme();
frame.setBackground(backgroundColors.get(0));
console.setBackground(backgroundColors.get(0));
entry.setBackground(backgroundColors.get(0));
main.setBackground(backgroundColors.get(0));
frame.setModal(true);
frame.setPreferredSize(new Dimension(900, 320));
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
entry.requestFocus();
updateDisplay("For help, type 'help'.");
}
private void handleCommand(String cmd) {
ArrayList<String> broken = new ArrayList<String>();
Pattern p = Pattern.compile("\\b(?:(?<=\")[^\"]*(?=\")|\\w+)\\b");
Matcher m = p.matcher(cmd);
while (m.find()) {
broken.add(m.group(0));
}
boolean isUsage = false;
if (broken.get(0).endsWith("usage")) {
broken.set(0, broken.get(0).replace("usage", ""));
isUsage = true;
}
Tuple<List<ParamType>, Action, String> act = actions.get(broken.get(0));
if (act == null) {
updateDisplay(LocalizationService.localizeString("unrecognised"));
return;
}
if (isUsage) {
updateDisplay(act.thd);
return;
}
Object[] parsed = new Object[act.fst.size()];
try {
if (act.fst.size() == broken.size() - 1) {
for (int i = 0; i < act.fst.size(); ++i) {
switch (act.fst.get(i)) {
case DOUBLE:
parsed[i] = Double.parseDouble(broken.get(i + 1));
break;
case INT:
parsed[i] = Integer.parseInt(broken.get(i + 1));
break;
case STRING:
parsed[i] = broken.get(i + 1);
break;
}
}
} else {
throw new Exception();
}
act.snd.doThing(parsed);
} catch (Exception e) {
handleCommand(broken.get(0) + "usage");
}
}
public class escapeListener implements KeyEventDispatcher {
@Override
public boolean dispatchKeyEvent(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
if (frame != null) {
frame.setVisible(false);
frame.dispose();
frame = null;
}
}
return false;
}
}
private void updateDisplay(String cmd) {
commands.add(cmd);
StringBuilder strb = new StringBuilder();
for (int i = Math.max(0, commands.size() - 100); i < commands.size(); ++i) {
strb.append(commands.get(i));
strb.append('\n');
}
console.setText(strb.toString());
}
}