#!/usr/bin/env perl
use strict;
use warnings;
use 5.020;
use utf8;

our $VERSION = '0.18';

use Getopt::Long;
use List::Util qw(min);
use Travel::Status::DE::IRIS;
use Travel::Status::DE::DBWagenreihung;

my $developer_mode = 0;

binmode( STDOUT, ':encoding(utf-8)' );

sub show_help {
	my ($code) = @_;

	say "Usage: db-wagenreihung <station> <train number>";

	exit $code;
}

sub show_version {
	say "db-wagenreihung version ${VERSION}";

	exit 0;
}

GetOptions(
	'h|help'  => sub { show_help(0) },
	'devmode' => \$developer_mode,
	'version' => sub { show_version() },
) or show_help(1);

if ( @ARGV != 2 ) {
	show_help(1);
}

my ( $station, $train_number ) = @ARGV;

my $col_first  = "\e[38;5;11m";
my $col_mixed  = "\e[38;5;208m";
my $col_second = "\e[0m";          #"\e[38;5;9m";
my $col_reset  = "\e[0m";

my $res = Travel::Status::DE::IRIS->new(
	developer_mode => $developer_mode,
	station        => $station,
	with_related   => 1
);

if ( $res->errstr ) {
	say STDERR $res->errstr;
	exit 1;
}

my @trains = grep { $_->train_no eq $train_number } $res->results;

if ( @trains != 1 ) {
	say STDERR "Unable to find train in reported departures";
	exit 1;
}

my $wr = Travel::Status::DE::DBWagenreihung->new(
	developer_mode => $developer_mode,
	departure      => $trains[0]->sched_departure || $trains[0]->sched_arrival,
	eva            => $trains[0]->station_eva,
	train_type     => $trains[0]->type,
	train_number   => $train_number,
);

if ( $wr->errstr ) {
	say STDERR $wr->errstr;
	exit 2;
}

printf(
	"%s → %s\n",
	join(
		' / ', map { $wr->train_type . ' ' . $_->{name} } $wr->train_numbers
	),
	join(
		' / ',
		map {
			sprintf( '%s (%s)', $_->{name}, join( q{}, @{ $_->{sectors} } ) )
		} $wr->destinations
	),
);

printf( "Gleis %s\n\n", $wr->platform );

for my $sector ( $wr->sectors ) {
	my $sector_length = $sector->length_percent;
	my $spacing_left  = int( ( $sector_length - 2 ) / 2 ) - 1;
	my $spacing_right = int( ( $sector_length - 2 ) / 2 );

	if ( $sector_length % 2 ) {
		$spacing_left++;
	}

	printf( "▏%s%s%s▕",
		( $spacing_left >= 0 )                 ? ' ' x $spacing_left  : q{},
		$sector->name, ( $spacing_right >= 0 ) ? ' ' x $spacing_right : q{} );
}
print "\n";

my @start_percentages = map { $_->start_percent } $wr->carriages;
if ( my $min_percentage = min @start_percentages ) {
	print ' ' x ( $min_percentage - 1 );
}
print $wr->direction == 100 ? '>' : '<';

for my $wagon ( $wr->carriages ) {
	my $wagon_length  = $wagon->length_percent;
	my $spacing_left  = int( $wagon_length / 2 ) - 2;
	my $spacing_right = int( $wagon_length / 2 ) - 1;

	if ( $wagon_length % 2 ) {
		$spacing_left++;
	}

	my $wagon_desc = $wagon->number || '?';

	if ( $wagon->is_closed ) {
		$wagon_desc = 'X';
	}

	if ( $wagon->is_locomotive or $wagon->is_powercar ) {
		$wagon_desc = ' ■ ';
	}

	my $class_color = '';
	if ( $wagon->class_type == 1 ) {
		$class_color = $col_first;
	}
	elsif ( $wagon->class_type == 2 ) {
		$class_color = $col_second;
	}
	elsif ( $wagon->class_type == 12 ) {
		$class_color = $col_mixed;
	}

	printf( "%s%s%3s%s%s",
		' ' x $spacing_left, $class_color, $wagon_desc,
		$col_reset,          ' ' x $spacing_right );
}
print $wr->direction == 100 ? '>' : '<';
print "\n\n";

for my $group ( $wr->groups ) {
	printf( "%s%s%s\n",
		$group->description || 'Zug',
		$group->designation ? ' „' . $group->designation . '“'          : q{},
		$group->has_sectors ? ' (' . join( q{}, $group->sectors ) . ')' : q{} );
	printf( "%s %s  → %s\n\n",
		$group->train_type, $group->train_no, $group->destination );

	for my $wagon ( $group->carriages ) {
		printf(
			"%3s: %3s %10s  %s\n",
			$wagon->is_closed       ? 'X'
			: $wagon->is_locomotive ? 'Lok'
			: $wagon->number || '?',
			$wagon->model || '???',
			$wagon->type,
			join( q{  }, $wagon->attributes )
		);
	}
	say "";
}

__END__

=head1 NAME

db-wagenreihung - Interface to Deutsche Bahn carriage formation API

=head1 SYNOPSIS

B<db-wagenreihung> I<station> I<train-number>

=head1 VERSION

version 0.18

This is beta software: API and output format may change without notice.

=head1 DESCRIPTION

db-wagenreihung shows the carriage formation (also known as coach sequence) of
train I<train-number> at station I<station> (must be a name or DS100 code) as
reported by the Deutsche Bahn Wagenreihung API. As of April 2024, it has mature
support for long-distance (IC/EC/ICE) trains and a growing number of regional
transport providers that also offer mostly correct carriage formation data.

It is not possible to request the carriage formation at a train's terminus
station.  This is a known limitation.

The departure of I<train-number> must be in the time range between now and
two hours in the future.

=head1 EXAMPLES

=over

=item db-wagenreihung 'Essen Hbf' 723

Show carriage formation of ICE 723 at Essen Hbf

=item db-wagenreihung TS 3259

Show carriage formation of IRE 3259 at Stuttgart Hbf

=back

=head1 DEPENDENCIES

=over

=item * JSON(3pm)

=item * LWP::UserAgent(3pm)

=item * Travel::Status::DE::IRIS(3pm)

=back

=head1 AUTHOR

Copyright (C) 2018-2024 by Birte Kristina Friesel E<lt>derf@finalrewind.orgE<gt>

=head1 LICENSE

This program is licensed under the same terms as Perl itself.
