mirror of
https://github.com/praktimarc/kst4contest.git
synced 2026-08-24 19:17:07 +02:00
154 lines
5.9 KiB
Java
154 lines
5.9 KiB
Java
package kst4contest.controller;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
|
|
import kst4contest.model.AirPlane;
|
|
import kst4contest.model.AirPlaneReflectionInfo;
|
|
import kst4contest.model.ChatMember;
|
|
import kst4contest.model.ChatPreferences;
|
|
|
|
/**
|
|
* Resolves variables used in operator messages, shortcuts, snippets and
|
|
* beacons.
|
|
*
|
|
* <p>Global variables only depend on the local station configuration and can
|
|
* therefore be used in every message context. Station variables additionally
|
|
* require a selected remote station. Keeping both groups in one resolver
|
|
* prevents the send field and the beacon tasks from implementing different
|
|
* replacement rules.</p>
|
|
*/
|
|
public final class MessageVariableResolver {
|
|
|
|
private static final int SHORT_VALUE_LENGTH = 7;
|
|
|
|
private final ChatPreferences chatPreferences;
|
|
|
|
/**
|
|
* Creates a resolver backed by the live application preferences.
|
|
*
|
|
* @param chatPreferences preferences that provide current station values
|
|
*/
|
|
public MessageVariableResolver(ChatPreferences chatPreferences) {
|
|
this.chatPreferences = Objects.requireNonNull(chatPreferences, "chatPreferences");
|
|
}
|
|
|
|
/**
|
|
* Resolves variables which do not require a selected remote station.
|
|
*
|
|
* <p>The replacement is literal rather than regular-expression based.
|
|
* Callsigns, locators and frequencies are data, not regular expressions.</p>
|
|
*
|
|
* @param template text that may contain variables
|
|
* @return text with all available global variables resolved, or {@code null}
|
|
* when the supplied template is {@code null}
|
|
*/
|
|
public String resolveGlobalVariables(String template) {
|
|
if (template == null) {
|
|
return null;
|
|
}
|
|
|
|
String primaryFrequency = valueOrEmpty(chatPreferences.getMYQRGFirstCat().getValue());
|
|
String secondaryFrequency = valueOrEmpty(chatPreferences.getMYQRGSecondCat().getValue());
|
|
String ownLocator = valueOrEmpty(chatPreferences.getStn_loginLocatorMainCat());
|
|
|
|
String resolvedText = template;
|
|
resolvedText = resolvedText.replace("MYQRGSHORT", abbreviate(primaryFrequency));
|
|
resolvedText = resolvedText.replace("MYQRG", primaryFrequency);
|
|
resolvedText = resolvedText.replace("SECONDQRG", secondaryFrequency);
|
|
resolvedText = resolvedText.replace("MYLOCATORSHORT", abbreviateLocator(ownLocator));
|
|
resolvedText = resolvedText.replace("MYLOCATOR", ownLocator);
|
|
resolvedText = resolvedText.replace("MYCALL", valueOrEmpty(chatPreferences.getStn_loginCallSign()));
|
|
resolvedText = resolvedText.replace("MYQTF", formatHeading(chatPreferences.getActualQTF().getValue().doubleValue()));
|
|
return resolvedText;
|
|
}
|
|
|
|
/**
|
|
* Resolves global variables and variables derived from a selected station.
|
|
*
|
|
* <p>If no station is selected, station-specific placeholders remain visible.
|
|
* This is intentional: silently removing {@code QRZNAME}, {@code FIRSTAP} or
|
|
* {@code SECONDAP} could create a plausible-looking but incomplete message.</p>
|
|
*
|
|
* @param template text that may contain variables
|
|
* @param selectedStation currently selected remote station, may be {@code null}
|
|
* @return resolved message text
|
|
*/
|
|
public String resolveForSelectedStation(String template, ChatMember selectedStation) {
|
|
String resolvedText = resolveGlobalVariables(template);
|
|
|
|
if (resolvedText == null || selectedStation == null) {
|
|
return resolvedText;
|
|
}
|
|
|
|
resolvedText = resolvedText.replace("QRZNAME", resolveStationName(selectedStation));
|
|
resolvedText = resolvedText.replace("FIRSTAP", resolveFirstAirPlane(selectedStation));
|
|
resolvedText = resolvedText.replace("SECONDAP", resolveSecondAirPlane(selectedStation));
|
|
return resolvedText;
|
|
}
|
|
|
|
private String resolveStationName(ChatMember selectedStation) {
|
|
String stationName = valueOrEmpty(selectedStation.getName()).trim();
|
|
|
|
if (!stationName.isEmpty()) {
|
|
return stationName;
|
|
}
|
|
|
|
return valueOrEmpty(selectedStation.getCallSign());
|
|
}
|
|
|
|
private String resolveFirstAirPlane(ChatMember selectedStation) {
|
|
List<AirPlane> risingAirPlanes = getRisingAirPlanes(selectedStation);
|
|
|
|
if (risingAirPlanes.isEmpty()) {
|
|
return "no ap available";
|
|
}
|
|
|
|
AirPlane firstAirPlane = risingAirPlanes.get(0);
|
|
return "a " + firstAirPlane.getPotencialDescriptionAsWord()
|
|
+ " in " + firstAirPlane.getArrivingDurationMinutes() + " min";
|
|
}
|
|
|
|
private String resolveSecondAirPlane(ChatMember selectedStation) {
|
|
List<AirPlane> risingAirPlanes = getRisingAirPlanes(selectedStation);
|
|
|
|
if (risingAirPlanes.size() < 2) {
|
|
return "";
|
|
}
|
|
|
|
AirPlane secondAirPlane = risingAirPlanes.get(1);
|
|
return "Next " + secondAirPlane.getPotencialDescriptionAsWord()
|
|
+ " in " + secondAirPlane.getArrivingDurationMinutes() + " min";
|
|
}
|
|
|
|
private List<AirPlane> getRisingAirPlanes(ChatMember selectedStation) {
|
|
AirPlaneReflectionInfo reflectionInfo = selectedStation.getAirPlaneReflectInfo();
|
|
|
|
if (reflectionInfo == null || reflectionInfo.getRisingAirplanes() == null) {
|
|
return List.of();
|
|
}
|
|
|
|
return reflectionInfo.getRisingAirplanes();
|
|
}
|
|
|
|
private String abbreviate(String value) {
|
|
return value.substring(0, Math.min(value.length(), SHORT_VALUE_LENGTH));
|
|
}
|
|
|
|
private String abbreviateLocator(String locator) {
|
|
return locator.substring(0, Math.min(locator.length(), 4));
|
|
}
|
|
|
|
private String formatHeading(double headingDegrees) {
|
|
if (!Double.isFinite(headingDegrees)) {
|
|
return "";
|
|
}
|
|
|
|
return BigDecimal.valueOf(headingDegrees).stripTrailingZeros().toPlainString();
|
|
}
|
|
|
|
private String valueOrEmpty(String value) {
|
|
return value == null ? "" : value;
|
|
}
|
|
} |