Merge branch 'racecommittee_wind'

This commit is contained in:
Axel Uhl committed 2013-07-08 11:25:38 +02:00
commit cf31cfff62
43 files changed
+736 -100

No files matched your search

@@ -35,7 +35,14 @@ public enum WindSourceType {
* Wind estimation combined from all other wind sources, using <code>TrackedRace.getWind(...)</code>, based on
* confidences
*/
COMBINED(false, 0.9, /* useSpeed */ true);
COMBINED(false, 0.9, /* useSpeed */ true),
/**
* Manually entered by the race committee over the app. As the race committee measures the wind several times over races for documentation purposes,
* their measures are stored in the race log.
*
*/
RACECOMMITTEE(false, 0.9, /* useSpeed */ true);
private final boolean canBeStored;
@@ -3,7 +3,7 @@ package com.sap.sailing.domain.common.racelog.utils;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
public abstract class FlagAlphabetInterpretationTemplate {
public abstract class RaceStateFlagsInterpretationTemplate {
public String getMeaningOfRaceStateAndFlags(RaceLogRaceStatus status, Flags upperFlag, Flags lowerFlag, boolean isDisplayed) {
String statusText = "";
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogRaceStatusEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.FinishedTimeFinder;
public class FinishedTmeFinderTest extends PassAwareRaceLogAnalyzerTest<FinishedTimeFinder, TimePoint> {
public class FinishedTimeFinderTest extends PassAwareRaceLogAnalyzerTest<FinishedTimeFinder, TimePoint> {
@Override
protected FinishedTimeFinder createAnalyzer(RaceLog raceLog) {
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogRaceStatusEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.FinishingTimeFinder;
public class FinishingTmeFinderTest extends PassAwareRaceLogAnalyzerTest<FinishingTimeFinder, TimePoint> {
public class FinishingTimeFinderTest extends PassAwareRaceLogAnalyzerTest<FinishingTimeFinder, TimePoint> {
@Override
protected FinishingTimeFinder createAnalyzer(RaceLog raceLog) {
@@ -36,7 +36,6 @@ public class LastWindFixFinderTest extends RaceLogAnalyzerTest<LastWindFixFinder
raceLog.add(event1);
raceLog.add(event2);
raceLog.lockForRead();
assertEquals(event2.getWindFix(), analyzer.analyze());
}
}
@@ -45,7 +45,6 @@ public class ProtestStartTimeFinderTest extends PassAwareRaceLogAnalyzerTest<Pro
raceLog.add(event1);
raceLog.add(event2);
raceLog.lockForRead();
assertEquals(event2.getProtestStartTime(), analyzer.analyze());
}
}
@@ -13,7 +13,7 @@ import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.StartTimeFinder;
public class StartTmeFinderTest extends PassAwareRaceLogAnalyzerTest<StartTimeFinder, TimePoint> {
public class StartTimeFinderTest extends PassAwareRaceLogAnalyzerTest<StartTimeFinder, TimePoint> {
@Override
protected StartTimeFinder createAnalyzer(RaceLog raceLog) {
@@ -0,0 +1,55 @@
package com.sap.sailing.domain.racelog.analyzing.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.List;
import org.junit.Test;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogFlagEvent;
import com.sap.sailing.domain.racelog.RaceLogWindFixEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.WindFixesFinder;
import com.sap.sailing.domain.tracking.Wind;
public class WindFixesFinderTest extends RaceLogAnalyzerTest<WindFixesFinder> {
@Override
protected WindFixesFinder createAnalyzer(RaceLog raceLog) {
return new WindFixesFinder(raceLog);
}
@Test
public void testEmptyForNone() {
RaceLogEvent event1 = createEvent(RaceLogEvent.class, 1);
raceLog.add(event1);
List<Wind> windList = analyzer.analyze();
assertNotNull(windList);
assertEquals(0, windList.size());
}
@Test
public void testWindFixList() {
RaceLogFlagEvent event1 = createEvent(RaceLogFlagEvent.class, 1);
RaceLogWindFixEvent event2 = createEvent(RaceLogWindFixEvent.class, 2);
RaceLogWindFixEvent event3 = createEvent(RaceLogWindFixEvent.class, 3);
when(event2.getWindFix()).thenReturn(mock(Wind.class));
when(event3.getWindFix()).thenReturn(mock(Wind.class));
raceLog.add(event1);
raceLog.add(event2);
raceLog.add(event3);
List<Wind> windList = analyzer.analyze();
assertNotNull(windList);
assertEquals(2, windList.size());
assertEquals(event3.getWindFix(), windList.get(0));
assertEquals(event2.getWindFix(), windList.get(1));
}
}
@@ -0,0 +1,29 @@
package com.sap.sailing.domain.racelog.analyzing.impl;
import java.util.ArrayList;
import java.util.List;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogEvent;
import com.sap.sailing.domain.racelog.RaceLogWindFixEvent;
import com.sap.sailing.domain.tracking.Wind;
public class WindFixesFinder extends RaceLogAnalyzer<List<Wind>> {
public WindFixesFinder(RaceLog raceLog) {
super(raceLog);
}
@Override
protected List<Wind> performAnalyzation() {
final List<Wind> windFixes = new ArrayList<Wind>();
for (RaceLogEvent event : getAllEventsDescending()) {
if (event instanceof RaceLogWindFixEvent) {
RaceLogWindFixEvent windFixEvent = (RaceLogWindFixEvent) event;
windFixes.add(windFixEvent.getWindFix());
}
}
return windFixes;
}
}
@@ -103,7 +103,7 @@ public abstract class AbstractRaceColumn extends SimpleAbstractRaceColumn implem
this.trackedRaces.remove(fleet);
if (previouslyLinkedRace != null) {
RaceLogIdentifierImpl identifier = new RaceLogIdentifierImpl(raceLogInformation.getIdentifierTemplate(), getName(), fleet);
previouslyLinkedRace.detachRaceLog(identifier);
previouslyLinkedRace.detachRaceLog(identifier.getIdentifier());
getRaceColumnListeners().notifyListenersAboutTrackedRaceUnlinked(this, fleet, previouslyLinkedRace);
}
}
@@ -1,6 +1,9 @@
package com.sap.sailing.domain.tracking.impl;
import com.sap.sailing.domain.base.CourseBase;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogCourseAreaChangedEvent;
import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent;
@@ -18,11 +21,15 @@ import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
import com.sap.sailing.domain.racelog.RaceLogWindFixEvent;
import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder;
import com.sap.sailing.domain.racelog.analyzing.impl.RaceStatusAnalyzer;
import com.sap.sailing.domain.racelog.analyzing.impl.WindFixesFinder;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.Wind;
public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
private DynamicTrackedRace trackedRace;
private final WindSource raceCommitteeWindSource;
private RaceStatusAnalyzer statusAnalyzer;
@@ -30,6 +37,7 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
public DynamicTrackedRaceLogListener(DynamicTrackedRace trackedRace) {
this.trackedRace = trackedRace;
raceCommitteeWindSource = new WindSourceImpl(WindSourceType.RACECOMMITTEE);
}
public void addTo(RaceLog raceLog) {
@@ -38,9 +46,21 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
trackedRace.invalidateEndTime();
courseDesignFinder = new LastPublishedCourseDesignFinder(raceLog);
statusAnalyzer = new RaceStatusAnalyzer(raceLog);
initializeWindTrack(raceLog);
analyze();
}
/**
* Retrieves all wind fixes available in the race log and adds them to the wind track for RACECOMMITTEEE
* @param raceLog The race log from which the available wind fixes shall be retrieved.
*/
private void initializeWindTrack(RaceLog raceLog) {
WindFixesFinder windFixesFinder = new WindFixesFinder(raceLog);
for (Wind wind : windFixesFinder.analyze()) {
trackedRace.recordWind(wind, raceCommitteeWindSource);
}
}
public void removeFrom(RaceLog raceLog) {
// Gets called whenever a RaceColumn was already linked to a TrackedRace on linkage.
// Maybe we need to reset the status of the old race somehow? There might be no new
@@ -50,10 +70,22 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
// ??? trackedRace.setStatus(new TrackedRaceStatusImpl(TrackedRaceStatusEnum.PREPARED, 0.0));
if (raceLog != null) {
trackedRace.invalidateStartTime();
removeAllWindFixesFromWindTrack(raceLog);
raceLog.removeListener(this);
}
}
/**
* Removes all wind fixes that are in the RaceLog from the RACECOMMITTEE wind source
* @param raceLog the RaceLog of which the wind fixes shall be removed
*/
private void removeAllWindFixesFromWindTrack(RaceLog raceLog) {
WindFixesFinder windFixesFinder = new WindFixesFinder(raceLog);
for (Wind wind : windFixesFinder.analyze()) {
trackedRace.removeWind(wind, raceCommitteeWindSource);
}
}
private void analyze() {
analyzeStatus();
analyzeCourseDesign();
@@ -138,8 +170,8 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
@Override
public void visit(RaceLogWindFixEvent event) {
// TODO handle a new wind fix entered by the race committee
// add the wind fix to the race committee WindTrack
trackedRace.recordWind(event.getWindFix(), raceCommitteeWindSource);
}
}
@@ -1,6 +1,7 @@
package com.sap.sailing.gwt.ui.client;
import com.google.gwt.i18n.client.Messages;
import com.google.gwt.safehtml.shared.SafeHtml;
public interface StringMessages extends Messages {
String helloWorld();
@@ -270,6 +271,7 @@ public interface StringMessages extends Messages {
String trackBasedEstimationWindSourceTypeName();
String expeditionWindSourceTypeName();
String webWindSourceTypeName();
String raceCommitteeWindSourceTypeName();
String clickChartToSetTime();
String position();
String windSourcesUsed();
@@ -700,6 +702,33 @@ public interface StringMessages extends Messages {
String raceLogReloaded();
String reloadAllRaceLogs();
String sideline();
String classAndGolfUp();
String classDisplayed();
String papaDisplayed();
String blackDisplayed();
String zuluIndiaDisplayed();
String papaRemoved();
String blackRemoved();
String zuluIndiaRemoved();
String classFlagRemoved();
String xray();
String firstSubstitute();
String blueFlagDisplayed();
String blueFlagRemoved();
String golfRemoved();
String answeringPennantOverAlphaDisplayed();
String answeringPennantOverHotelDisplayed();
String answeringPennantDisplayed();
String answeringPennantRemoved();
String novemberOverAlphaDisplayed();
String novemberOverHotelDisplayed();
String novemberDisplayed();
String bravoDisplayed();
String bravoRemoved();
String essThreeDisplayed();
String essTwoDisplayed();
String essOneDisplayed();
String essOneRemoved();
String export();
String dataBeforeAfter();
String rawFixes();
@@ -713,4 +742,5 @@ public interface StringMessages extends Messages {
String importOverrideSwitchLabel();
String importSelectedLeaderboardGroups();
String importSelectAtLeastOne();
String deselectAll();
}
@@ -293,6 +293,7 @@ courseBasedWindSourceTypeName=Course Layout
trackBasedEstimationWindSourceTypeName=Estimation
expeditionWindSourceTypeName=Measured
webWindSourceTypeName=Manual
raceCommitteeWindSourceTypeName=Race Committee
clickChartToSetTime=Click on the chart to set the time
position=Position
windSourcesUsed=Wind Sources Used
@@ -695,6 +696,33 @@ raceLogReloaded=RaceLog successfully reloaded from database
reloadAllRaceLogs=Reload all race logs
export=Export
sideline=Sideline
classAndGolfUp=Flag displayed - eight minutes till start - the startprocedure is a gate start
classDisplayed=Flag displayed - five minutes till start
papaDisplayed=Start mode flag - four minutes till start
blackDisplayed=Start mode flag - disqualification for early starters - four minutes till start
zuluIndiaDisplayed=Start mode flag - penalties for early starters - four minutes till start
papaRemoved=Start mode flag - one minute till start
blackRemoved=Start mode flag - disqualification for early starters - one minute till start
zuluIndiaRemoved=Start mode flag - start with penalties for early starters - one minute till start
classFlagRemoved=Flag removed - race starting signal
xray=Individual recall - had early starters
firstSubstitute=General recall - had too many early starters - start procedure will be repeated
blueFlagDisplayed=Flag displayed - first competitor passed the finishing line
blueFlagRemoved=Flag removed - last competitor passed the finishing line or the finish time limit is passed
golfRemoved=Flag removed - gate is closed
answeringPennantOverAlphaDisplayed=Flag displayed - start postponed - no more racing today
answeringPennantOverHotelDisplayed=Flag displayed - start postponed - further signals ashore
answeringPennantDisplayed=Flag displayed - start postponed
answeringPennantRemoved=Flag removed - start procedure starts in one minute
novemberOverAlphaDisplayed=Flag displayed - race abandoned - no more racing today
novemberOverHotelDisplayed=Flag displayed - race abandoned - further signals ashore
novemberDisplayed=Flag displayed - race abandoned
bravoDisplayed=Protest time started
bravoRemoved=Protest time ended
essThreeDisplayed=Three minutes till start
essTwoDisplayed=Two minutes till start
essOneDisplayed=One minute till start
essOneRemoved=Race starting signal
dataBeforeAfter=Data from before/after race
rawFixes=All fixes (including outliers)
importRemoteHost=Remote host:
@@ -706,4 +734,5 @@ importServerError=GET leaderboardgroups request failed with Server error. Please
importLeaderboardGroups=Leaderboard Groups:
importOverrideSwitchLabel=Override existing data if names and ids match
importSelectedLeaderboardGroups=Import selected leaderboard groups
importSelectAtLeastOne=You have to select at least one leaderboard group to import
importSelectAtLeastOne=You have to select at least one leaderboard group to import
deselectAll=Deselect all
@@ -294,6 +294,7 @@ courseBasedWindSourceTypeName=Kurslayout
trackBasedEstimationWindSourceTypeName=Schätzung
expeditionWindSourceTypeName=Messung
webWindSourceTypeName=Manuell
raceCommitteeWindSourceTypeName=Wettfahrtleitung
clickChartToSetTime=Klicke auf das Diagramm um die Zeit zu setzen
position=Position
windSourcesUsed=Benutzte Windquellen
@@ -691,6 +692,33 @@ raceLogReloaded=RaceLog wurde neu geladen
reloadAllRaceLogs=Alle RaceLogs neu laden
export=Exportieren
sideline=Seitenlinie
classAndGolfUp=Flagge angezeigt - acht Minuten bis zum Start - die Startprozedur ist der Gate Start
classDisplayed=Flagge angezeigt - fünf Minuten bis zum Start
papaDisplayed=Startmodusflagge - vier Minuten bis zum Start
blackDisplayed=Startmodusflagge - Disqualifizierung für Frühstarter - vier Minuten bis zum Start
zuluIndiaDisplayed=Startmodusflagge - Strafen für Frühstarter - vier Minuten bis zum Start
papaRemoved=Startmodusflagge - eine Minute bis zum Start
blackRemoved=Startmodusflagge - Disqualifizierung für Frühstarter - eine Minute bis zum Start
zuluIndiaRemoved=Startmodusflagge - Strafen für Frühstarter - eine Minute bis zum Start
classFlagRemoved=Flagge heruntergenommen - Rennstartsignal
xray=Individueller Rückruf eines Frühstarters
firstSubstitute=Gesamtrückruf - es gab zu viele Frühstarter - die Startprozedur wird wiederholt
blueFlagDisplayed=Flagge angezeigt - erster Teilnehmer im Ziel
blueFlagRemoved=Flagge heruntergenommen - letzter Teilnehmer hat das Ziel erreicht oder das Zielzeitlimit ist erreicht
golfRemoved=Flagge heruntergenommen - das Startgate ist geschlossen
answeringPennantOverAlphaDisplayed=Flagge angezeigt - Startverschiebung - heute keine Rennen mehr
answeringPennantOverHotelDisplayed=Flagge angezeigt - Startverschiebung - weitere Signale an Land
answeringPennantDisplayed=Flagge angezeigt - Startverschiebung
answeringPennantRemoved=Flagge heruntergenommen - Startprozedur startet in einer Minute
novemberOverAlphaDisplayed=Flagge angezeigt - Rennabbruch - heute keine Rennen mehr
novemberOverHotelDisplayed=Flagge angezeigt - Rennabbruch - weitere Signale an Land
novemberDisplayed=Flagge angezeigt - Rennabbruch
bravoDisplayed=Protestzeit hat begonnen
bravoRemoved=Protestzeit beendet
essThreeDisplayed=Drei Minuten bis zum Start
essTwoDisplayed=Zwei Minuten bis zum Start
essOneDisplayed=Eine Minute bis zum Start
essOneRemoved=Rennstartsignal
dataBeforeAfter=Daten von vor/nach dem Rennen
rawFixes=Alle Fixes (inklusive Ausreißer)
importRemoteHost=Entfernter Host:
@@ -702,4 +730,5 @@ importServerError=Der GET leaderboardgroups Request scheiterte an einem Server E
importLeaderboardGroups=Leaderboard Groups:
importOverrideSwitchLabel=Bei übereinstimmenden IDs und Namen die Daten überschreiben
importSelectedLeaderboardGroups=Ausgewählte Leaderboard Groups selektieren
importSelectAtLeastOne=Es muss mindestens eine Leaderboard Group ausgewählt werden
importSelectAtLeastOne=Es muss mindestens eine Leaderboard Group ausgewählt werden
deselectAll=Alle deselektieren
@@ -16,6 +16,8 @@ public class WindSourceTypeFormatter {
return stringMessages.expeditionWindSourceTypeName();
case WEB:
return stringMessages.webWindSourceTypeName();
case RACECOMMITTEE:
return stringMessages.raceCommitteeWindSourceTypeName();
}
return null;
}
@@ -0,0 +1,67 @@
package com.sap.sailing.gwt.ui.regattaoverview;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.gwt.ui.client.StringMessages;
public class FlagsMeaningExplanator {
public static String getFlagsMeaning(StringMessages stringMessages, Flags upperFlag, Flags lowerFlag, boolean displayed) {
if (upperFlag.equals(Flags.CLASS) && lowerFlag.equals(Flags.GOLF) && displayed) {
return stringMessages.classAndGolfUp();
} else if (upperFlag.equals(Flags.CLASS) && displayed) {
return stringMessages.classDisplayed();
} else if (upperFlag.equals(Flags.PAPA) && displayed) {
return stringMessages.papaDisplayed();
} else if (upperFlag.equals(Flags.BLACK) && displayed) {
return stringMessages.blackDisplayed();
} else if ((upperFlag.equals(Flags.ZULU) || upperFlag.equals(Flags.INDIA)) && displayed) {
return stringMessages.zuluIndiaDisplayed();
} else if (upperFlag.equals(Flags.PAPA) && !displayed) {
return stringMessages.papaRemoved();
} else if (upperFlag.equals(Flags.BLACK) && !displayed) {
return stringMessages.blackRemoved();
} else if ((upperFlag.equals(Flags.ZULU) || upperFlag.equals(Flags.INDIA)) && !displayed) {
return stringMessages.zuluIndiaRemoved();
} else if (upperFlag.equals(Flags.CLASS) && !displayed) {
return stringMessages.classFlagRemoved();
} else if (upperFlag.equals(Flags.XRAY)) {
return stringMessages.xray();
} else if (upperFlag.equals(Flags.FIRSTSUBSTITUTE)) {
return stringMessages.firstSubstitute();
} else if (upperFlag.equals(Flags.BLUE) && displayed) {
return stringMessages.blueFlagDisplayed();
} else if (upperFlag.equals(Flags.BLUE) && !displayed) {
return stringMessages.blueFlagRemoved();
} else if (upperFlag.equals(Flags.GOLF) && !displayed) {
return stringMessages.golfRemoved();
} else if (upperFlag.equals(Flags.AP) && lowerFlag.equals(Flags.ALPHA) && displayed) {
return stringMessages.answeringPennantOverAlphaDisplayed();
} else if (upperFlag.equals(Flags.AP) && lowerFlag.equals(Flags.HOTEL) && displayed) {
return stringMessages.answeringPennantOverHotelDisplayed();
} else if (upperFlag.equals(Flags.AP) && displayed) {
return stringMessages.answeringPennantDisplayed();
} else if (upperFlag.equals(Flags.AP) && !displayed) {
return stringMessages.answeringPennantRemoved();
} else if (upperFlag.equals(Flags.NOVEMBER) && lowerFlag.equals(Flags.ALPHA) && displayed) {
return stringMessages.novemberOverAlphaDisplayed();
} else if (upperFlag.equals(Flags.NOVEMBER) && lowerFlag.equals(Flags.HOTEL) && displayed) {
return stringMessages.novemberOverHotelDisplayed();
} else if (upperFlag.equals(Flags.NOVEMBER) && displayed) {
return stringMessages.novemberDisplayed();
} else if (upperFlag.equals(Flags.BRAVO) && displayed) {
return stringMessages.bravoDisplayed();
} else if (upperFlag.equals(Flags.BRAVO) && !displayed) {
return stringMessages.bravoRemoved();
} else if (upperFlag.equals(Flags.ESSTHREE) && displayed) {
return stringMessages.essThreeDisplayed();
} else if (upperFlag.equals(Flags.ESSTWO) && displayed) {
return stringMessages.essTwoDisplayed();
} else if (upperFlag.equals(Flags.ESSONE) && displayed) {
return stringMessages.essOneDisplayed();
} else if (upperFlag.equals(Flags.ESSONE) && !displayed) {
return stringMessages.essOneRemoved();
}
return "";
}
}
@@ -40,7 +40,7 @@ public class RaceDetailPanel extends SimplePanel {
private final DateTimeFormat dateFormatter = DateTimeFormat.getFormat("dd.MM.yyyy");
private final DurationFormat durationFormatter = new DurationFormat();
private final NumberFormat decimalFormat = NumberFormat.getFormat("#.##");
private final FlagAlphabetInterpreter flagInterpreter;
private final RaceStateFlagsInterpreter flagInterpreter;
private final StringMessages stringMessages;
private final Button closeButton;
@@ -61,7 +61,7 @@ public class RaceDetailPanel extends SimplePanel {
public RaceDetailPanel(final StringMessages stringMessages, final ClickHandler closeButtonHandler) {
this.stringMessages = stringMessages;
this.flagInterpreter = new FlagAlphabetInterpreter(stringMessages);
this.flagInterpreter = new RaceStateFlagsInterpreter(stringMessages);
closeButton = new Button(stringMessages.close());
closeButton.addClickHandler(new ClickHandler() {
@Override
@@ -1,13 +1,13 @@
package com.sap.sailing.gwt.ui.regattaoverview;
import com.sap.sailing.domain.common.racelog.utils.FlagAlphabetInterpretationTemplate;
import com.sap.sailing.domain.common.racelog.utils.RaceStateFlagsInterpretationTemplate;
import com.sap.sailing.gwt.ui.client.StringMessages;
public class FlagAlphabetInterpreter extends FlagAlphabetInterpretationTemplate {
public class RaceStateFlagsInterpreter extends RaceStateFlagsInterpretationTemplate {
private StringMessages stringMessages;
public FlagAlphabetInterpreter(StringMessages stringMessages) {
public RaceStateFlagsInterpreter(StringMessages stringMessages) {
this.stringMessages = stringMessages;
}
@@ -92,7 +92,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
private TextColumn<RegattaOverviewEntryDTO> fleetNameColumn;
private final RegattaRaceStatesSettings settings;
private final FlagAlphabetInterpreter flagInterpreter;
private final RaceStateFlagsInterpreter flagInterpreter;
private final String localStorageRegattaOverviewEventKey;
@@ -133,7 +133,7 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
this.localStorageRegattaOverviewEventKey = LOCAL_STORAGE_REGATTA_OVERVIEW_KEY + eventIdAsString;
this.flagInterpreter = new FlagAlphabetInterpreter(stringMessages);
this.flagInterpreter = new RaceStateFlagsInterpreter(stringMessages);
this.settings = new RegattaRaceStatesSettings();
loadAndSetSettings(settings);
@@ -411,11 +411,15 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
@Override
public SafeHtml getValue(RegattaOverviewEntryDTO entryDTO) {
String tooltip = "";
if (entryDTO.raceInfo.lastUpperFlag != null) {
if (entryDTO.raceInfo.lastUpperFlag != null && entryDTO.raceInfo.lastLowerFlag != null) {
tooltip = entryDTO.raceInfo.lastUpperFlag.name();
if (entryDTO.raceInfo.lastLowerFlag != null && !entryDTO.raceInfo.lastLowerFlag.equals(Flags.NONE)) {
if (!entryDTO.raceInfo.lastLowerFlag.equals(Flags.NONE)) {
tooltip += " over " + entryDTO.raceInfo.lastLowerFlag.name();
}
tooltip += " " + FlagsMeaningExplanator.getFlagsMeaning(stringMessages,
entryDTO.raceInfo.lastUpperFlag,
entryDTO.raceInfo.lastLowerFlag,
entryDTO.raceInfo.isLastFlagDisplayed);
}
return SailingFlagsBuilder.render(
entryDTO.raceInfo.lastUpperFlag,
@@ -6,7 +6,10 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusWidget;
@@ -34,6 +37,8 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
private final Map<String, CheckBox> courseAreaCheckBoxMap;
private final Map<String, CheckBox> regattaCheckBoxMap;
private final Anchor resultingLink;
private Button courseAreaDeselectButton;
private Button regattaDeselectButton;
private final static String SETTINGS_DIALOG_COMPONENT = "SettingsDialogComponent";
@@ -68,9 +73,12 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
Grid courseAreaGrid = new Grid(numberOfRequiredRows, maxCourseAreasPerRow);
courseAreaPanel.add(courseAreaGrid);
boolean allCheckboxesSelected = true;
for (CourseAreaDTO courseAreaDTO : courseAreas) {
CheckBox checkBox = dialog.createCheckbox(courseAreaDTO.getName());
checkBox.setValue(Util.contains(initialSettings.getVisibleCourseAreas(), courseAreaDTO.id));
boolean isCourseAreaVisible = Util.contains(initialSettings.getVisibleCourseAreas(), courseAreaDTO.id);
allCheckboxesSelected &= isCourseAreaVisible;
checkBox.setValue(isCourseAreaVisible);
courseAreaCheckBoxMap.put(courseAreaDTO.id, checkBox);
courseAreaGrid.setWidget(rowIndex, columnIndex++, checkBox);
@@ -79,6 +87,29 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
columnIndex = 0;
}
}
courseAreaDeselectButton = new Button();
setTextOfDeselectButton(courseAreaDeselectButton, allCheckboxesSelected);
courseAreaDeselectButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (courseAreaDeselectButton.getText().equals(stringMessages.deselectAll())) {
for (CheckBox checkBox : courseAreaCheckBoxMap.values()) {
checkBox.setValue(false);
}
courseAreaDeselectButton.setText(stringMessages.selectAll());
} else {
for (CheckBox checkBox : courseAreaCheckBoxMap.values()) {
checkBox.setValue(true);
}
courseAreaDeselectButton.setText(stringMessages.deselectAll());
}
}
});
flowPanel.add(courseAreaDeselectButton);
return flowPanel;
}
@@ -101,9 +132,12 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
Grid regattaGrid = new Grid(numberOfRequiredRows, maxRegattasPerRow);
regattaNamesPanel.add(regattaGrid);
boolean allCheckboxesSelected = true;
for (RaceGroupDTO raceGroup : raceGroups) {
CheckBox checkBox = dialog.createCheckbox(raceGroup.displayName);
checkBox.setValue(Util.contains(initialSettings.getVisibleRegattas(), raceGroup.getName()));
boolean isRaceGroupVisible = Util.contains(initialSettings.getVisibleRegattas(), raceGroup.getName());
allCheckboxesSelected &= isRaceGroupVisible;
checkBox.setValue(isRaceGroupVisible);
regattaCheckBoxMap.put(raceGroup.getName(), checkBox);
regattaGrid.setWidget(rowIndex, columnIndex++, checkBox);
@@ -112,9 +146,40 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
columnIndex = 0;
}
}
regattaDeselectButton = new Button();
setTextOfDeselectButton(regattaDeselectButton, allCheckboxesSelected);
regattaDeselectButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (regattaDeselectButton.getText().equals(stringMessages.deselectAll())) {
for (CheckBox checkBox : regattaCheckBoxMap.values()) {
checkBox.setValue(false);
}
regattaDeselectButton.setText(stringMessages.selectAll());
} else {
for (CheckBox checkBox : regattaCheckBoxMap.values()) {
checkBox.setValue(true);
}
regattaDeselectButton.setText(stringMessages.deselectAll());
}
}
});
flowPanel.add(regattaDeselectButton);
return flowPanel;
}
private void setTextOfDeselectButton(Button deselectButton, boolean allCheckboxesSelected) {
if (allCheckboxesSelected) {
deselectButton.setText(stringMessages.deselectAll());
} else {
deselectButton.setText(stringMessages.selectAll());
}
}
private CheckBox getShowOnlyRacesOfSameDayWidget(DataEntryDialog<?> dialog) {
showOnlyRacesOfSameDayCheckBox = dialog.createCheckbox(stringMessages.showOnlyRacesOfSameDay());
showOnlyRacesOfSameDayCheckBox.setValue(initialSettings.isShowOnlyRacesOfSameDay());
@@ -160,6 +225,8 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
selectedCourseAreas.add(entry.getKey());
}
}
boolean allCourseAreasSelected = selectedCourseAreas.size() == courseAreas.size();
setTextOfDeselectButton(courseAreaDeselectButton, allCourseAreasSelected);
List<String> selectedRegattas = new ArrayList<String>();
for (Entry<String, CheckBox> entry : regattaCheckBoxMap.entrySet()) {
@@ -167,6 +234,8 @@ public class RegattaRaceStatesSettingsDialogComponent implements SettingsDialogC
selectedRegattas.add(entry.getKey());
}
}
boolean allRegattasSelected = selectedRegattas.size() == raceGroups.size();
setTextOfDeselectButton(regattaDeselectButton, allRegattasSelected);
boolean isShowOnlyRacesOfSameDay = showOnlyRacesOfSameDayCheckBox.getValue();
boolean isShowOnlyCurrentlyRunningRaces = showOnlyCurrentlyRunningRacesCheckBox.getValue();
@@ -0,0 +1,212 @@
package com.sap.sailing.server.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.RaceDefinition;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.CourseImpl;
import com.sap.sailing.domain.base.impl.KnotSpeedWithBearingImpl;
import com.sap.sailing.domain.base.impl.MillisecondsTimePoint;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.RaceDefinitionImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.RegattaName;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.TimePoint;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.Util;
import com.sap.sailing.domain.common.impl.WindSourceImpl;
import com.sap.sailing.domain.leaderboard.impl.LowPoint;
import com.sap.sailing.domain.racelog.RaceLog;
import com.sap.sailing.domain.racelog.RaceLogEventFactory;
import com.sap.sailing.domain.racelog.RaceLogWindFixEvent;
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
import com.sap.sailing.domain.tracking.Wind;
import com.sap.sailing.domain.tracking.WindTrack;
import com.sap.sailing.domain.tracking.impl.EmptyWindStore;
import com.sap.sailing.domain.tracking.impl.WindImpl;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sailing.server.operationaltransformation.AddColumnToLeaderboard;
import com.sap.sailing.server.operationaltransformation.AddDefaultRegatta;
import com.sap.sailing.server.operationaltransformation.AddRaceDefinition;
import com.sap.sailing.server.operationaltransformation.ConnectTrackedRaceToLeaderboardColumn;
import com.sap.sailing.server.operationaltransformation.CreateFlexibleLeaderboard;
import com.sap.sailing.server.operationaltransformation.CreateTrackedRace;
import com.sap.sailing.server.operationaltransformation.DisconnectLeaderboardColumnFromTrackedRace;
import com.sap.sailing.server.operationaltransformation.TrackRegatta;
public class WindByRaceLogTest {
private DynamicTrackedRace trackedRace;
private RegattaNameAndRaceName raceIdentifier;
private RaceColumn raceColumn;
private Fleet defaultFleet;
private RacingEventService service;
@Before
public void setup() throws Exception {
this.service = new RacingEventServiceImpl();
final String boatClassName = "49er";
// FIXME use master DomainFactory; see bug 592
final DomainFactory masterDomainFactory = DomainFactory.INSTANCE;
BoatClass boatClass = masterDomainFactory.getOrCreateBoatClass(boatClassName, /* typicallyStartsUpwind */true);
Competitor competitor = createCompetitor(masterDomainFactory);
int[] discardThreshold = {1, 2};
CreateFlexibleLeaderboard createLeaderboardOperation = new CreateFlexibleLeaderboard("Test Leaderboard", "Test", discardThreshold, new LowPoint(), null);
service.apply(createLeaderboardOperation);
AddColumnToLeaderboard leaderboardColumnOperation = new AddColumnToLeaderboard("R1", "Test Leaderboard", false);
raceColumn = service.apply(leaderboardColumnOperation);
final String baseRegattaName = "Test Event";
AddDefaultRegatta addRegattaOperation = new AddDefaultRegatta(baseRegattaName, boatClassName, UUID.randomUUID());
Regatta regatta = service.apply(addRegattaOperation);
final String raceName = "Test Race";
final CourseImpl masterCourse = new CourseImpl("Test Course", new ArrayList<Waypoint>());
RaceDefinition race = new RaceDefinitionImpl(raceName, masterCourse, boatClass, Collections.singletonList(competitor));
AddRaceDefinition addRaceOperation = new AddRaceDefinition(new RegattaName(regatta.getName()), race);
service.apply(addRaceOperation);
masterCourse.addWaypoint(0, masterDomainFactory.createWaypoint(masterDomainFactory.getOrCreateMark("Mark1"), /*passingSide*/ null));
raceIdentifier = new RegattaNameAndRaceName(regatta.getName(), raceName);
service.apply(new TrackRegatta(raceIdentifier));
trackedRace = (DynamicTrackedRace) service.apply(new CreateTrackedRace(raceIdentifier, EmptyWindStore.INSTANCE, /* delayToLiveInMillis */ 5000,
/* millisecondsOverWhichToAverageWind */ 10000, /* millisecondsOverWhichToAverageSpeed */10000));
defaultFleet = Util.get(raceColumn.getFleets(), 0);
}
private Competitor createCompetitor(final DomainFactory masterDomainFactory) {
return masterDomainFactory.getOrCreateCompetitor("GER 61", "Sailor", new TeamImpl("Sailor",
(List<PersonImpl>) Arrays.asList(new PersonImpl[] { new PersonImpl("Sailor 1", DomainFactory.INSTANCE.getOrCreateNationality("GER"), null, null)}),
new PersonImpl("Sailor 2", DomainFactory.INSTANCE.getOrCreateNationality("NED"), null, null)),
new BoatImpl("GER 61", DomainFactory.INSTANCE.getOrCreateBoatClass("470", /* typicallyStartsUpwind */ true), "GER 61"));
}
private void attachTrackedRaceToRaceColumn() {
ConnectTrackedRaceToLeaderboardColumn connectColumn = new ConnectTrackedRaceToLeaderboardColumn("Test Leaderboard", "R1",
defaultFleet.getName(), raceIdentifier);
service.apply(connectColumn);
}
private void detachTrackedRaceFromRaceColumn() {
DisconnectLeaderboardColumnFromTrackedRace disconnectColumn = new DisconnectLeaderboardColumnFromTrackedRace("Test Leaderboard", "R1", defaultFleet.getName());
service.apply(disconnectColumn);
}
@Test
public void testAttachingRaceLogContainingWindFixes() {
RaceLog raceLog = raceColumn.getRaceLog(defaultFleet);
TimePoint timeMinus3 = MillisecondsTimePoint.now().minus(20);
TimePoint timeMinus2 = MillisecondsTimePoint.now().minus(10);
Wind wind1 = new WindImpl(new DegreePosition(50, 4), timeMinus3,
new KnotSpeedWithBearingImpl(15, new DegreeBearingImpl(234)));
Wind wind2 = new WindImpl(new DegreePosition(49, 3), timeMinus2,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)));
RaceLogWindFixEvent windEvent1 = RaceLogEventFactory.INSTANCE.createWindFixEvent(timeMinus3, 0, wind1);
RaceLogWindFixEvent windEvent2 = RaceLogEventFactory.INSTANCE.createWindFixEvent(timeMinus2, 0, wind2);
raceLog.add(windEvent1);
raceLog.add(windEvent2);
attachTrackedRaceToRaceColumn();
WindSource source = new WindSourceImpl(WindSourceType.RACECOMMITTEE);
assertTrue(Util.contains(trackedRace.getWindSources(), source));
WindTrack windTrack = trackedRace.getOrCreateWindTrack(source);
try {
windTrack.lockForRead();
assertTrue(Util.contains(windTrack.getFixes(), wind1));
assertTrue(Util.contains(windTrack.getFixes(), wind2));
} finally {
windTrack.unlockAfterRead();
}
}
@Test
public void testAttachingRaceLogAndAddWindFixes() {
RaceLog raceLog = raceColumn.getRaceLog(defaultFleet);
TimePoint timeMinus3 = MillisecondsTimePoint.now().minus(20);
attachTrackedRaceToRaceColumn();
Wind wind1 = new WindImpl(new DegreePosition(50, 4), timeMinus3,
new KnotSpeedWithBearingImpl(15, new DegreeBearingImpl(234)));
RaceLogWindFixEvent windEvent1 = RaceLogEventFactory.INSTANCE.createWindFixEvent(timeMinus3, 0, wind1);
raceLog.add(windEvent1);
WindSource source = new WindSourceImpl(WindSourceType.RACECOMMITTEE);
assertTrue(Util.contains(trackedRace.getWindSources(), source));
WindTrack windTrack = trackedRace.getOrCreateWindTrack(source);
try {
windTrack.lockForRead();
assertTrue(Util.contains(windTrack.getFixes(), wind1));
} finally {
windTrack.unlockAfterRead();
}
}
@Test
public void testDetachingRaceLogWithWindFixes() {
RaceLog raceLog = raceColumn.getRaceLog(defaultFleet);
TimePoint timeMinus3 = MillisecondsTimePoint.now().minus(20);
TimePoint timeMinus2 = MillisecondsTimePoint.now().minus(10);
TimePoint timeMinus1 = MillisecondsTimePoint.now().minus(5);
Wind wind1 = new WindImpl(new DegreePosition(50, 4), timeMinus3,
new KnotSpeedWithBearingImpl(15, new DegreeBearingImpl(234)));
Wind wind2 = new WindImpl(new DegreePosition(49, 3), timeMinus2,
new KnotSpeedWithBearingImpl(12, new DegreeBearingImpl(123)));
Wind wind3 = new WindImpl(new DegreePosition(48, 1), timeMinus2,
new KnotSpeedWithBearingImpl(18, new DegreeBearingImpl(270)));
RaceLogWindFixEvent windEvent1 = RaceLogEventFactory.INSTANCE.createWindFixEvent(timeMinus3, 0, wind1);
RaceLogWindFixEvent windEvent2 = RaceLogEventFactory.INSTANCE.createWindFixEvent(timeMinus2, 0, wind2);
RaceLogWindFixEvent windEvent3 = RaceLogEventFactory.INSTANCE.createWindFixEvent(timeMinus1, 0, wind3);
raceLog.add(windEvent1);
raceLog.add(windEvent2);
attachTrackedRaceToRaceColumn();
raceLog.add(windEvent3);
detachTrackedRaceFromRaceColumn();
WindSource source = new WindSourceImpl(WindSourceType.RACECOMMITTEE);
assertTrue(Util.contains(trackedRace.getWindSources(), source));
WindTrack windTrack = trackedRace.getOrCreateWindTrack(source);
try {
windTrack.lockForRead();
assertFalse(Util.contains(windTrack.getFixes(), wind1));
assertFalse(Util.contains(windTrack.getFixes(), wind2));
assertFalse(Util.contains(windTrack.getFixes(), wind3));
} finally {
windTrack.unlockAfterRead();
}
}
}