/** Create a standard JPanel containing the provided JComponent (i.e. JLabel, JButton, etc.). */
  public JPanel buildJPanel(JComponent jc) {
    JPanel jp = new JPanel(new GridLayout(1, 1), false);
    jp.add(jc);
    jp.setBorder(borderline);

    JPanel container = new JPanel();
    container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
    container.add(jp);
    return container;
  }
  /**
   * Create the train module GUI (the dynamic and static windows). Both windows are HIDE_ON_CLOSE so
   * that closing them does not cause the train module to close.
   */
  public TrainModelUI() {
    try {
      JPanel emptyJPanel = new JPanel();
      emptyJPanel.add(new JLabel("            "));
      isPaused = true;

      // Setup the dynamicWindow.

      btnShowStaticValues = buildJButton("Show Static Values");
      btnSelectTrain = buildJButton("Select Train");
      btnPauseResume = buildJButton("Pause");
      btnPauseResume.setEnabled(false);
      btnSetManRecPower = buildJButton("Set Manual Received Power");
      btnToggleManRecPower = buildJButton("Toggle Manual Received Power");
      btnSetManDesSpdLmt = buildJButton("Set Manual Desired Speed Limit");
      btnToggleManDesSpdLmt = buildJButton("Toggle Manual Desired Speed Limit");
      btnToggleSignalPickupFailure = buildJButton("Toggle Signal Pickup Failure");
      btnToggleEngineFailure = buildJButton("Toggle Engine Failure");
      btnToggleBrakeFailure = buildJButton("Toggle Brake Failure");
      btnToggleServiceBrake = buildJButton("Toggle Service Brake");
      btnToggleEmergencyBrake = buildJButton("Toggle Emergency Brake");
      btnSetManLights = buildJButton("Set Manual Lights Status");
      btnToggleManLights = buildJButton("Toggle Manual Lights Status");
      btnSetManDoors = buildJButton("Set Manual Doors Status");
      btnToggleManDoors = buildJButton("Toggle Manual Doors Status");
      btnSetManTarTemperature = buildJButton("Set Manual Target Temp.");
      btnToggleManTarTemperature = buildJButton("Toggle Manual Target Temp.");

      jlTime = new JLabel("XX:XX:XX", JLabel.CENTER);
      jlCurVel = new JLabel("", JLabel.CENTER);
      jlCurAccel = new JLabel("", JLabel.CENTER);
      jlRecPowerTNC = new JLabel("", JLabel.CENTER);
      jlManRecPower = new JLabel("", JLabel.CENTER);
      jlToggleManRecPower = new JLabel("", JLabel.CENTER);
      jlPostedSpdLmt = new JLabel("", JLabel.CENTER);
      jlManDesSpdLmt = new JLabel("", JLabel.CENTER);
      jlToggleManDesSpdLmt = new JLabel("", JLabel.CENTER);
      jlGrade = new JLabel("", JLabel.CENTER);
      jlTotalMass = new JLabel("", JLabel.CENTER);
      jlPassengerCount = new JLabel("", JLabel.CENTER);
      jlCrewCount = new JLabel("", JLabel.CENTER);
      jlPosition = new JLabel("", JLabel.CENTER);
      jlToggleSignalPickupFailure = new JLabel("", JLabel.CENTER);
      jlToggleEngineFailure = new JLabel("", JLabel.CENTER);
      jlToggleBrakeFailure = new JLabel("", JLabel.CENTER);
      jlToggleServiceBrake = new JLabel("", JLabel.CENTER);
      jlToggleEmergencyBrake = new JLabel("", JLabel.CENTER);
      jlLights = new JLabel("", JLabel.CENTER);
      jlManLights = new JLabel("", JLabel.CENTER);
      jlToggleManLights = new JLabel("", JLabel.CENTER);
      jlDoors = new JLabel("", JLabel.CENTER);
      jlManDoors = new JLabel("", JLabel.CENTER);
      jlToggleManDoors = new JLabel("", JLabel.CENTER);
      jlCurTemperature = new JLabel("", JLabel.CENTER);
      jlTarTemperature = new JLabel("", JLabel.CENTER);
      jlManTarTemperature = new JLabel("", JLabel.CENTER);
      jlToggleManTarTemperature = new JLabel("", JLabel.CENTER);
      jlAnnouncement = new JLabel("", JLabel.CENTER);

      JPanel dwPanel1 = new JPanel();
      dwPanel1.setLayout(new GridLayout(18, 2));
      dwPanel1.add(buildJPanel(new JLabel("Current Velocity (m/s)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlCurVel));
      dwPanel1.add(buildJPanel(new JLabel("Current Acceleration (m/s^2)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlCurAccel));
      dwPanel1.add(buildJPanel(new JLabel("Received Power from TNC (W)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlRecPowerTNC));
      dwPanel1.add(buildJPanel(btnSetManRecPower));
      dwPanel1.add(buildJPanel(jlManRecPower));
      dwPanel1.add(buildJPanel(btnToggleManRecPower));
      dwPanel1.add(buildJPanel(jlToggleManRecPower));
      dwPanel1.add(buildJPanel(new JLabel("Speed Limit Posted on Signs (m/s)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlPostedSpdLmt));
      dwPanel1.add(buildJPanel(btnSetManDesSpdLmt));
      dwPanel1.add(buildJPanel(jlManDesSpdLmt));
      dwPanel1.add(buildJPanel(btnToggleManDesSpdLmt));
      dwPanel1.add(buildJPanel(jlToggleManDesSpdLmt));
      dwPanel1.add(buildJPanel(new JLabel("Relative Grade from TKM (%)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlGrade));
      dwPanel1.add(
          buildJPanel(new JLabel("Total Mass (inc. passengers/crew) (kg)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlTotalMass));
      dwPanel1.add(buildJPanel(new JLabel("Passenger Count", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlPassengerCount));
      dwPanel1.add(buildJPanel(new JLabel("Crew Count", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlCrewCount));
      dwPanel1.add(
          buildJPanel(new JLabel("Position from Onboard GPS ([block], m)", JLabel.CENTER)));
      dwPanel1.add(buildJPanel(jlPosition));
      dwPanel1.add(buildJPanel(btnToggleSignalPickupFailure));
      dwPanel1.add(buildJPanel(jlToggleSignalPickupFailure));
      dwPanel1.add(buildJPanel(btnToggleEngineFailure));
      dwPanel1.add(buildJPanel(jlToggleEngineFailure));
      dwPanel1.add(buildJPanel(btnToggleBrakeFailure));
      dwPanel1.add(buildJPanel(jlToggleBrakeFailure));
      dwPanel1.add(buildJPanel(btnToggleServiceBrake));
      dwPanel1.add(buildJPanel(jlToggleServiceBrake));
      dwPanel1.add(buildJPanel(btnToggleEmergencyBrake));
      dwPanel1.add(buildJPanel(jlToggleEmergencyBrake));
      JPanel dwPanel2 = new JPanel();
      dwPanel2.setLayout(new GridLayout(18, 2));
      dwPanel2.add(buildJPanel(new JLabel("Lights Status", JLabel.CENTER)));
      dwPanel2.add(buildJPanel(jlLights));
      dwPanel2.add(buildJPanel(btnSetManLights));
      dwPanel2.add(buildJPanel(jlManLights));
      dwPanel2.add(buildJPanel(btnToggleManLights));
      dwPanel2.add(buildJPanel(jlToggleManLights));
      dwPanel2.add(buildJPanel(new JLabel("Doors Status", JLabel.CENTER)));
      dwPanel2.add(buildJPanel(jlDoors));
      dwPanel2.add(buildJPanel(btnSetManDoors));
      dwPanel2.add(buildJPanel(jlManDoors));
      dwPanel2.add(buildJPanel(btnToggleManDoors));
      dwPanel2.add(buildJPanel(jlToggleManDoors));
      dwPanel2.add(buildJPanel(new JLabel("Current Temp. (degrees F)", JLabel.CENTER)));
      dwPanel2.add(buildJPanel(jlCurTemperature));
      dwPanel2.add(buildJPanel(new JLabel("Target Temp. from TNC (degrees F)", JLabel.CENTER)));
      dwPanel2.add(buildJPanel(jlTarTemperature));
      dwPanel2.add(buildJPanel(btnSetManTarTemperature));
      dwPanel2.add(buildJPanel(jlManTarTemperature));
      dwPanel2.add(buildJPanel(btnToggleManTarTemperature));
      dwPanel2.add(buildJPanel(jlToggleManTarTemperature));
      dwPanel2.add(buildJPanel(new JLabel("Announcement", JLabel.CENTER)));
      dwPanel2.add(buildJPanel(jlAnnouncement));

      JPanel primaryButtons = new JPanel();
      primaryButtons.setLayout(new GridLayout(1, 4));
      primaryButtons.add(btnShowStaticValues);
      primaryButtons.add(btnSelectTrain);
      primaryButtons.add(btnPauseResume);
      primaryButtons.add(buildJPanel(jlTime));

      JPanel jp = new JPanel();
      jp.setLayout(new BoxLayout(jp, BoxLayout.Y_AXIS));
      jp.add(primaryButtons);
      jp.add(emptyJPanel);
      jp.add(new JSeparator(JSeparator.HORIZONTAL));
      jp.add(dwPanel1);
      jp.add(new JSeparator(JSeparator.HORIZONTAL));
      jp.add(dwPanel2);

      jp.setMaximumSize(new Dimension(400, 700));

      JScrollPane dScroll = new JScrollPane(jp);
      dScroll.setViewportView(jp);

      dynamicWindow = new JFrame();
      dynamicWindow.setTitle("Train Model (Chris Paskie)   -   UI   (Train ID:   --)");
      dynamicWindow.setSize(600, 400);
      dynamicWindow.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
      dynamicWindow.add(dScroll);
      isVisible = false;
      dynamicWindow.setVisible(isVisible);

      // Setup the staticWindow.

      jlLength = new JLabel("", JLabel.CENTER);
      jlWidth = new JLabel("", JLabel.CENTER);
      jlHeight = new JLabel("", JLabel.CENTER);
      jlNumCars = new JLabel("", JLabel.CENTER);
      jlMotorPower = new JLabel("", JLabel.CENTER);
      jlMaxSpeed = new JLabel("", JLabel.CENTER);
      jlServiceBrakeDecel = new JLabel("", JLabel.CENTER);
      jlEmergencyBrakeDecel = new JLabel("", JLabel.CENTER);
      jlFrictionCoeff = new JLabel("", JLabel.CENTER);
      jlEmptyTrainMass = new JLabel("", JLabel.CENTER);
      jlPersonMass = new JLabel("", JLabel.CENTER);
      jlMaxSeatedCount = new JLabel("", JLabel.CENTER);
      jlMaxStandingCount = new JLabel("", JLabel.CENTER);
      jlMaxCrewCount = new JLabel("", JLabel.CENTER);

      JPanel swPanel = new JPanel();
      swPanel.setLayout(new GridLayout(14, 2));
      swPanel.add(buildJPanel(new JLabel("Length (m)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlLength));
      swPanel.add(buildJPanel(new JLabel("Width (m)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlWidth));
      swPanel.add(buildJPanel(new JLabel("Height (m)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlHeight));
      swPanel.add(buildJPanel(new JLabel("Number of Cars", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlNumCars));
      swPanel.add(buildJPanel(new JLabel("Motor Power (W)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlMotorPower));
      swPanel.add(buildJPanel(new JLabel("Maximum Speed (m/s)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlMaxSpeed));
      swPanel.add(buildJPanel(new JLabel("Service Brake Deceleration (m/s^2)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlServiceBrakeDecel));
      swPanel.add(buildJPanel(new JLabel("Emergency Brake Deceleration (m/s^2)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlEmergencyBrakeDecel));
      swPanel.add(buildJPanel(new JLabel("Coefficient of Friction", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlFrictionCoeff));
      swPanel.add(
          buildJPanel(new JLabel("Train Mass (not inc. passengers/crew) (kg)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlEmptyTrainMass));
      swPanel.add(buildJPanel(new JLabel("Mass Per Passenger/Crew (kg)", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlPersonMass));
      swPanel.add(buildJPanel(new JLabel("Maximum Seated Passenger Count", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlMaxSeatedCount));
      swPanel.add(buildJPanel(new JLabel("Maximum Standing Passenger Count", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlMaxStandingCount));
      swPanel.add(buildJPanel(new JLabel("Maximum Crew Count", JLabel.CENTER)));
      swPanel.add(buildJPanel(jlMaxCrewCount));

      staticWindow = new JFrame();
      staticWindow.setTitle("Train Model (Chris Paskie)   -   Static Values   (Train ID:   --)");
      staticWindow.setSize(700, 600);
      staticWindow.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
      staticWindow.add(swPanel);
      isVisibleStatic = false;
      staticWindow.setVisible(isVisibleStatic);

      // Set up the TNC UI.
      if (!isSolo) {
        tncUI = new TNC_UI();
      }

    } catch (Exception e) {
      e.printStackTrace(System.err);
      JOptionPane.showMessageDialog(null, e, "Error", JOptionPane.ERROR_MESSAGE);
    }
  }