Merge branch 'bug5029'

This commit is contained in:
Tim Hessenmüller committed 2019-11-04 15:26:26 +01:00
commit b1f5d43513
7 files changed
+147 -160

No files matched your search

@@ -0,0 +1,53 @@
package com.sap.sailing.domain.common;
import java.util.Date;
import com.sap.sse.common.Util;
public class RaceTimesCalculationUtil {
public static final long MIN_TIME_BEFORE_RACE_START = 3 * 60 * 1000; // 3 minutes
public static final long MIN_TIME_AFTER_RACE_START = 5 * 60 * 1000; // 5 minutes
public static final long TIME_AFTER_LIVE = 5 * 60 * 1000; // 5 minutes
public static final long MAX_TIME_AFTER_RACE_END = 3 * 60 * 1000; // 3 minutes
public static Util.Pair<Date, Date> calculateRaceMinMax(Date liveTimePoint, Date startOfTracking, Date startOfRace,
Date raceFinishingTime, Date raceFinishedTime, Date endOfRace, Date endOfTracking) {
if (liveTimePoint == null) {
return new Util.Pair<Date, Date>(null, null);
}
Date min = null;
Date max = null;
// Range start / min
if (startOfRace != null) {
// We have a start time
min = new Date(startOfRace.getTime() - MIN_TIME_BEFORE_RACE_START);
} else if (startOfTracking != null) {
// We at least have a start of tracking time
min = startOfTracking;
}
if (min == null || liveTimePoint.before(min)){
// There is no start time or the start time is in the future
min = new Date(liveTimePoint.getTime());
}
// Range end / max
if (raceFinishedTime != null) {
// We have a blue flag down event
max = new Date(raceFinishedTime.getTime() + MAX_TIME_AFTER_RACE_END);
} else if (endOfRace != null && raceFinishingTime == null) {
// We have NO blue flag up event and we have an end of race time
max = new Date(endOfRace.getTime() + MAX_TIME_AFTER_RACE_END);
} else {
// We have no end time and are not expecting any end events
if (endOfTracking != null && raceFinishingTime == null) {
max = endOfTracking;
} else {
// No end in sight; Keep on playing
max = new Date(liveTimePoint.getTime() + TIME_AFTER_LIVE);
}
}
return new Util.Pair<Date, Date>(min, max);
}
}
@@ -2,8 +2,10 @@ package com.sap.sailing.domain.common.dto;
import java.util.Date;
import com.sap.sailing.domain.common.RaceTimesCalculationUtil;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.TimingConstants;
import com.sap.sse.common.Util;
import com.sap.sse.security.shared.dto.NamedDTO;
/**
@@ -19,6 +21,7 @@ public class BasicRaceDTO extends NamedDTO {
public Date startOfRace;
public Date endOfRace;
public Date raceFinishingTime;
public Date raceFinishedTime;
public TrackedRaceDTO trackedRace;
@@ -37,44 +40,35 @@ public class BasicRaceDTO extends NamedDTO {
* point of the "live" interval as defined above.
*/
public boolean isLive(long serverTimePointAsMillis) {
final Date startOfLivePeriod;
final Date endOfLivePeriod;
if (trackedRace == null || !trackedRace.hasGPSData || !trackedRace.hasWindData) {
startOfLivePeriod = null;
endOfLivePeriod = null;
} else {
if (startOfRace == null) {
startOfLivePeriod = trackedRace.startOfTracking;
} else {
startOfLivePeriod = new Date(startOfRace.getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
}
if (endOfRace == null) {
if (trackedRace.timePointOfNewestEvent != null) {
endOfLivePeriod = new Date(trackedRace.timePointOfNewestEvent.getTime()
+ TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
} else {
endOfLivePeriod = null;
}
} else {
endOfLivePeriod = new Date(endOfRace.getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
Date timePoint = null;
if (serverTimePointAsMillis != 0) {
timePoint = new Date(serverTimePointAsMillis);
} else if (trackedRace != null && trackedRace.startOfTracking != null) {
timePoint = trackedRace.startOfTracking;
} else if (startOfRace != null) {
timePoint = new Date(startOfRace.getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS + 1);
}
if (trackedRace != null && trackedRace.hasGPSData && trackedRace.hasWindData) {
Util.Pair<Date, Date> minMax = RaceTimesCalculationUtil.calculateRaceMinMax(timePoint,
trackedRace.startOfTracking, startOfRace, raceFinishingTime, raceFinishedTime, endOfRace,
trackedRace.endOfTracking);
Date min = minMax.getA() != null
? new Date(minMax.getA().getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS)
: null;
Date max = minMax.getB() != null
? new Date(minMax.getB().getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS
+ trackedRace.delayToLiveInMs)
: null;
// We are live if at is in between min and max
if (timePoint != null && min != null && max != null) {
return !min.after(timePoint) && !timePoint.after(max);
}
}
// if an empty timepoint is given then take the start of the race
if (serverTimePointAsMillis == 0) {
serverTimePointAsMillis = startOfLivePeriod.getTime()+1;
}
// whenLastTrackedRaceWasLive is null if there is no tracked race for fleet, or the tracked race hasn't started yet at the server time
// when this DTO was assembled, or there were no GPS or wind data
final boolean result =
startOfLivePeriod != null &&
endOfLivePeriod != null &&
startOfLivePeriod.getTime() <= serverTimePointAsMillis &&
serverTimePointAsMillis <= endOfLivePeriod.getTime();
return result;
return false;
}
@Override
public int hashCode() {
final int prime = 31;
@@ -208,6 +208,7 @@ public class DomainFactoryImpl extends SharedDomainFactoryImpl<RaceLogAndTracked
assert trackedRace != null;
raceDTO.startOfRace = trackedRace.getStartOfRace() == null ? null : trackedRace.getStartOfRace().asDate();
raceDTO.endOfRace = trackedRace.getEndOfRace() == null ? null : trackedRace.getEndOfRace().asDate();
raceDTO.raceFinishingTime = trackedRace.getFinishingTime() == null ? null : trackedRace.getFinishingTime().asDate();
raceDTO.raceFinishedTime = trackedRace.getFinishedTime() == null ? null : trackedRace.getFinishedTime().asDate();
raceDTO.status = new RaceStatusDTO();
raceDTO.status.status = trackedRace.getStatus() == null ? null : trackedRace.getStatus().getStatus();
@@ -75,6 +75,7 @@ import com.sap.sailing.domain.common.ManeuverType;
import com.sap.sailing.domain.common.NauticalSide;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.Position;
import com.sap.sailing.domain.common.RaceTimesCalculationUtil;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
import com.sap.sailing.domain.common.SpeedWithBearing;
@@ -1182,45 +1183,42 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
public boolean hasStarted(TimePoint at) {
return getStartOfRace() != null && getStartOfRace().compareTo(at) <= 0;
}
@Override
public boolean isLive(TimePoint at) {
final TimePoint startOfLivePeriod;
final TimePoint endOfLivePeriod;
if (!hasGPSData() || !hasWindData()) {
startOfLivePeriod = null;
endOfLivePeriod = null;
Date timePoint = null;
if (at != null) {
timePoint = at.asDate();
} else {
if (getStartOfRace() == null) {
startOfLivePeriod = getStartOfTracking();
} else {
startOfLivePeriod = getStartOfRace().minus(TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS);
}
if (getEndOfRace() == null) {
if (getTimePointOfNewestEvent() != null) {
endOfLivePeriod = getTimePointOfNewestEvent().plus(
TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS).plus(getDelayToLiveInMillis());
} else {
endOfLivePeriod = null;
}
} else {
endOfLivePeriod = getEndOfRace().plus(TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS);
if (startOfTracking != null) {
timePoint = startOfTracking.asDate();
} else if (startTime != null) {
timePoint = startTime.minus(TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS).plus(1).asDate();
}
}
// if an empty timepoint is given then take the start of the race
if (at == null) {
at = startOfLivePeriod.plus(1);
if (hasGPSData() && hasWindData()) {
Util.Pair<Date, Date> minMax = RaceTimesCalculationUtil.calculateRaceMinMax(timePoint,
startOfTracking != null ? startOfTracking.asDate() : null,
startTime != null ? startTime.asDate() : null,
finishingTime != null ? finishingTime.asDate() : null,
finishedTime != null ? finishedTime.asDate() : null,
endTime != null ? endTime.asDate() : null,
endOfTracking != null ? endOfTracking.asDate() : null);
Date min = minMax.getA() != null
? new Date(minMax.getA().getTime() - TimingConstants.PRE_START_PHASE_DURATION_IN_MILLIS)
: null;
Date max = minMax.getB() != null
? new Date(minMax.getB().getTime() + TimingConstants.IS_LIVE_GRACE_PERIOD_IN_MILLIS
+ getDelayToLiveInMillis())
: null;
// We are live if at is in between min and max
if (min != null && max != null) {
return !min.after(at.asDate()) && !at.asDate().after(max);
}
}
// whenLastTrackedRaceWasLive is null if there is no tracked race for fleet, or the tracked race hasn't started yet at the server time
// when this DTO was assembled, or there were no GPS or wind data
final boolean result =
startOfLivePeriod != null &&
endOfLivePeriod != null &&
!startOfLivePeriod.after(at) &&
!at.after(endOfLivePeriod);
return result;
return false;
}
@Override
@@ -45,7 +45,7 @@ public class LiveRacesList extends Composite {
private final SortableRaceListColumn<LiveRaceDTO, ?> raceViewStateColumn = RaceListColumnFactory.getRaceViewStateColumn();
public RaceListLiveRaces(EventView.Presenter presenter, boolean showRegattaDetails) {
super(presenter, new RaceListColumnSet(1, 1), false);
super(presenter, new RaceListColumnSet(1, 1), false); // See: https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=3819
this.regattaNameColumn.setShowDetails(showRegattaDetails);
}
@@ -6,6 +6,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.common.RaceTimesCalculationUtil;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.security.SecuredDomainType.TrackedRaceActions;
import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil;
@@ -14,6 +15,7 @@ import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sailing.gwt.ui.shared.RaceWithCompetitorsAndBoatsDTO;
import com.sap.sse.common.Duration;
import com.sap.sse.common.Util;
import com.sap.sse.common.Util.Pair;
import com.sap.sse.gwt.client.player.TimeRangeWithZoomProvider;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
@@ -233,43 +235,34 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
*/
@Override
protected boolean isLiveModeToBeMadePossible() {
long liveTimePointInMillis = timer.getLiveTimePointInMillis();
RaceTimesInfoDTO lastRaceTimesInfo = raceTimesInfoProvider != null ? raceTimesInfoProvider.getRaceTimesInfo(selectedRace) : null;
final boolean isLiveModeToBeMadePossible;
if (lastRaceTimesInfo != null &&
// check that we're after startOfTracking or startOfRace minus some leeway:
((lastRaceTimesInfo.startOfTracking != null && liveTimePointInMillis > lastRaceTimesInfo.startOfTracking.getTime()) ||
(lastRaceTimesInfo.startOfRace != null && liveTimePointInMillis > lastRaceTimesInfo.startOfRace.getTime() - RaceTimesCalculationUtil.MIN_TIME_BEFORE_RACE_START))) {
// now check that we cannot know about an end time or are reasonably before it;
// we don't know about the end time if startOfTracking is valid but endOfTracking is not;
// neither do we know about the end time if both, startOfTracking and endOfTracking are null
// and we have neither a valid newestTrackingEvent nor an endOfRace value; if we do, we would
// have to be before the later one plus some leeway.
Date endTimeOfLivePeriod;
if (lastRaceTimesInfo.startOfTracking == null && lastRaceTimesInfo.endOfTracking == null) {
Date latestOfNewestTrackingEventAndEndOfRace = lastRaceTimesInfo.newestTrackingEvent;
if (latestOfNewestTrackingEventAndEndOfRace == null || (lastRaceTimesInfo.endOfRace != null && lastRaceTimesInfo.endOfRace.after(latestOfNewestTrackingEventAndEndOfRace))) {
latestOfNewestTrackingEventAndEndOfRace = lastRaceTimesInfo.endOfRace;
}
endTimeOfLivePeriod = latestOfNewestTrackingEventAndEndOfRace == null ? null :
new Date(latestOfNewestTrackingEventAndEndOfRace.getTime() + RaceTimesCalculationUtil.TIME_AFTER_LIVE);
} else {
endTimeOfLivePeriod = lastRaceTimesInfo.endOfTracking;
if (lastRaceTimesInfo.endOfRace != null) {
// this is a failsafe, if the tracking was never finished, the race was always assumed to be live.
Date latestAllowedTime = new Date(
lastRaceTimesInfo.endOfRace.getTime() + RaceTimesCalculationUtil.MAX_TIME_AFTER_RACE_END);
if (endTimeOfLivePeriod == null || endTimeOfLivePeriod.after(latestAllowedTime)) {
endTimeOfLivePeriod = latestAllowedTime;
}
}
}
isLiveModeToBeMadePossible = endTimeOfLivePeriod == null /* meaning we don't know an end time */ ||
endTimeOfLivePeriod.getTime() >= liveTimePointInMillis;
} else {
isLiveModeToBeMadePossible = false;
RaceTimesInfoDTO lastRaceTimesInfo = raceTimesInfoProvider != null
? raceTimesInfoProvider.getRaceTimesInfo(selectedRace)
: null;
if (lastRaceTimesInfo == null) return false;
Date timePoint = timer.getLiveTimePointAsDate();
Pair<Date, Date> minMax = RaceTimesCalculationUtil.calculateRaceMinMax(timer.getLiveTimePointAsDate(),
lastRaceTimesInfo.startOfTracking, lastRaceTimesInfo.startOfRace, lastRaceTimesInfo.raceFinishingTime,
lastRaceTimesInfo.raceFinishedTime, lastRaceTimesInfo.endOfRace, lastRaceTimesInfo.endOfTracking);
Date min = minMax.getA();
Date max = minMax.getB();
// Bug 3482: try to determine a value for max if max is null
if (max == null && lastRaceTimesInfo.newestTrackingEvent != null) {
max = new Date(lastRaceTimesInfo.newestTrackingEvent.getTime() + RaceTimesCalculationUtil.TIME_AFTER_LIVE);
}
return isLiveModeToBeMadePossible;
// Assume we are live (no end known as of now)
boolean beforeEnd = true;
if (max != null) {
beforeEnd = !timePoint.after(max);
}
if (min != null) {
// min < timePoint < max; max might be unknown as of now
return !timePoint.before(min) && beforeEnd;
}
return beforeEnd;
}
@Override
@@ -291,7 +284,9 @@ public class RaceTimePanel extends TimePanel<RaceTimePanelSettings> implements R
* was <code>null</code> before, or extended to a later point in time.
*/
private void updateMinMax(RaceTimesInfoDTO newRaceTimesInfo) {
Util.Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.calculateRaceMinMax(timer, newRaceTimesInfo);
Util.Pair<Date, Date> raceMinMax = RaceTimesCalculationUtil.calculateRaceMinMax(timer.getLiveTimePointAsDate(),
newRaceTimesInfo.startOfTracking, newRaceTimesInfo.startOfRace, newRaceTimesInfo.raceFinishingTime,
newRaceTimesInfo.raceFinishedTime, newRaceTimesInfo.endOfRace, newRaceTimesInfo.endOfTracking);
Date min = raceMinMax.getA();
Date max = raceMinMax.getB();
@@ -1,54 +0,0 @@
package com.sap.sailing.gwt.ui.client;
import java.util.Date;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.player.Timer;
public class RaceTimesCalculationUtil {
public static final long MIN_TIME_BEFORE_RACE_START = 3 * 60 * 1000; // 3 minutes
public static final long MIN_TIME_AFTER_RACE_START = 5 * 60 * 1000; // 5 minutes
public static final long TIME_AFTER_LIVE = 5 * 60 * 1000; // 5 minutes
public static final long MAX_TIME_AFTER_RACE_END = 1 * 60 * 1000; // 1 minutes
public static Util.Pair<Date, Date> calculateRaceMinMax(Timer timer, RaceTimesInfoDTO raceTimesInfo) {
Date min = null;
Date max = null;
Date liveTimePoint = timer.getLiveTimePointAsDate();
// Range start / min
if (raceTimesInfo.startOfRace != null) {
// We have a start time
min = new Date(raceTimesInfo.startOfRace.getTime() - MIN_TIME_BEFORE_RACE_START);
} else if (raceTimesInfo.startOfTracking != null) {
// We at least have a start of tracking time
min = raceTimesInfo.startOfTracking;
}
if (min == null || liveTimePoint.before(min)){
// There is no start time or the start time is in the future
min = new Date(liveTimePoint.getTime());
}
// Range end / max
if (raceTimesInfo.raceFinishedTime != null) {
// We have a blue flag down event
max = new Date(raceTimesInfo.raceFinishedTime.getTime() + MAX_TIME_AFTER_RACE_END);
} else if (raceTimesInfo.endOfRace != null && raceTimesInfo.raceFinishingTime == null) {
// We have NO blue flag up event and we have an end of race time
max = new Date(raceTimesInfo.endOfRace.getTime() + MAX_TIME_AFTER_RACE_END);
} else {
// We have no end time so just keep playing until they are created
max = new Date(liveTimePoint.getTime() + TIME_AFTER_LIVE);
}
// If there are no end events or the additional offset exceeds end of tracking
if (raceTimesInfo.endOfTracking != null) {
if (max == null || max.after(raceTimesInfo.endOfTracking)) {
max = raceTimesInfo.endOfTracking;
}
}
return new Util.Pair<Date, Date>(min, max);
}
}