Skip to content

Commit d017770

Browse files
committed
refactor(service): rewrite replaceIntermediateStopWithNode with approriate names and comments
This method was very painful to read and understand. Signed-off-by: Louis Greiner <louis.greiner@proton.me>
1 parent aa75a90 commit d017770

File tree

2 files changed

+103
-96
lines changed

2 files changed

+103
-96
lines changed

src/app/services/data/data.service.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,9 @@ export class DataService implements OnDestroy {
129129
);
130130

131131
this.trainrunSectionService.getTrainrunSectionFromId(currentSection.id).setNumberOfStops(0);
132-
const {existingTrainrunSection, newTrainrunSection} =
133-
this.trainrunSectionService.replaceIntermediateStopWithNode(
134-
currentSection.id,
135-
newNode.getId(),
136-
);
137-
138-
currentSection = newTrainrunSection.getDto();
132+
currentSection = this.trainrunSectionService
133+
.replaceIntermediateStopWithNode(currentSection.id, newNode.getId())
134+
.getDto();
139135
}
140136
}
141137
}

src/app/services/data/trainrunsection.service.ts

Lines changed: 100 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -860,119 +860,130 @@ export class TrainrunSectionService implements OnDestroy {
860860
// this function is no longer used for its original purpose (drag a node that only existed inside numberOfStops and create it inside the real graph)
861861
replaceIntermediateStopWithNode(
862862
trainrunSectionId: number,
863-
nodeId: number,
864-
stopDuration?: number,
865-
) {
866-
const trainrunSection1 = this.getTrainrunSectionFromId(trainrunSectionId);
863+
intermediateNodeId: number,
864+
initialStopDuration?: number,
865+
): TrainrunSection | null {
866+
// Before:
867+
// initialSourceNode ◄─[port]──[port]─► initialTargetNode
868+
// initialSection
869+
//
870+
// After:
871+
// initialSourceNode ◄-[port]──[port]─► intermediateNode ◄─[port]──[port]─► initialTargetNode
872+
// initialSection newSection
873+
874+
const initialSection = this.getTrainrunSectionFromId(trainrunSectionId);
867875
if (
868-
trainrunSection1.getSourceNodeId() === nodeId ||
869-
trainrunSection1.getTargetNodeId() === nodeId
876+
initialSection.getSourceNodeId() === intermediateNodeId ||
877+
initialSection.getTargetNodeId() === intermediateNodeId
870878
) {
871-
return {};
879+
// Early return if the intermediate node is already part of the trainrun section
880+
return null;
872881
}
873-
const origTravelTime = trainrunSection1.getTravelTime();
874-
const trainrunSection2 = this.copyTrainrunSection(
875-
trainrunSection1,
876-
trainrunSection1.getTrainrunId(),
877-
);
878-
const node1 = trainrunSection1.getSourceNode();
879-
const node2 = trainrunSection1.getTargetNode();
880-
const nodeIntermediate = this.nodeService.getNodeFromId(nodeId);
881-
const transition1: Transition = node1.getTransition(trainrunSection1.getId());
882-
const nonStop1 = transition1 !== undefined ? transition1.getIsNonStopTransit() : false;
883-
const transition2: Transition = node2.getTransition(trainrunSection1.getId());
884-
const nonStop2 = transition2 !== undefined ? transition2.getIsNonStopTransit() : false;
885-
886-
node2.replaceTrainrunSectionOnPort(trainrunSection1, trainrunSection2);
887-
888-
trainrunSection1.setTargetNode(nodeIntermediate);
889-
nodeIntermediate.addPortWithRespectToOppositeNode(node1, trainrunSection1);
890-
node1.reAlignPortWithRespectToOppositeNode(nodeIntermediate, trainrunSection1);
891-
892-
trainrunSection2.setSourceNode(nodeIntermediate);
893-
trainrunSection2.setTargetNode(node2);
894-
nodeIntermediate.addPortWithRespectToOppositeNode(node2, trainrunSection2);
895-
node2.reAlignPortWithRespectToOppositeNode(nodeIntermediate, trainrunSection2);
896-
882+
// Create new section with same properties as initial section
883+
const newSection = this.copyTrainrunSection(initialSection, initialSection.getTrainrunId());
884+
885+
// Store initial values for later validation
886+
const initialTravelTime = initialSection.getTravelTime();
887+
const initialSourceNode = initialSection.getSourceNode();
888+
const initialTargetNode = initialSection.getTargetNode();
889+
890+
// Store initial transition properties for later validation
891+
const initialTargetNodeTransition = initialTargetNode.getTransition(initialSection.getId());
892+
const isInitialTargetNodeNonStop = initialTargetNodeTransition?.getIsNonStopTransit();
893+
894+
// Update initial target node port to use new section instead of initial section
895+
initialTargetNode.replaceTrainrunSectionOnPort(initialSection, newSection);
896+
897+
// Update initial section to point from intermediate node to initial target node
898+
const intermediateNode = this.nodeService.getNodeFromId(intermediateNodeId);
899+
initialSection.setTargetNode(intermediateNode);
900+
intermediateNode.addPortWithRespectToOppositeNode(initialSourceNode, initialSection);
901+
initialSourceNode.reAlignPortWithRespectToOppositeNode(intermediateNode, initialSection);
902+
903+
// Update new section to point from intermediate node to initial target node
904+
newSection.setSourceNode(intermediateNode);
905+
newSection.setTargetNode(initialTargetNode);
906+
intermediateNode.addPortWithRespectToOppositeNode(initialTargetNode, newSection);
907+
initialTargetNode.reAlignPortWithRespectToOppositeNode(intermediateNode, newSection);
908+
909+
// Add transitions and connections for new section
897910
this.nodeService.addTransitionToNodeForTrainrunSections(
898-
nodeIntermediate.getId(),
899-
trainrunSection1,
900-
trainrunSection2,
911+
intermediateNode.getId(),
912+
initialSection,
913+
newSection,
901914
);
902-
this.trainrunService.propagateConsecutiveTimesForTrainrun(trainrunSection1.getId());
915+
const initialSectionNewTargetTransition = initialTargetNode.getTransition(newSection.getId());
916+
if (initialSectionNewTargetTransition !== undefined) {
917+
initialSectionNewTargetTransition.setIsNonStopTransit(isInitialTargetNodeNonStop);
918+
}
903919

904-
const minHalteZeitFromNode = this.nodeService.getHaltezeit(
905-
nodeId,
906-
trainrunSection1.getTrainrun().getTrainrunCategory(),
920+
// Propagate times to ensure that the new section gets correct times based on the initial section
921+
this.trainrunService.propagateConsecutiveTimesForTrainrun(initialSection.getId());
922+
923+
// Calculate travel time using consecutive times in both directions
924+
let forwardTravelTime =
925+
initialSection.getTargetArrivalConsecutiveTime() -
926+
initialSection.getSourceDepartureConsecutiveTime();
927+
let backwardTravelTime =
928+
initialSection.getSourceArrivalConsecutiveTime() -
929+
initialSection.getTargetDepartureConsecutiveTime();
930+
forwardTravelTime = forwardTravelTime < 0 ? backwardTravelTime : forwardTravelTime;
931+
backwardTravelTime = backwardTravelTime < 0 ? forwardTravelTime : backwardTravelTime;
932+
const minimumCalculatedTravelTime = Math.min(forwardTravelTime, backwardTravelTime);
933+
const travelTimeIssue = !forwardTravelTime || !backwardTravelTime;
934+
935+
// Determine stop duration at intermediate node based on calculated travel time
936+
// and minimum haltezeit for the trainrun category at the intermediate node
937+
const minimumHalteZeitAtIntermediateNode = this.nodeService.getHaltezeit(
938+
intermediateNodeId,
939+
initialSection.getTrainrun().getTrainrunCategory(),
907940
);
908-
let travelTime1 =
909-
trainrunSection1.getTargetArrivalConsecutiveTime() -
910-
trainrunSection1.getSourceDepartureConsecutiveTime();
911-
let travelTime2 =
912-
trainrunSection1.getSourceArrivalConsecutiveTime() -
913-
trainrunSection1.getTargetDepartureConsecutiveTime();
914-
travelTime1 = travelTime1 < 0 ? travelTime2 : travelTime1;
915-
travelTime2 = travelTime2 < 0 ? travelTime1 : travelTime2;
916-
const calculatedTravelTime = Math.min(travelTime1, travelTime2);
917-
const halteZeit =
918-
stopDuration ?? Math.min(minHalteZeitFromNode, Math.max(0, calculatedTravelTime - 2));
919-
const travelTimeIssue = !travelTime1 || !travelTime2;
920-
const halteZeitIssue = minHalteZeitFromNode < halteZeit;
921-
const travelTime = Math.max(trainrunSection1.getTravelTime() - halteZeit, 0);
922-
const halfTravelTime = travelTime / 2;
923-
trainrunSection1.setTravelTime(travelTime - halfTravelTime);
924-
trainrunSection2.setTravelTime(halfTravelTime);
925-
926-
trainrunSection1.setTargetArrival(
941+
const stopDuration =
942+
initialStopDuration ??
943+
Math.min(minimumHalteZeitAtIntermediateNode, Math.max(0, minimumCalculatedTravelTime - 2));
944+
const halteZeitIssue = minimumHalteZeitAtIntermediateNode < stopDuration;
945+
946+
// Finally, set the times for both sections (order of setting times is important)
947+
const travelTime = Math.max(initialSection.getTravelTime() - stopDuration, 0);
948+
initialSection.setTravelTime(travelTime / 2);
949+
newSection.setTravelTime(travelTime / 2);
950+
initialSection.setTargetArrival(
927951
TrainrunSectionService.boundMinutesToOneHour(
928-
trainrunSection1.getSourceDeparture() + trainrunSection1.getTravelTime(),
952+
initialSection.getSourceDeparture() + initialSection.getTravelTime(),
929953
),
930954
);
931-
trainrunSection2.setSourceArrival(
955+
newSection.setSourceArrival(
932956
TrainrunSectionService.boundMinutesToOneHour(
933-
trainrunSection1.getTargetDeparture() + trainrunSection2.getTravelTime(),
957+
initialSection.getTargetDeparture() + newSection.getTravelTime(),
934958
),
935959
);
936-
trainrunSection1.setTargetDeparture(
937-
TrainrunSectionService.boundMinutesToOneHour(halteZeit + trainrunSection2.getSourceArrival()),
960+
initialSection.setTargetDeparture(
961+
TrainrunSectionService.boundMinutesToOneHour(stopDuration + newSection.getSourceArrival()),
938962
);
939-
trainrunSection2.setSourceDeparture(
940-
TrainrunSectionService.boundMinutesToOneHour(halteZeit + trainrunSection1.getTargetArrival()),
963+
newSection.setSourceDeparture(
964+
TrainrunSectionService.boundMinutesToOneHour(
965+
stopDuration + initialSection.getTargetArrival(),
966+
),
941967
);
942968

943-
if (
944-
halteZeitIssue ||
945-
trainrunSection1.getTravelTime() + trainrunSection2.getTravelTime() + halteZeit !==
946-
origTravelTime ||
947-
travelTimeIssue
948-
) {
969+
// Validate that the changes did not lead to inconsistencies in the times
970+
const finalTravelTimeIssue =
971+
initialSection.getTravelTime() + newSection.getTravelTime() + stopDuration !==
972+
initialTravelTime;
973+
if (travelTimeIssue || halteZeitIssue || finalTravelTimeIssue) {
949974
const title = $localize`:@@app.services.data.trainrunsection.intermediate-stop-replacement.title:Intermediate stop replacement`;
950975
const description = $localize`:@@app.services.data.trainrunsection.intermediate-stop-replacement.description:Intermediate stop replacement led to inconsistencies in the allocation of times!`;
951-
trainrunSection1.setTargetArrivalWarning(title, description);
952-
trainrunSection1.setTargetDepartureWarning(title, description);
953-
trainrunSection2.setSourceArrivalWarning(title, description);
954-
trainrunSection2.setSourceDepartureWarning(title, description);
976+
initialSection.setTargetArrivalWarning(title, description);
977+
initialSection.setTargetDepartureWarning(title, description);
978+
newSection.setSourceArrivalWarning(title, description);
979+
newSection.setSourceDepartureWarning(title, description);
955980
}
956981

957-
const transitionNew1 = node1.getTransition(trainrunSection1.getId());
958-
if (transitionNew1 !== undefined) {
959-
transitionNew1.setIsNonStopTransit(nonStop1);
960-
}
961-
const transitionNew2 = node2.getTransition(trainrunSection2.getId());
962-
if (transitionNew2 !== undefined) {
963-
transitionNew2.setIsNonStopTransit(nonStop2);
964-
}
965-
966-
this.trainrunService.propagateConsecutiveTimesForTrainrun(trainrunSection1.getId());
967-
968982
this.nodeService.transitionsUpdated();
969983
this.nodeService.connectionsUpdated();
970984
this.nodeService.nodesUpdated();
971985
this.trainrunSectionsUpdated();
972-
return {
973-
existingTrainrunSection: trainrunSection1,
974-
newTrainrunSection: trainrunSection2,
975-
};
986+
return newSection;
976987
}
977988

978989
addIntermediateStopOnTrainrunSection(trainrunSection: TrainrunSection) {

0 commit comments

Comments
 (0)