001package jmri.jmrit.etcs; 002 003import java.util.*; 004 005import javax.annotation.Nonnull; 006 007import org.apiguardian.api.API; 008 009/** 010 * Class to represent a Movement Authority which is passed to the DMI 011 * to authorise a route. 012 * @author Steve Young Copyright (C) 2024 013 */ 014@API(status=API.Status.EXPERIMENTAL) 015public class MovementAuthority { 016 017 private final List<TrackSection> list; 018 019 /** 020 * Create a new MovementAuthority from a List of TrackSections. 021 * @param sectionList the list of TrackSections. 022 */ 023 public MovementAuthority(List<TrackSection> sectionList){ 024 list = sectionList; 025 } 026 027 /** 028 * Get the list of TrackSections. 029 * @return Unmodifiable list of TrackSections. 030 */ 031 public List<TrackSection> getTrackSections() { 032 return Collections.unmodifiableList(list); 033 } 034 035 /** 036 * Remove a TrackSection from the Movement Authority. 037 * @param ts the TrackSection to remove. 038 */ 039 private void removeTrackSection(TrackSection ts){ 040 list.remove(ts); 041 } 042 043 /** 044 * Aggregates a list of DmiMovementAuthorities into a list of 045 * DmiTrackSections, based on either speed changes or gradient changes. 046 * 047 * @param completeList The list of MovementAuthority objects to process. 048 * @param isSpeed True to aggregate based on speed changes, 049 * False to aggregate based on gradient changes. 050 * @return A list of aggregated DmiTrackSection77 objects. 051 */ 052 @Nonnull 053 public static List<TrackSection> getTrackSectionList( 054 @Nonnull List<MovementAuthority> completeList, boolean isSpeed) { 055 056 List<TrackSection> trackSectionList = new ArrayList<>(); 057 TrackSection lastTs = null; 058 List<TrackSection> tempTrackList; 059 for (MovementAuthority ma : completeList) { 060 tempTrackList = ma.getTrackSections(); 061 for (TrackSection ts : tempTrackList) { 062 if (lastTs == null || checkAddToList(lastTs, ts, isSpeed)) { 063 trackSectionList.add(new TrackSection(ts.getLength(), ts.getSpeed(), ts.getGradient())); 064 lastTs = trackSectionList.get(trackSectionList.size() - 1); 065 } else { 066 lastTs.setLength(ts.getLength() + lastTs.getLength()); 067 } 068 } 069 } 070 return trackSectionList; 071 } 072 073 private static boolean checkAddToList( 074 @Nonnull TrackSection lastTs, @Nonnull TrackSection ts, boolean isSpeed ) { 075 if (isSpeed) { 076 return lastTs.getSpeed() != ts.getSpeed(); 077 } else { 078 return lastTs.getGradient() != ts.getGradient(); 079 } 080 } 081 082 /** 083 * Advance forward a List of Movement Authorities. 084 * The length of the nearest TrackSection(s) are reduced by the distance. 085 * Unused Track Sections are removed from the List. 086 * Track Section announcements are also advanced. 087 * @param list the list to advance. 088 * @param distance the distance to advance. 089 * @return the modified List of Movement Authorities. 090 */ 091 @Nonnull 092 public static List<MovementAuthority> advanceForward( 093 @Nonnull List<MovementAuthority> list, int distance) { 094 095 if (list.isEmpty()){ 096 return list; 097 } 098 099 MovementAuthority ma = list.get(0); 100 if (ma.getTrackSections().isEmpty()) { 101 list.remove(ma); 102 return advanceForward(list, distance); 103 } 104 TrackSection ts = ma.getTrackSections().get(0); 105 106 int newLength = ts.getLength() - distance; 107 if ( newLength < 0 ) { 108 ma.removeTrackSection(ts); 109 return advanceForward(list, distance-ts.getLength()); 110 } 111 ts.setLength(newLength); 112 ts.advanceAnnouncements(distance); 113 return list; 114 } 115 116}