diff options
Diffstat (limited to 'lib/Travelynx/Controller')
-rwxr-xr-x | lib/Travelynx/Controller/Traveling.pm | 166 |
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; |