package DBInfoscreen::Controller::Wagenreihung;

# Copyright (C) 2011-2020 Birte Kristina Friesel
#
# SPDX-License-Identifier: AGPL-3.0-or-later

use Mojo::Base 'Mojolicious::Controller';
use Mojo::JSON qw(decode_json encode_json);
use Mojo::Util qw(b64_encode b64_decode);

use utf8;

use Travel::Status::DE::DBWagenreihung;
use Travel::Status::DE::DBWagenreihung::Wagon;

sub handle_wagenreihung_error {
	my ( $self, $train_no, $err ) = @_;

	$self->render(
		'wagenreihung',
		title     => "Zug $train_no",
		wr_error  => $err,
		train_no  => $train_no,
		wr        => undef,
		wref      => undef,
		hide_opts => 1,
	);
}

sub wagenreihung {
	my ($self)    = @_;
	my $train     = $self->stash('train');
	my $departure = $self->stash('departure');
	my $exit_side = $self->param('e');

	$self->render_later;

	$self->wagonorder->get_p( $train, $departure )->then(
		sub {
			my ($json) = @_;
			my $wr;
			eval {
				$wr
				  = Travel::Status::DE::DBWagenreihung->new(
					from_json => $json );
			};
			if ($@) {
				$self->handle_wagenreihung_error( $train, scalar $@ );
				return;
			}

			if ( $exit_side and $exit_side =~ m{^a} ) {
				if ( $wr->sections and defined $wr->direction ) {
					my $section_0 = ( $wr->sections )[0];
					my $direction = $wr->direction;
					if ( $section_0->name eq 'A' and $direction == 0 ) {
						$exit_side =~ s{^a}{};
					}
					elsif ( $section_0->name ne 'A' and $direction == 100 ) {
						$exit_side =~ s{^a}{};
					}
					else {
						$exit_side = ( $exit_side eq 'ar' ) ? 'l' : 'r';
					}
				}
				else {
					$exit_side = undef;
				}
			}

			my $wref = {
				e  => $exit_side ? substr( $exit_side, 0, 1 ) : '',
				tt => $wr->train_type,
				tn => $train,
				s  => $wr->station->{name},
				p  => $wr->platform
			};

			if ( $wr->has_bad_wagons ) {

				# create fake positions as the correct ones are not available
				my $pos = 0;
				for my $wagon ( $wr->wagons ) {
					$wagon->{position}{start_percent} = $pos;
					$wagon->{position}{end_percent}   = $pos + 4;
					$pos += 4;
				}
			}
			elsif ( defined $wr->direction and scalar $wr->wagons > 2 ) {

				# wagenlexikon images only know one orientation. They assume
				# that the second class (i.e., the wagon with the lowest
				# wagon number) is in the leftmost carriage(s). We define the
				# wagon with the lowest start_percent value to be leftmost
				# and invert the direction passed on to $wref if it is not
				# the wagon with the lowest wagon number.

				# Note that we need to check both the first two and the last two
				# wagons as the train may consist of several wings. If their
				# order differs, we do not show a direction, as we do not
				# handle that case yet.

				my @wagons = $wr->wagons;

				# skip first/last wagon as it may be a locomotive
				my $wna1 = $wagons[1]->number;
				my $wna2 = $wagons[2]->number;
				my $wnb1 = $wagons[-3]->number;
				my $wnb2 = $wagons[-2]->number;
				my $wpa1 = $wagons[1]{position}{start_percent};
				my $wpa2 = $wagons[2]{position}{start_percent};
				my $wpb1 = $wagons[-3]{position}{start_percent};
				my $wpb2 = $wagons[-2]{position}{start_percent};

				if (    $wna1 =~ m{^\d+$}
					and $wna2 =~ m{^\d+$}
					and $wnb1 =~ m{^\d+$}
					and $wnb2 =~ m{^\d+$} )
				{

					# We need to perform normalization in two cases:
					# * wagon 1 is leftmost and its number is higher than wagon 2
					# * wagon 1 is rightmost and its number is lower than wagon 2
					#   (-> the leftmost wagon has the highest number)

					# However, if wpa/wna und wpb/wnb do not match, we have a
					# winged train with different normalization requirements
					# in its wings. We do not handle that case yet.
					if ( ( $wna1 <=> $wna2 ) != ( $wnb1 <=> $wnb2 ) ) {

						# unhandled. Do not set $wref->{d}.
					}
					elsif (( $wpa1 < $wpa2 and $wna1 > $wna2 )
						or ( $wpa1 > $wpa2 and $wna1 < $wna2 ) )
					{
						# perform normalization
						$wref->{d} = 100 - $wr->direction;
					}
					else {
						# no normalization required
						$wref->{d} = $wr->direction;
					}
				}
			}

			my $exit_dir = 'unknown';
			if ( defined $wr->direction and $exit_side ) {
				if ( $wr->direction == 0 and $exit_side eq 'l' ) {
					$exit_dir = 'left';
				}
				elsif ( $wr->direction == 0 and $exit_side eq 'r' ) {
					$exit_dir = 'right';
				}
				elsif ( $wr->direction == 100 and $exit_side eq 'l' ) {
					$exit_dir = 'right';
				}
				elsif ( $wr->direction == 100 and $exit_side eq 'r' ) {
					$exit_dir = 'left';
				}
			}

			$wref = b64_encode( encode_json($wref) );

			my $title = join( ' / ',
				map { $wr->train_type . ' ' . $_ } $wr->train_numbers );

			$self->render(
				'wagenreihung',
				description => sprintf(
					'Ist-Wagenreihung %s in %s',
					$title, $wr->station->{name}
				),
				wr_error  => undef,
				title     => $title,
				train_no  => $train,
				wr        => $wr,
				wref      => $wref,
				exit_dir  => $exit_dir,
				hide_opts => 1,
			);
		}
	)->catch(
		sub {
			my ($err) = @_;

			$self->handle_wagenreihung_error( $train,
				$err->{error}->{msg} // $err // "Unbekannter Fehler" );
			return;
		}
	)->wait;

}

sub wagen {
	my ($self)   = @_;
	my $wagon_id = $self->stash('wagon');
	my $wagon_no = $self->param('n');
	my $section  = $self->param('s');
	my $wref     = $self->param('r');

	if ( not $self->app->dbdb_wagon->{$wagon_id} ) {
		$self->render(
			'not_found',
			message   => "Keine Daten zu Wagentyp \"${wagon_id}\" vorhanden",
			hide_opts => 1
		);
		return;
	}

	eval { $wref = decode_json( b64_decode($wref) ); };
	if ($@) {
		$wref = {};
	}

	$wref->{wn} = $wagon_no;
	$wref->{ws} = $section;

	my @wagon_files
	  = ("https://lib.finalrewind.org/dbdb/db_wagen/${wagon_id}.png");

	if ( $self->app->dbdb_wagon->{"${wagon_id}_u"} ) {
		@wagon_files = (
			"https://lib.finalrewind.org/dbdb/db_wagen/${wagon_id}_u.png",
			"https://lib.finalrewind.org/dbdb/db_wagen/${wagon_id}_l.png"
		);
	}

	my $title = 'Wagen ' . $wagon_id;

	if ( $wref->{tt} and $wref->{tn} ) {
		$title = sprintf( '%s %s', $wref->{tt}, $wref->{tn} );
		if ($wagon_no) {
			$title .= ' Wagen ' . $wagon_no;
		}
		else {
			$title .= ' Wagen ' . $wagon_id;
		}
	}

	if ( defined $wref->{d} and $wref->{e} ) {
		if ( $wref->{d} == 0 and $wref->{e} eq 'l' ) {
			$wref->{e} = 'd';
		}
		elsif ( $wref->{d} == 0 and $wref->{e} eq 'r' ) {
			$wref->{e} = 'u';
		}
		elsif ( $wref->{d} == 100 and $wref->{e} eq 'l' ) {
			$wref->{e} = 'u';
		}
		elsif ( $wref->{d} == 100 and $wref->{e} eq 'r' ) {
			$wref->{e} = 'd';
		}
	}
	else {
		$wref->{e} = '';
	}

	$self->render(
		'wagen',
		description => ( $wref->{s} ? 'Position von ' : q{} )
		  . $title
		  . ( $wref->{s} ? " in $wref->{s}" : q{} ),
		title       => $title,
		wagon_files => [@wagon_files],
		wagon_data  => $self->app->dbdb_wagon->{$wagon_id},
		wref        => $wref,
		hide_opts   => 1,
	);
}

1;