package shared.model; import javafx.animation.AnimationTimer; import javafx.collections.FXCollections; import mock.model.VMG; import network.Messages.Enums.RaceStatusEnum; import network.Messages.Enums.RaceTypeEnum; import network.Messages.LatestMessages; import shared.dataInput.BoatDataSource; import shared.dataInput.RaceDataSource; import shared.dataInput.RegattaDataSource; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import static java.lang.Math.cos; /** * Represents a yacht race. * This is a base class inherited by {@link mock.model.MockRace} and {@link visualiser.model.VisualiserRace}. * Has a course, state, wind, boundaries, etc.... Boats are added by inheriting classes (see {@link Boat}, {@link mock.model.MockBoat}, {@link visualiser.model.VisualiserBoat}. */ public abstract class Race implements Runnable { /** * The source of race related data. */ protected RaceDataSource raceDataSource; /** * The source of boat related data. */ protected BoatDataSource boatDataSource; /** * The source of regatta related data. */ protected RegattaDataSource regattaDataSource; /** * The collection of latest race messages. * Can be either read from or written to. */ protected LatestMessages latestMessages; /** * The sequence number of the latest boatLocation message sent or received. */ protected int boatLocationSequenceNumber = 1; /** * A list of compound marks in the race. */ protected List compoundMarks; /** * A list of legs in the race. */ protected List legs; /** * A list of coordinates describing the boundary of the course. */ protected List boundary; /** * The elapsed time, in milliseconds, of the race. */ protected long totalTimeElapsed; /** * The starting timestamp, in milliseconds, of the race. */ protected long startTime; /** * The race ID of the course. */ protected int raceId; /** * The current status of the race. */ protected RaceStatusEnum raceStatusEnum; /** * The type of race this is. */ protected RaceTypeEnum raceType; /** * The current wind direction bearing. */ protected Bearing windDirection; /** * Wind speed (knots). * Convert this to millimeters per second before passing to RaceStatus. */ protected double windSpeed; /** * Constructs a race object with a given BoatDataSource, RaceDataSource, and RegattaDataSource. * @param boatDataSource Data source for boat related data (yachts and marker boats). * @param raceDataSource Data source for race related data (participating boats, legs, etc...). * @param regattaDataSource Data source for race related data (course name, location, timezone, etc...). * @param latestMessages The collection of latest messages, which can be written to, or read from. */ public Race(BoatDataSource boatDataSource, RaceDataSource raceDataSource, RegattaDataSource regattaDataSource, LatestMessages latestMessages) { //Keep a reference to data sources. this.raceDataSource = raceDataSource; this.boatDataSource = boatDataSource; this.regattaDataSource = regattaDataSource; this.latestMessages = latestMessages; this.compoundMarks = raceDataSource.getCompoundMarks(); this.boundary = raceDataSource.getBoundary(); this.useLegsList(raceDataSource.getLegs()); this.raceId = raceDataSource.getRaceId(); this.startTime = raceDataSource.getStartDateTime().toInstant().toEpochMilli(); this.setRaceStatusEnum(RaceStatusEnum.NOT_ACTIVE); this.raceType = raceDataSource.getRaceType(); this.windSpeed = 0; this.windDirection = Bearing.fromDegrees(0); this.totalTimeElapsed = 0; } /** * Initialise the boats in the race. * This sets their starting positions and current legs. */ protected abstract void initialiseBoats(); /** * Updates the race to use a new list of legs, and adds a dummy "Finish" leg at the end. * @param legs The new list of legs to use. */ protected void useLegsList(List legs) { //We add a "dummy" leg at the end of the race. this.legs = legs; this.legs.add(new Leg("Finish", this.legs.size())); } /** * Determines whether or not a specific leg is the last leg in the race. * @param leg The leg to check. * @return Returns true if it is the last, false otherwise. */ protected boolean isLastLeg(Leg leg) { //Get the last leg. Leg lastLeg = this.legs.get(this.legs.size() - 1); //Check its ID. int lastLegID = lastLeg.getLegNumber(); //Get the specified leg's ID. int legID = leg.getLegNumber(); //Check if they are the same. return legID == lastLegID; } /** * Returns the current race status. * @return The current race status. */ public RaceStatusEnum getRaceStatusEnum() { return raceStatusEnum; } /** * Sets the current race status. * @param raceStatusEnum The new status of the race. */ protected void setRaceStatusEnum(RaceStatusEnum raceStatusEnum) { this.raceStatusEnum = raceStatusEnum; } /** * Returns the type of race this is. * @return The type of race this is. */ public RaceTypeEnum getRaceType() { return raceType; } }