bug 4175: using leaderboard to determine "quick ranks" if available;

in the process, I've adjusted the naming of what used to be the
list of competitors ordered by windward distance traveled to simply
"from best to worst." I had changed these semantics some time ago but
never had adjusted the naming accordingly.

Change-Id: I203840842eedf050f5c2ed8a3e052e4bc4d7772d
This commit is contained in:
Axel Uhl
2017-06-10 00:14:40 +02:00
parent 492eb60080
commit a68014fd33
14 changed files with 226 additions and 96 deletions
@@ -30,6 +30,8 @@ import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.RaceTimesInfoProvider;
import com.sap.sailing.gwt.ui.client.SailingServiceAsync;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.shared.racemap.DefaultQuickRanksDTOProvider;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceCompetitorSet;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
@@ -173,8 +175,8 @@ public class StartAnalysisCard extends Composite implements HasWidgets, StartAna
raceMap = new RaceMap(null, null, new RaceMapLifecycle(StringMessages.INSTANCE), raceMapSettings,
sailingServiceAsync,
asyncActionsExecutor, null, timer, competitorSelectionModel,
StringMessages.INSTANCE, startAnalysisDTO.regattaAndRaceIdentifier,
raceMapResources, /* showHeaderPanel */ true);
new RaceCompetitorSet(competitorSelectionModel), StringMessages.INSTANCE,
startAnalysisDTO.regattaAndRaceIdentifier, raceMapResources, /* showHeaderPanel */ true, new DefaultQuickRanksDTOProvider());
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
raceMap.setSize("100%", "100%");
card_map_container.getElement().getStyle().setHeight(getHeightForRaceMapInPixels(), Unit.PX);
@@ -175,6 +175,20 @@ public class LeaderboardEntryDTO implements Serializable {
}
return result;
}
public int getOneBasedCurrentLegNumber() {
int result = 0;
if (legDetails != null && !legDetails.isEmpty()) {
for (LegEntryDTO legDetail : legDetails) {
if (legDetail != null && legDetail.started) {
result++;
} else {
break;
}
}
}
return result;
}
@Override
public int hashCode() {
@@ -17,7 +17,6 @@ public interface LeaderboardUpdateListener {
/**
* Called whenever the leaderboard has been updated.
* @param leaderboard
*/
void updatedLeaderboard(LeaderboardDTO leaderboard);
@@ -0,0 +1,21 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import java.util.LinkedHashMap;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
public class DefaultQuickRanksDTOProvider implements QuickRanksDTOProvider {
private LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanksFromServer;
@Override
public void quickRanksReceivedFromServer(LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanksFromServer) {
this.quickRanksFromServer = quickRanksFromServer;
}
@Override
public LinkedHashMap<CompetitorDTO, QuickRankDTO> getQuickRanks() {
return quickRanksFromServer;
}
}
@@ -0,0 +1,36 @@
package com.sap.sailing.gwt.ui.client.shared.racemap;
import java.util.LinkedHashMap;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
import com.sap.sailing.gwt.ui.raceboard.RaceBoardPanel;
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
import com.sap.sailing.gwt.ui.shared.RaceMapDataDTO;
/**
* The {@link QuickRankDTO} objects stored in the {@link RaceMap}'s {@code quickRanks} field may be obtained in
* different ways. This interface abstracts the different strategies for how this may happen. If a {@link RaceMap} is
* used in the context of a {@link RaceBoardPanel} which is a {@link LeaderboardUpdateListener}, {@link LeaderboardDTO}
* objects can provide the up-to-date information for all aspects of the {@link QuickRankDTO} objects required.
* Otherwise, the {@link QuickRankDTO} objects as received in the {@link RaceMapDataDTO} objects can be used. This may
* not always be consistent and in sync with the leaderboard being shown for a particular time point because their
* calculation in the back-end happens in a lower-priority thread, hence may be a bit delayed in a server under high
* load. See also bug 4175.
*
* @author Axel Uhl (d043530)
*
*/
public interface QuickRanksDTOProvider {
/**
* The strategy may or may not use this quick ranks information provided directly from the server. This information
* may have been provided with some delay and may be slightly inconsistent with a {@link LeaderboardDTO leaderboard}
* that was delivered through a different channel. Therefore, a strategy that has access to a current
* {@link LeaderboardDTO leaderboard} should ignore this call if it already has quick ranks information available
* from a leaderboard.
*/
void quickRanksReceivedFromServer(LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanksFromServer);
LinkedHashMap<CompetitorDTO, QuickRankDTO> getQuickRanks();
}
@@ -8,7 +8,6 @@ import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -76,11 +75,11 @@ import com.sap.sailing.domain.common.Bounds;
import com.sap.sailing.domain.common.Distance;
import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.WindSource;
import com.sap.sailing.domain.common.WindSourceType;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.impl.DegreeBearingImpl;
import com.sap.sailing.domain.common.impl.DegreePosition;
import com.sap.sailing.domain.common.impl.MeterDistance;
@@ -349,18 +348,12 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
private int lastLegNumber;
/**
* The last quick ranks received from a call to {@link SailingServiceAsync#getQuickRanks(RaceIdentifier, Date, AsyncCallback)} upon
* the last {@link #timeChanged(Date, Date)} event. Therefore, the ranks listed here correspond to the {@link #timer}'s time.
* The strategy for maintaining and delivering the "quick ranks" information. The provider will be informed about
* quick ranks received from a {@link RaceMapDataDTO#quickRanks} field but may choose to ignore this information, e.g.,
* if it can assume that more current information about ranks and leg numbers is available from a {@link LeaderboardDTO}.
*/
private LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanks;
private final QuickRanksDTOProvider quickRanksDTOProvider;
/**
* Taken from {@link RaceMapDataDTO#competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber}; tells the
* windward distances traveled and the leg numbers in which the respective competitor is.
*/
private LinkedHashMap<CompetitorDTO, Integer> competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber;
private final CombinedWindPanel combinedWindPanel;
private final TrueNorthIndicatorPanel trueNorthIndicatorPanel;
private final FlowPanel topLeftControlsWrapperPanel;
@@ -418,10 +411,11 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
public RaceMap(Component<?> parent, ComponentContext<?> context, RaceMapLifecycle raceMapLifecycle,
RaceMapSettings raceMapSettings,
SailingServiceAsync sailingService, AsyncActionsExecutor asyncActionsExecutor,
ErrorReporter errorReporter, Timer timer, CompetitorSelectionProvider competitorSelection, StringMessages stringMessages,
RegattaAndRaceIdentifier raceIdentifier, RaceMapResources raceMapResources,
boolean showHeaderPanel) {
ErrorReporter errorReporter, Timer timer, CompetitorSelectionProvider competitorSelection, RaceCompetitorSet raceCompetitorSet,
StringMessages stringMessages, RegattaAndRaceIdentifier raceIdentifier,
RaceMapResources raceMapResources, boolean showHeaderPanel, QuickRanksDTOProvider quickRanksDTOProvider) {
super(parent, context);
this.quickRanksDTOProvider = quickRanksDTOProvider;
this.raceMapLifecycle = raceMapLifecycle;
this.stringMessages = stringMessages;
this.sailingService = sailingService;
@@ -442,7 +436,7 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
courseMarkOverlays = new HashMap<String, CourseMarkOverlay>();
courseMarkClickHandlers = new HashMap<String, HandlerRegistration>();
this.competitorSelection = competitorSelection;
this.raceCompetitorSet = new RaceCompetitorSet(competitorSelection);
this.raceCompetitorSet = raceCompetitorSet;
competitorSelection.addCompetitorSelectionChangeListener(this);
settings = raceMapSettings;
coordinateSystem = new DelegateCoordinateSystem(new IdentityCoordinateSystem());
@@ -972,9 +966,7 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
" in regatta "+raceIdentifier.getRegattaName(), e);
}
}
quickRanks = raceMapDataDTO.quickRanks;
competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber =
raceMapDataDTO.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber;
quickRanksDTOProvider.quickRanksReceivedFromServer(raceMapDataDTO.quickRanks);
if (isSimulationEnabled && settings.isShowSimulationOverlay()) {
lastLegNumber = raceMapDataDTO.coursePositions.currentLegNumber;
simulationOverlay.updateLeg(Math.max(lastLegNumber, 1), /* clearCanvas */ false, raceMapDataDTO.simulationResultVersion);
@@ -1361,35 +1353,29 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
/**
* Returns a pair whose first component is the leg number (one-based) of the competitor returned as the second component.
*/
private com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> getFarthestAheadVisibleCompetitorWithOneBasedLegNumber(
private com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> getBestVisibleCompetitorWithOneBasedLegNumber(
Iterable<CompetitorDTO> competitorsToShow) {
CompetitorDTO leadingCompetitorDTO = null;
int legOfLeaderCompetitor = -1;
// this only works because the quickRanks are sorted
for (Entry<CompetitorDTO, Integer> competitorsByWindwardDistanceTraveledAndOneBasedLegNumber :
getCompetitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber()) {
if (Util.contains(competitorsToShow, competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getKey()) &&
competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getValue() != null) {
leadingCompetitorDTO = competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getKey();
legOfLeaderCompetitor = competitorsByWindwardDistanceTraveledAndOneBasedLegNumber.getValue();
for (QuickRankDTO competitorFromBestToWorstAndOneBasedLegNumber : quickRanksDTOProvider.getQuickRanks().values()) {
if (Util.contains(competitorsToShow, competitorFromBestToWorstAndOneBasedLegNumber.competitor) &&
competitorFromBestToWorstAndOneBasedLegNumber.legNumberOneBased != 0) {
leadingCompetitorDTO = competitorFromBestToWorstAndOneBasedLegNumber.competitor;
legOfLeaderCompetitor = competitorFromBestToWorstAndOneBasedLegNumber.legNumberOneBased;
return new com.sap.sse.common.Util.Pair<Integer, CompetitorDTO>(legOfLeaderCompetitor, leadingCompetitorDTO);
}
}
return null;
}
private Set<Entry<CompetitorDTO, Integer>> getCompetitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber() {
// TODO bug4175: obtain from raceBoardPanel.leaderboardPanel.leaderboard instead of QuickRanks
return competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber.entrySet();
}
final static Distance advantageLineLength = new MeterDistance(1000); // TODO this should probably rather scale with the visible area of the map; bug 616
private void showAdvantageLine(Iterable<CompetitorDTO> competitorsToShow, Date date, long timeForPositionTransitionMillis) {
if (map != null && lastRaceTimesInfo != null && quickRanks != null && lastCombinedWindTrackInfoDTO != null) {
if (map != null && lastRaceTimesInfo != null && quickRanksDTOProvider.getQuickRanks() != null && lastCombinedWindTrackInfoDTO != null) {
boolean drawAdvantageLine = false;
if (settings.getHelpLinesSettings().isVisible(HelpLineTypes.ADVANTAGELINE)) {
// find competitor with highest rank
com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> visibleLeaderInfo = getFarthestAheadVisibleCompetitorWithOneBasedLegNumber(competitorsToShow);
com.sap.sse.common.Util.Pair<Integer, CompetitorDTO> visibleLeaderInfo = getBestVisibleCompetitorWithOneBasedLegNumber(competitorsToShow);
// the boat fix may be null; may mean that no positions were loaded yet for the leading visible boat;
// don't show anything
GPSFixDTOWithSpeedWindTackAndLegType lastBoatFix = null;
@@ -2785,15 +2771,11 @@ public class RaceMap extends AbstractCompositeComponent<RaceMapSettings> impleme
return result;
}
private QuickRankDTO getQuickRank(CompetitorDTO competitorDTO) {
return quickRanks.get(competitorDTO);
}
@Override
public Integer getRank(CompetitorDTO competitor) {
// TODO bug4175: obtain from raceBoardPanel.leaderboardPanel.leaderboard instead of QuickRanks
final Integer result;
QuickRankDTO quickRank = getQuickRank(competitor);
QuickRankDTO quickRank = quickRanksDTOProvider.getQuickRanks().get(competitor);
if (quickRank != null) {
result = quickRank.rank;
} else {
@@ -1648,22 +1648,9 @@ public class LeaderboardPanel extends AbstractCompositeComponent<LeaderboardSett
public Double get(LeaderboardRowDTO row) {
Double result = null;
LeaderboardEntryDTO fieldsForRace = row.fieldsByRaceColumnName.get(getRaceColumnName());
if (fieldsForRace != null && fieldsForRace.legDetails != null && !fieldsForRace.legDetails.isEmpty()) {
for (LegEntryDTO legDetail : fieldsForRace.legDetails) {
if (legDetail != null) {
if (legDetail.started) {
if (result == null) {
result = 0.0;
}
result++;
} else {
if (result != null) {
result++;
}
break;
}
}
}
if (fieldsForRace != null) {
int currentLeg = fieldsForRace.getOneBasedCurrentLegNumber();
result = currentLeg == 0 ? null : (double) currentLeg;
}
return result;
}
@@ -37,6 +37,8 @@ import com.sap.sailing.gwt.ui.client.TimePanelSettings;
import com.sap.sailing.gwt.ui.client.shared.charts.WindChart;
import com.sap.sailing.gwt.ui.client.shared.charts.WindChartLifecycle;
import com.sap.sailing.gwt.ui.client.shared.charts.WindChartSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.DefaultQuickRanksDTOProvider;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceCompetitorSet;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapHelpLinesSettings.HelpLineTypes;
@@ -200,8 +202,8 @@ public class EmbeddedMapAndWindChartEntryPoint extends AbstractSailingEntryPoint
}
final RaceMap raceMap = new RaceMap(null, null, new RaceMapLifecycle(getStringMessages()), raceMapSettings,
sailingService, asyncActionsExecutor, /* errorReporter */ EmbeddedMapAndWindChartEntryPoint.this, timer,
competitorSelection, getStringMessages(), selectedRaceIdentifier, raceMapResources,
/* showHeaderPanel */ false) {
competitorSelection, new RaceCompetitorSet(competitorSelection), getStringMessages(), selectedRaceIdentifier,
raceMapResources, /* showHeaderPanel */ false, new DefaultQuickRanksDTOProvider()) {
@Override
protected void showAdditionalControls(MapWidget map) {
backToLivePlayButton.removeFromParent();
@@ -0,0 +1,111 @@
package com.sap.sailing.gwt.ui.raceboard;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import com.sap.sailing.domain.common.RaceIdentifier;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.common.dto.LeaderboardEntryDTO;
import com.sap.sailing.domain.common.dto.LeaderboardRowDTO;
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
import com.sap.sailing.gwt.ui.client.shared.racemap.QuickRanksDTOProvider;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceCompetitorSet;
import com.sap.sailing.gwt.ui.shared.QuickRankDTO;
import com.sap.sse.common.Util;
/**
* Computes a map of {@link QuickRankDTO}s from a {@link LeaderboardDTO} and a {@link RaceCompetitorSet}, restricting
* the calculation to those competitors actually taking part in a race. If the {@link LeaderboardDTO} does not contain
* detail information about the race, only the order "from best to worst" is used, and ranks are determined based on it,
* whereas the {@link QuickRankDTO#legNumberOneBased leg numbers} will continue to be accepted from the quick ranks
* coming from the server.
*
* @author Axel Uhl (d043530)
*
*/
public class QuickRanksDTOFromLeaderboardDTOProvider implements QuickRanksDTOProvider {
private LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanks;
private final RaceCompetitorSet raceCompetitorSet;
private final RaceIdentifier selectedRace;
private boolean lastLeaderboardProvidedLegNumbers;
private String raceColumnName;
public QuickRanksDTOFromLeaderboardDTOProvider(RaceCompetitorSet raceCompetitorSet, RaceIdentifier selectedRace) {
this.raceCompetitorSet = raceCompetitorSet;
this.selectedRace = selectedRace;
}
@Override
public void quickRanksReceivedFromServer(LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanksFromServer) {
if (quickRanks == null) {
quickRanks = quickRanksFromServer;
} else if (!lastLeaderboardProvidedLegNumbers) {
// extract at least the leg numbers and update existing quick ranks accordingly in place
for (final Entry<CompetitorDTO, QuickRankDTO> e : quickRanks.entrySet()) {
final QuickRankDTO quickRankFromServer = quickRanksFromServer.get(e.getKey());
if (quickRankFromServer != null) {
e.getValue().legNumberOneBased = quickRankFromServer.legNumberOneBased;
}
}
}
}
public void updateQuickRanks(final LeaderboardDTO leaderboard) {
if (quickRanks == null) {
quickRanks = new LinkedHashMap<>();
}
RaceColumnDTO raceColumn = leaderboard.getRaceColumnByName(raceColumnName);
if (raceColumn == null || !raceColumn.containsRace(selectedRace)) {
raceColumnName = getRaceColumnName(leaderboard, selectedRace);
}
if (raceColumnName != null) {
final List<CompetitorDTO> competitorsFromBestToWorst = leaderboard.getCompetitorsFromBestToWorst(raceColumnName);
int rank = 1;
for (final CompetitorDTO c : competitorsFromBestToWorst) {
if (Util.contains(raceCompetitorSet.getCompetitorsParticipatingInRace(), c)) {
final LeaderboardRowDTO row = leaderboard.rows.get(c);
final int oneBasedLegNumber;
if (row != null) {
final LeaderboardEntryDTO raceEntryForCompetitor = row.fieldsByRaceColumnName.get(raceColumnName);
if (raceEntryForCompetitor != null && raceEntryForCompetitor.legDetails != null) {
oneBasedLegNumber = raceEntryForCompetitor.getOneBasedCurrentLegNumber();
lastLeaderboardProvidedLegNumbers = true;
} else {
oneBasedLegNumber = 0;
lastLeaderboardProvidedLegNumbers = false;
}
} else {
oneBasedLegNumber = 0;
}
QuickRankDTO quickRankToUpdate = quickRanks.get(c);
if (quickRankToUpdate == null) {
quickRanks.put(c, new QuickRankDTO(c, rank, oneBasedLegNumber));
} else {
quickRankToUpdate.rank = rank;
if (lastLeaderboardProvidedLegNumbers) {
quickRankToUpdate.legNumberOneBased = oneBasedLegNumber;
}
}
rank++;
}
}
}
}
private String getRaceColumnName(LeaderboardDTO leaderboard, RaceIdentifier selectedRace) {
for (final RaceColumnDTO raceColumn : leaderboard.getRaceList()) {
if (raceColumn.containsRace(selectedRace)) {
return raceColumn.getName();
}
}
return null;
}
@Override
public LinkedHashMap<CompetitorDTO, QuickRankDTO> getQuickRanks() {
return quickRanks;
}
}
@@ -70,6 +70,7 @@ import com.sap.sailing.gwt.ui.client.shared.charts.WindChartLifecycle;
import com.sap.sailing.gwt.ui.client.shared.charts.WindChartSettings;
import com.sap.sailing.gwt.ui.client.shared.filter.FilterWithUI;
import com.sap.sailing.gwt.ui.client.shared.filter.LeaderboardFetcher;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceCompetitorSet;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMap;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapLifecycle;
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapResources;
@@ -158,6 +159,7 @@ public class RaceBoardPanel
private final RaceBoardResources raceBoardResources = RaceBoardResources.INSTANCE;
private final RaceBoardMainCss mainCss = raceBoardResources.mainCss();
private final QuickRanksDTOFromLeaderboardDTOProvider quickRanksDTOProvider;
private static final RaceMapResources raceMapResources = GWT.create(RaceMapResources.class);
@@ -218,10 +220,12 @@ public class RaceBoardPanel
RaceTimePanelLifecycle raceTimePanelLifecycle = lifecycle.getRaceTimePanelLifecycle();
RaceTimePanelSettings raceTimePanelSettings = settings
.findSettingsByComponentId(raceTimePanelLifecycle.getComponentId());
final RaceCompetitorSet raceCompetitorSet = new RaceCompetitorSet(competitorSelectionProvider);
quickRanksDTOProvider = new QuickRanksDTOFromLeaderboardDTOProvider(raceCompetitorSet, selectedRaceIdentifier);
raceMap = new RaceMap(this, componentContext, raceMapLifecycle, defaultRaceMapSettings, sailingService, asyncActionsExecutor,
errorReporter, timer,
competitorSelectionProvider, stringMessages, selectedRaceIdentifier, raceMapResources,
/* showHeaderPanel */ true) {
competitorSelectionProvider, raceCompetitorSet, stringMessages, selectedRaceIdentifier,
raceMapResources, /* showHeaderPanel */ true, quickRanksDTOProvider) {
private static final String INDENT_SMALL_CONTROL_STYLE = "indentsmall";
private static final String INDENT_BIG_CONTROL_STYLE = "indentbig";
@Override
@@ -568,6 +572,7 @@ public class RaceBoardPanel
if (editMarkPositionPanel != null) {
editMarkPositionPanel.setLeaderboard(leaderboard);
}
quickRanksDTOProvider.updateQuickRanks(leaderboard);
}
@Override
@@ -1076,6 +1076,10 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
return result;
}
/**
* Converts the {@link Competitor} objects passed as {@code iterable} to {@link CompetitorDTO} objects.
* The iteration order in the result matches that of the {@code iterable} passed.
*/
private List<CompetitorDTO> convertToCompetitorDTOs(Iterable<? extends Competitor> iterable) {
List<CompetitorDTO> result = new ArrayList<CompetitorDTO>();
for (Competitor c : iterable) {
@@ -2211,7 +2215,6 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
public QuickRanksDTO computeQuickRanks(RegattaAndRaceIdentifier raceIdentifier, TimePoint timePoint)
throws NoWindException {
final List<QuickRankDTO> result = new ArrayList<>();
final List<CompetitorDTO> competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst;
TrackedRace trackedRace = getExistingTrackedRace(raceIdentifier);
if (trackedRace != null) {
final TimePoint actualTimePoint;
@@ -2233,11 +2236,8 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
}
rank++;
}
competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst = convertToCompetitorDTOs(competitorsFromBestToWorst);
} else {
competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst = Collections.emptyList();
}
return new QuickRanksDTO(result, competitorDTOsInOrderOfWindwardDistanceTraveledFarthestFirst);
return new QuickRanksDTO(result);
}
private QuickRanksDTO getQuickRanks(RegattaAndRaceIdentifier raceIdentifier, Date date) throws NoWindException {
@@ -6,7 +6,6 @@ import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.sap.sailing.domain.base.RaceDefinition;
@@ -30,7 +29,6 @@ public class CompactRaceMapDataDTO implements IsSerializable {
private CoursePositionsDTO coursePositions;
private List<SidelineDTO> courseSidelines;
private List<CompactQuickRankDTO> quickRanks;
private LinkedHashMap<String, Integer> competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber;
private long simulationResultVersion;
/**
@@ -46,7 +44,6 @@ public class CompactRaceMapDataDTO implements IsSerializable {
this.boatPositionsByCompetitorIdAsString = new CompactBoatPositionsDTO(boatPositions);
this.raceCompetitorIdsAsStrings = raceCompetitorIdsAsStrings;
this.quickRanks = new ArrayList<CompactQuickRankDTO>(quickRanks == null ? 0 : Util.size(quickRanks.getQuickRanks()));
this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber = new LinkedHashMap<>();
Map<String, Integer> competitorIdAsStringToOneBasedLegNumber = new HashMap<>();
if (quickRanks != null) {
for (QuickRankDTO quickRank : quickRanks.getQuickRanks()) {
@@ -54,11 +51,6 @@ public class CompactRaceMapDataDTO implements IsSerializable {
quickRank.legNumberOneBased));
competitorIdAsStringToOneBasedLegNumber.put(quickRank.competitor.getIdAsString(), quickRank.legNumberOneBased);
}
for (CompetitorDTO competitorInOrderOfWindwardDistanceTraveled : quickRanks.getCompetitorsInOrderOfWindwardDistanceTraveledFarthestFirst()) {
this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.put(
competitorInOrderOfWindwardDistanceTraveled.getIdAsString(),
competitorIdAsStringToOneBasedLegNumber.get(competitorInOrderOfWindwardDistanceTraveled.getIdAsString()));
}
}
this.courseSidelines = courseSidelines;
this.coursePositions = coursePositions;
@@ -77,13 +69,6 @@ public class CompactRaceMapDataDTO implements IsSerializable {
result.courseSidelines = courseSidelines;
result.coursePositions = coursePositions;
result.boatPositions = boatPositionsByCompetitorIdAsString.getBoatPositionsForCompetitors(competitorsByIdAsString);
result.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber = new LinkedHashMap<>();
for (Entry<String, Integer> i : competitorsInOrderOfWindwardDistanceTraveledFarthestFirstIdAsStringAndOneBasedLegNumber.entrySet()) {
CompetitorDTO c = competitorsByIdAsString.get(i.getKey());
if (c != null) {
result.competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber.put(c, i.getValue());
}
}
result.simulationResultVersion = simulationResultVersion;
result.raceCompetitorIdsAsStrings = this.raceCompetitorIdsAsStrings;
return result;
@@ -1,7 +1,5 @@
package com.sap.sailing.gwt.ui.shared;
import com.sap.sailing.domain.common.dto.CompetitorDTO;
/**
* Combines a list of {@link QuickRankDTO} objects telling about the (calculated, according to any handicap ranking metric
* in place)) ranks of the competitors with an information about the boat farthest ahead in the race. The latter is useful,
@@ -17,23 +15,12 @@ public class QuickRanksDTO {
*/
private final Iterable<QuickRankDTO> quickRanksAfterCalculatedTime;
/**
* Lists the competitors according to their windward distance traveled. The first boat (rank 1) is the
* competitor farthest ahead.
*/
private final Iterable<CompetitorDTO> competitorsInOrderOfWindwardDistanceTraveledFarthestFirst;
public QuickRanksDTO(Iterable<QuickRankDTO> quickRanks, Iterable<CompetitorDTO> competitorsInOrderOfWindwardDistanceTraveledFarthestFirst) {
public QuickRanksDTO(Iterable<QuickRankDTO> quickRanks) {
super();
this.quickRanksAfterCalculatedTime = quickRanks;
this.competitorsInOrderOfWindwardDistanceTraveledFarthestFirst = competitorsInOrderOfWindwardDistanceTraveledFarthestFirst;
}
public Iterable<QuickRankDTO> getQuickRanks() {
return quickRanksAfterCalculatedTime;
}
public Iterable<CompetitorDTO> getCompetitorsInOrderOfWindwardDistanceTraveledFarthestFirst() {
return competitorsInOrderOfWindwardDistanceTraveledFarthestFirst;
}
}
@@ -13,7 +13,6 @@ public class RaceMapDataDTO implements IsSerializable {
public CoursePositionsDTO coursePositions;
public List<SidelineDTO> courseSidelines;
public LinkedHashMap<CompetitorDTO, QuickRankDTO> quickRanks;
public LinkedHashMap<CompetitorDTO, Integer> competitorsInOrderOfWindwardDistanceTraveledWithOneBasedLegNumber;
public long simulationResultVersion;
/**