package de.saring.exerciseviewer.gui.panels;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import de.saring.exerciseviewer.gui.EVDocument;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import de.saring.exerciseviewer.data.EVExercise;
import de.saring.exerciseviewer.data.HeartRateLimit;
import de.saring.exerciseviewer.gui.EVContext;
import de.saring.util.unitcalc.FormatUtils;
import javafx.util.StringConverter;
/**
* Controller (MVC) class of the "Main" panel, which displays all the main exercise data.
*
* @author Stefan Saring
*/
public class MainPanelController extends AbstractPanelController {
private DiagramPanelController diagramPanelController;
@FXML
private Label laDateTimeValue;
@FXML
private Label laDurationValue;
@FXML
private Label laEnergyValue;
@FXML
private Label laDeviceValue;
@FXML
private Label laTypeValue;
@FXML
private Label laHeartrateAvgValue;
@FXML
private Label laHeartrateMaxValue;
@FXML
private ChoiceBox<HeartRateLimit> cbHeartrateRanges;
@FXML
private Label laTimeBelowValue;
@FXML
private Label laTimeWithinValue;
@FXML
private Label laTimeAboveValue;
@FXML
private Label laModeSpeedValue;
@FXML
private Label laModeAltitudeValue;
@FXML
private Label laModeCadendeValue;
@FXML
private Label laModePowerValue;
@FXML
private Label laTotalExerciseTimeValue;
@FXML
private Label laTotalRidingTimeValue;
@FXML
private Label laTotalEnergyValue;
@FXML
private Label laOdometerValue;
/**
* Standard c'tor for dependency injection.
*
* @param context the ExerciseViewer UI context
* @param document the ExerciseViewer document / model
*/
public MainPanelController(final EVContext context, final EVDocument document) {
super(context, document);
}
public void setDiagramPanelController(final DiagramPanelController diagramPanelController) {
this.diagramPanelController = diagramPanelController;
}
@Override
protected String getFxmlFilename() {
return "/fxml/panels/MainPanel.fxml";
}
@Override
protected void setupPanel() {
showExerciseData();
setupHeartrateRangeSelection();
}
private void showExerciseData() {
final EVExercise exercise = getDocument().getExercise();
final FormatUtils formatUtils = getContext().getFormatUtils();
if (exercise.getFileType() != EVExercise.ExerciseFileType.HRM) {
// fill energy data
if (exercise.getEnergy() > 0) {
laEnergyValue.setText(formatUtils.caloriesToString(exercise.getEnergy()));
}
// fill statistics data
if (exercise.getSumExerciseTime() > 0) {
laTotalExerciseTimeValue.setText(formatUtils.minutes2TimeString(exercise.getSumExerciseTime()));
}
if (exercise.getEnergyTotal() > 0) {
laTotalEnergyValue.setText(formatUtils.caloriesToString(exercise.getEnergyTotal()));
}
// fill total riding time (available only in S710 exercises)
if (exercise.getFileType() == EVExercise.ExerciseFileType.S710RAW) {
laTotalRidingTimeValue.setText(formatUtils.minutes2TimeString(exercise.getSumRideTime()));
}
}
// fill device and type data
if (exercise.getDeviceName() != null && !exercise.getDeviceName().trim().isEmpty()) {
laDeviceValue.setText(exercise.getDeviceName());
}
if (exercise.getType() != null) {
laTypeValue.setText(exercise.getType());
}
// fill time data
if (exercise.getDateTime() != null) {
laDateTimeValue.setText(exercise.getDateTime().format(
DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)));
}
if (exercise.getDuration() > 0) {
laDurationValue.setText(formatUtils.tenthSeconds2TimeString(exercise.getDuration()));
}
// fill heartrate data
if (exercise.getHeartRateAVG() > 0) {
laHeartrateAvgValue.setText(formatUtils.heartRateToString(exercise.getHeartRateAVG()));
}
if (exercise.getHeartRateMax() > 0) {
laHeartrateMaxValue.setText(formatUtils.heartRateToString(exercise.getHeartRateMax()));
}
// fill recording mode data
laModeSpeedValue.setText(boolean2EnabledString(exercise.getRecordingMode().isSpeed()));
laModeAltitudeValue.setText(boolean2EnabledString(exercise.getRecordingMode().isAltitude()));
laModeCadendeValue.setText(boolean2EnabledString(exercise.getRecordingMode().isCadence()));
laModePowerValue.setText(boolean2EnabledString(exercise.getRecordingMode().isPower()));
// fill odometer data (if available, e.g. not on Polar S410 or S610)
if (exercise.getOdometer() != 0) {
laOdometerValue.setText(formatUtils.distanceToString(exercise.getOdometer(), 2));
}
}
/**
* Fills the heartrate range selection choicebox with the ranges stored in the exercise and selects
* the first one. When no ranges are available, the selection will be disabled.<br/>
*/
private void setupHeartrateRangeSelection() {
cbHeartrateRanges.addEventHandler(ActionEvent.ACTION, event -> updateHeartRateRangeTimes());
cbHeartrateRanges.setConverter(new StringConverter<HeartRateLimit>() {
@Override
public String toString(final HeartRateLimit limit) {
final String unitName = limit.isAbsoluteRange() ? "bpm" : "%";
return "" + limit.getLowerHeartRate() + " - " + limit.getUpperHeartRate() + " " + unitName;
}
@Override
public HeartRateLimit fromString(String string) {
throw new UnsupportedOperationException();
}
});
final EVExercise exercise = getDocument().getExercise();
if (exercise.getHeartRateLimits() != null && exercise.getHeartRateLimits().length > 0) {
cbHeartrateRanges.getItems().addAll(exercise.getHeartRateLimits());
cbHeartrateRanges.getSelectionModel().select(0);
} else {
cbHeartrateRanges.setDisable(true);
}
}
/**
* Updates the heartrate time value labels with the values of the current selected range.
*/
private void updateHeartRateRangeTimes() {
final EVExercise exercise = getDocument().getExercise();
final FormatUtils formatUtils = getContext().getFormatUtils();
final HeartRateLimit limit = cbHeartrateRanges.getValue();
// calculate percentages of times below, within and above
int percentsBelow = 0, percentsWithin = 0, percentsAbove = 0;
if (exercise.getDuration() > 0) {
percentsBelow = (int) Math.round(limit.getTimeBelow() / (double) exercise.getDuration() * 10 * 100);
percentsWithin = (int) Math.round(limit.getTimeWithin() / (double) exercise.getDuration() * 10 * 100);
percentsAbove = (int) Math.round(limit.getTimeAbove() / (double) exercise.getDuration() * 10 * 100);
}
laTimeBelowValue.setText(formatUtils.seconds2TimeString(limit.getTimeBelow()) + " (" + percentsBelow + " %)");
laTimeWithinValue.setText(formatUtils.seconds2TimeString(limit.getTimeWithin()) + " (" + percentsWithin + " %)");
laTimeAboveValue.setText(formatUtils.seconds2TimeString(limit.getTimeAbove()) + " (" + percentsAbove + " %)");
// update heartrate range in diagram
diagramPanelController.displayDiagramForHeartrateRange(limit);
}
private String boolean2EnabledString(final boolean enabled) {
return getContext().getResources().getString(enabled ? "common.enabled" : "common.disabled");
}
}