#!/usr/bin/env perl
## Copyright © 2009 by Daniel Friesel <derf@derf.homelinux.org>
## License: WTFPL <http://sam.zoy.org/wtfpl>
use strict;
use warnings;
use 5.010;
use encoding 'utf8';
use Getopt::Long;
use WWW::Mechanize;

my $firsturl = 'http://efa.vrr.de/vrr/XSLT_TRIP_REQUEST2?language=de&itdLPxx_transpCompany=vrr';
my $posturl = 'http://efa.vrr.de/vrr/XSLT_TRIP_REQUEST2';

my $content;
my %post;
my $www = WWW::Mechanize->new(
	autocheck => 1,
);
my $offer = 0;
my $i = 0;
my $raw;
my $cons;
my $groupsize = 8;
my $offset;
my (@from, @to, @via);
my ($time, $time_depart, $time_arrive);
my $date;
my $restrict;
my $debug = 0;

$post{type_origin} = 'stop';
$post{type_destination} = 'stop';

GetOptions(
	'from=s{2}' => \@from,
	'to=s{2}'   => \@to,
	'via=s{2}'  => \@via,
	'time=s'    => \$time,
	'depart=s'  => \$time_depart,
	'arrive=s'  => \$time_arrive,
	'date=s'    => \$date,
	'debug'     => \$debug,
	'post=s'    => \%post,
	'restrict=s' => \$restrict,
);

unless (@to == 2 and @from == 2) {
	print STDERR "Usage: efa --from <city> <stop> --to <city> <stop> [other options]\n";
	exit(1);
}

@post{'place_origin','name_origin'} = @from;
@post{'place_destination','name_destination'} = @to;
if (@via == 2) {
	@post{'place_via','name_via'} = @via;
}

if ($time_arrive) {
	$time = $time_arrive;
	$post{itdTripDateTimeDepArr} = 'arr';
} elsif ($time_depart) {
	$time = $time_depart;
	$post{itdTripDateTimeDepArr} = 'dep';
}

if ($time) {
	@post{'itdTimeHour','itdTimeMinute'} = split(/:/, $time);
}
if ($date) {
	@post{'itdDateDay','itdDateMonth','itdDateYear'} = split(/\./, $date);
}

if ($restrict) {
	given ($restrict) {
		when('local') { $post{lineRestriction} = 403 }
		when('ic')    { $post{lineRestriction} = 401 }
		when('ice')   { $post{lineRestriction} = 400 }
		when(/\d+/)   { $post{lineRestriction} = $restrict }
		default {
			print STDERR "--restrict usage: local / ic / ice\n";
		}
	}
}

$www->get($firsturl);
$www->submit_form(
	form_name => 'jp',
	fields => \%post,
);

$content = $www->content;

foreach(split(/<span class="labelTextBold"> \d+\. Fahrt<\/span>/, $content)) {
	unless ($offer) {
		$offer++;
		next;
	}
	foreach(split(/\n/)) {
		if (/<span class="labelText">(?<content>[^<]+)<\/span>/) {
			push(@{$raw->[$offer-1]}, $+{content});
		}
	}
	$offer++;
}

if ($debug) {
	print STDERR "custom post values used in query:\n";
	foreach(keys(%post)) {
		print STDERR "    $_ => $post{$_}\n";
	}
	print STDERR "\nraw response:\n";
	foreach(@$raw) {
		print STDERR "---\n";
		foreach(@$_) {
			print STDERR "$_\n";
		}
	}
}

for ($offer = 0; exists($raw->[$offer]); $offer++) {
	for ($i = 0; @{$raw->[$offer]} >= (($i+1) * $groupsize); $i++) {
		$offset = $i * $groupsize;
		# If the first field is not a time we've got some additional information.
		# Sadly, this script does not parse it yet, so it's ignored
		until ($raw->[$offer]->[$offset] =~ /^\d+:\d+$/) {
			last unless exists($raw->[$offer]->[++$offset]);
		}
		$cons->[$offer]->[$i] = {
			deptime  => $raw->[$offer]->[$offset],
			dep      => $raw->[$offer]->[$offset+1],
			depstop  => $raw->[$offer]->[$offset+2],
			deptrain => $raw->[$offer]->[$offset+3],
			depdest  => $raw->[$offer]->[$offset+7],
			arrtime  => $raw->[$offer]->[$offset+4],
			arr      => $raw->[$offer]->[$offset+5],
			arrstop  => $raw->[$offer]->[$offset+6],
		};
	}
}

foreach (@$cons) {
	foreach (@$_) {
		printf(
			"%-5s %-2s %-30s %-20s %s\n%-5s %-2s %-30s\n\n",
			$_->{deptime}, $_->{dep}, $_->{depstop}, $_->{deptrain},
			$_->{depdest}, $_->{arrtime}, $_->{arr}, $_->{arrstop}
		);
	}
	print "------\n\n";
}

__END__

=head1 NAME

efa - unofficial efa.vrr.de command line client

=head1 SYNOPSIS

B<efa> B<--from> I<city> I<stop> B<--to> I<city> I<stop> [ I<additional options> ]

=head1 DESCRIPTION

B<efa> is a command line client for the L<http://efa.vrr.de> web interface.
It sends the specified information to the online form and displays the results

=head1 OPTIONS

=over

=item B<--from> I<city> I<stop> (mandatory)

Departure place

=item B<--to> I<city> I<stop> (mandatory)

Arrival place

=item B<--via> I<city> I<stop>

Travel via this place

=item B<--debug>

Display debug information (additional post requests sent to the site,
raw items received from the site)

=item B<--time>|B<--depart> I<hh>:I<mm>

Journey start time

=item B<--arrive> I<hh>:I<mm>

Journey end time (overrides --time/--depart)

=item B<--date> I<dd>.I<mm>.I<yyyy>

Journey date

=item B<--restrict> I<type>

Only accept connections using trains of type I<type>, where I<type> may be:

=over

=item * local

only take local trains ("Verbund-/Nahverkehrslinien"). Slow, but the cheapest
method if you're not travelling long distance

=item * ic

All trains exctep ICE

=item * ICE

All trains

=back

=item B<--post> I<key>=I<value>

Add I<key> with I<value> to the HTTP POST request sent to the EFA server.
This can be used to use setting B<efa> does not yet cover, like
C<--post lineRestriction=400> to also show IC and ICE trains.
Note that B<--post> will be overridden by the standard efa options, such as
B<--time>.

=back
