package visualiser.Controllers; import javafx.animation.AnimationTimer; import javafx.application.Platform; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.GridPane; import mock.model.commandFactory.CompositeCommand; import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RequestToJoinEnum; import network.Messages.LatestMessages; import shared.dataInput.*; import shared.enums.XMLFileType; import shared.exceptions.InvalidBoatDataException; import shared.exceptions.InvalidRaceDataException; import shared.exceptions.InvalidRegattaDataException; import shared.exceptions.XMLReaderException; import visualiser.gameController.ControllerClient; import visualiser.model.VisualiserRaceState; import visualiser.network.ServerConnection; import visualiser.model.VisualiserBoat; import visualiser.model.VisualiserRaceEvent; import java.io.IOException; import java.net.Socket; import java.net.URL; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; /** * Controller to for waiting for the race to start. */ public class StartController extends Controller { @FXML private GridPane start; @FXML private AnchorPane startWrapper; /** * The name of the race/regatta. */ @FXML private Label raceTitleLabel; /** * The time the race starts at. */ @FXML private Label raceStartLabel; /** * The current time at the race location. */ @FXML private Label timeZoneTime; /** * Time until the race starts. */ @FXML private Label timer; @FXML private TableView boatNameTable; @FXML private TableColumn boatNameColumn; @FXML private TableColumn boatCodeColumn; /** * The status of the race. */ @FXML private Label raceStatusLabel; /** * The race + connection to server. */ private VisualiserRaceEvent visualiserRaceEvent; /** * Writes BoatActions to outgoing message queue. */ private ControllerClient controllerClient; private boolean isHost; /** * Ctor. */ public StartController() { } @Override public void initialize(URL location, ResourceBundle resources) { } /** * Starts the race. */ private void startRace() { //Initialise the boat table. initialiseBoatTable(this.visualiserRaceEvent.getVisualiserRaceState()); //Initialise the race name. initialiseRaceName(this.visualiserRaceEvent.getVisualiserRaceState()); //Initialises the race clock. initialiseRaceClock(this.visualiserRaceEvent.getVisualiserRaceState()); //Starts the race countdown timer. countdownTimer(); } public AnchorPane startWrapper(){ return startWrapper; } /** * Initialises the boat table that is to be shown on the pane. * @param visualiserRace The race to get data from. */ private void initialiseBoatTable(VisualiserRaceState visualiserRace) { //Get the boats. ObservableList boats = visualiserRace.getBoats(); //Populate table. boatNameTable.setItems(boats); boatNameColumn.setCellValueFactory(cellData -> cellData.getValue().nameProperty()); boatCodeColumn.setCellValueFactory(cellData -> cellData.getValue().countryProperty()); } /** * Initialises the race name which is shown on the pane. * @param visualiserRace The race to get data from. */ private void initialiseRaceName(VisualiserRaceState visualiserRace) { raceTitleLabel.setText(visualiserRace.getRegattaName()); } /** * Initialises the race clock/timer labels for the start time, current time, and remaining time. * @param visualiserRace The race to get data from. */ private void initialiseRaceClock(VisualiserRaceState visualiserRace) { //Start time. initialiseRaceClockStartTime(visualiserRace); //Current time. initialiseRaceClockCurrentTime(visualiserRace); //Remaining time. initialiseRaceClockDuration(visualiserRace); } /** * Initialises the race current time label. * @param visualiserRace The race to get data from. */ private void initialiseRaceClockStartTime(VisualiserRaceState visualiserRace) { raceStartLabel.setText(visualiserRace.getRaceClock().getStartingTimeString()); visualiserRace.getRaceClock().startingTimeProperty().addListener((observable, oldValue, newValue) -> { Platform.runLater(() -> { raceStartLabel.setText(newValue); }); }); } /** * Initialises the race current time label. * @param visualiserRace The race to get data from. */ private void initialiseRaceClockCurrentTime(VisualiserRaceState visualiserRace) { visualiserRace.getRaceClock().currentTimeProperty().addListener((observable, oldValue, newValue) -> { Platform.runLater(() -> { timeZoneTime.setText(newValue); }); }); } /** * Initialises the race duration label. * @param visualiserRace The race to get data from. */ private void initialiseRaceClockDuration(VisualiserRaceState visualiserRace) { visualiserRace.getRaceClock().durationProperty().addListener((observable, oldValue, newValue) -> { Platform.runLater(() -> { timer.setText(newValue); }); }); } /** * Countdown timer until race starts. */ private void countdownTimer() { new AnimationTimer() { @Override public void handle(long arg0) { //Get the current race status. RaceStatusEnum raceStatus = visualiserRaceEvent.getVisualiserRaceState().getRaceStatusEnum(); //If the race has reached the preparatory phase, or has started... if (raceStatus == RaceStatusEnum.WARNING || raceStatus == RaceStatusEnum.PREPARATORY || raceStatus == RaceStatusEnum.STARTED) { //Stop this timer. stop(); //Hide this, and display the race controller. startWrapper.setVisible(false); //start.setVisible(false);//TODO is this needed? parent.beginRace(visualiserRaceEvent, controllerClient, isHost); } } }.start(); } /** * Show starting information for a race given a socket. * @param socket network source of information * @param isHost is user a host */ public void enterLobby(Socket socket, Boolean isHost) { try { this.isHost = isHost; this.visualiserRaceEvent = new VisualiserRaceEvent(socket, RequestToJoinEnum.PARTICIPANT); this.controllerClient = visualiserRaceEvent.getControllerClient(); startWrapper.setVisible(true); startRace(); } catch (IOException e) { //TODO should probably let this propagate, so that we only enter this scene if everything works Logger.getGlobal().log(Level.WARNING, "Could not connect to server.", e); } } }