summaryrefslogtreecommitdiff
path: root/lib/Travelynx/Controller/Traveling.pm
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2022-07-30 10:27:57 +0200
committerDaniel Friesel <derf@finalrewind.org>2022-07-30 10:27:57 +0200
commit83954508f03f4a71b8669a4389a144dd68189367 (patch)
treef87116a702fa875a0efbd97df2d9633b435f7083 /lib/Travelynx/Controller/Traveling.pm
parent17126940115455296706b99655a052ffb60bd763 (diff)
move get_connecting_trains helper to Traveling controller
Diffstat (limited to 'lib/Travelynx/Controller/Traveling.pm')
-rwxr-xr-xlib/Travelynx/Controller/Traveling.pm166
1 files changed, 166 insertions, 0 deletions
diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm
index 0493d25..132b439 100755
--- a/lib/Travelynx/Controller/Traveling.pm
+++ b/lib/Travelynx/Controller/Traveling.pm
@@ -1476,4 +1476,170 @@ sub add_journey_form {
}
}
+sub get_connecting_trains {
+ my ( $self, %opt ) = @_;
+
+ my $uid = $opt{uid} //= $self->current_user->{id};
+ my $use_history = $self->users->use_history( uid => $uid );
+
+ my ( $eva, $exclude_via, $exclude_train_id, $exclude_before );
+ my $now = $self->now->epoch;
+ my ( $stationinfo, $arr_epoch, $arr_platform );
+
+ if ( $opt{eva} ) {
+ if ( $use_history & 0x01 ) {
+ $eva = $opt{eva};
+ }
+ elsif ( $opt{destination_name} ) {
+ $eva = $opt{eva};
+ }
+ }
+ else {
+ if ( $use_history & 0x02 ) {
+ my $status = $self->get_user_status;
+ $eva = $status->{arr_eva};
+ $exclude_via = $status->{dep_name};
+ $exclude_train_id = $status->{train_id};
+ $arr_platform = $status->{arr_platform};
+ $stationinfo = $status->{extra_data}{stationinfo_arr};
+ if ( $status->{real_arrival} ) {
+ $exclude_before = $arr_epoch = $status->{real_arrival}->epoch;
+ }
+ }
+ }
+
+ $exclude_before //= $now - 300;
+
+ if ( not $eva ) {
+ return;
+ }
+
+ my @destinations = $self->journeys->get_connection_targets(%opt);
+
+ if ($exclude_via) {
+ @destinations = grep { $_ ne $exclude_via } @destinations;
+ }
+
+ if ( not @destinations ) {
+ return;
+ }
+
+ my $stationboard = $self->iris->get_departures(
+ station => $eva,
+ lookbehind => 10,
+ lookahead => 40,
+ with_related => 1
+ );
+ if ( $stationboard->{errstr} ) {
+ return;
+ }
+ @{ $stationboard->{results} } = map { $_->[0] }
+ sort { $a->[1] <=> $b->[1] }
+ map { [ $_, $_->departure ? $_->departure->epoch : 0 ] }
+ @{ $stationboard->{results} };
+ my @results;
+ my @cancellations;
+ my %via_count = map { $_ => 0 } @destinations;
+ for my $train ( @{ $stationboard->{results} } ) {
+ if ( not $train->departure ) {
+ next;
+ }
+ if ( $exclude_before
+ and $train->departure
+ and $train->departure->epoch < $exclude_before )
+ {
+ next;
+ }
+ if ( $exclude_train_id
+ and $train->train_id eq $exclude_train_id )
+ {
+ next;
+ }
+
+ # In general, this function is meant to return feasible
+ # connections. However, cancelled connections may also be of
+ # interest and are also useful for logging cancellations.
+ # To satisfy both demands with (hopefully) little confusion and
+ # UI clutter, this function returns two concatenated arrays:
+ # actual connections (ordered by actual departure time) followed
+ # by cancelled connections (ordered by scheduled departure time).
+ # This is easiest to achieve in two separate loops.
+ #
+ # Note that a cancelled train may still have a matching destination
+ # in its route_post, e.g. if it leaves out $eva due to
+ # unscheduled route changes but continues on schedule afterwards
+ # -- so it is only cancelled at $eva, not on the remainder of
+ # the route. Also note that this specific case is not yet handled
+ # properly by the cancellation logic etc.
+
+ if ( $train->departure_is_cancelled ) {
+ my @via = ( $train->sched_route_post, $train->sched_route_end );
+ for my $dest (@destinations) {
+ if ( List::Util::any { $_ eq $dest } @via ) {
+ push( @cancellations, [ $train, $dest ] );
+ next;
+ }
+ }
+ }
+ else {
+ my @via = ( $train->route_post, $train->route_end );
+ for my $dest (@destinations) {
+ if ( $via_count{$dest} < 2
+ and List::Util::any { $_ eq $dest } @via )
+ {
+ push( @results, [ $train, $dest ] );
+
+ # Show all past and up to two future departures per destination
+ if ( not $train->departure
+ or $train->departure->epoch >= $now )
+ {
+ $via_count{$dest}++;
+ }
+ next;
+ }
+ }
+ }
+ }
+
+ @results = map { $_->[0] }
+ sort { $a->[1] <=> $b->[1] }
+ map {
+ [ $_, $_->[0]->departure->epoch // $_->[0]->sched_departure->epoch ]
+ } @results;
+ @cancellations = map { $_->[0] }
+ sort { $a->[1] <=> $b->[1] }
+ map { [ $_, $_->[0]->sched_departure->epoch ] } @cancellations;
+
+ for my $result (@results) {
+ my $train = $result->[0];
+ my @message_ids = List::Util::uniq map { $_->[1] } $train->raw_messages;
+ $train->{message_id} = { map { $_ => 1 } @message_ids };
+ my $interchange_duration;
+ if ( exists $stationinfo->{i} ) {
+ $interchange_duration
+ = $stationinfo->{i}{$arr_platform}{ $train->platform };
+ $interchange_duration //= $stationinfo->{i}{"*"};
+ }
+ if ( defined $interchange_duration ) {
+ my $interchange_time
+ = ( $train->departure->epoch - $arr_epoch ) / 60;
+ if ( $interchange_time < $interchange_duration ) {
+ $train->{interchange_text} = 'Anschluss knapp';
+ $train->{interchange_icon} = 'warning';
+ }
+ elsif ( $interchange_time == $interchange_duration ) {
+ $train->{interchange_text} = 'Anschluss könnte knapp werden';
+ $train->{interchange_icon} = 'directions_run';
+ }
+
+ #else {
+ # $train->{interchange_text} = 'Anschluss wird voraussichtlich erreicht';
+ # $train->{interchange_icon} = 'check';
+ #}
+ }
+ }
+
+ return ( @results, @cancellations );
+}
+
1;