#! /usr/local/bin/perl
#!/usr/bin/perl
# -*- perl -*-

#
# Author: Slaven Rezic
#
# Copyright (C) 2001,2013 Slaven Rezic. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#
# Mail: slaven@rezic.de
# WWW:  http://bbbike.sourceforge.net
#

package BBBikeRouting::Cmdline;
use FindBin;
use lib ($FindBin::RealBin, "$FindBin::RealBin/lib");
use BBBikeRouting;
use strict;

sub parse_options {
    my %o = (vehicle => "bike");
    if (eval { require Getopt::Long; 1 }) {
	if (!Getopt::Long::GetOptions
	    (\%o,
	     "vehicle=s",
	     "algorithm=s",
	     "xs!",
	     "cache!",
	     "scope=s",
	     "v",
	     "dumproute",
	     "dumppath",
	     "dumpbbd",
	     "yaml",
	    )) {
	    die <<EOF;
Usage: $0 [-vehicle vehicle] [-[no]cache] [-[no]xs]
        [-algorithm ...] [-scope ...] [-v]
	[-dumproute | -dumppath | -dumpbbd] [-yaml] start goal

start and goal may be prefixed with \"city:\" to force cities instead of
streets. start and goal may also be "standard" coordinates instead.
EOF
	}
    } else {
	warn "No Getopt::Long installed...\n";
    }
    \%o;
}

sub new {
    my($class, $routing) = @_;
    bless { R => $routing }, $class;
}

sub cmdline_input {
    my($self, $o) = @_;

    my $r = $self->{R};
    my %o = $o ? %$o : ();

    if (defined $o{vehicle}) { $r->Context->Vehicle($o{vehicle}) }
    if (defined $o{algorithm}) { $r->Context->Algorithm($o{algorithm}) }
    if (        $o{xs}) { $r->Context->UseXS($o{xs}) }
    if (        $o{cache}) { $r->Context->UseCache($o{cache}) }
    if (defined $o{scope}) { $r->Context->Scope($o{scope}) }
    if (	$o{v}) {
	require Strassen;
	Strassen::set_verbose(1);
	$r->Context->Verbose(1);
    }
    if (        $o{dumproute}) { $self->{DumpRoute} = 1 }
    if (        $o{dumppath}) { $self->{DumpPath} = 1 }
    if (        $o{dumpbbd}) { $self->{DumpBBD} = 1 }
    if (        $o{yaml}) { $self->{YAML} = 1 }
    
    if (@ARGV < 2) {
	print "Zu wenige Argumente: mindestens Start- und Zielstraße angeben!\n";
	exit 1;
    }
    if (@ARGV == 2) {
	$self->set_city_or_street($r->Start, $ARGV[0]);
	$self->set_city_or_street($r->Goal,  $ARGV[1]);
    } elsif (@ARGV == 4) {
	$r->Start->Street  ($ARGV[0]);
	$r->Start->Citypart($ARGV[1]);
	$r->Goal->Street   ($ARGV[2]);
	$r->Goal->Citypart ($ARGV[3]);
    } elsif (@ARGV == 3) {
	$self->set_city_or_street($r->Start, shift @ARGV);
	if ($ARGV[0] =~ /^\d+$/) {
	    $r->Start->Citypart(shift @ARGV);
	} elsif ($ARGV[1] =~ /^\d+$/) {
	    $r->Goal->Citypart(pop @ARGV);
	}
	if (@ARGV == 1) {
	    $self->set_city_or_street($r->Goal, shift @ARGV);
	} else {
	    require Geography;
	    my $geo = Geography->new('Berlin', 'DE');
	    $ENV{LANG} = "de";
	    my(@cityparts) = keys %{ $geo->subcitypart_to_citypart };
	    foreach (@cityparts) {
		if ($_ =~ /^\Q$ARGV[0]\E/i) {
		    $r->Start->Citypart ($ARGV[0]);
		    $self->set_city_or_street($r->Goal, $ARGV[1]);
		    last;
		} elsif ($_ =~ /^\Q$ARGV[1]\E/i) {
		    $self->set_city_or_street($r->Goal, $ARGV[0]);
		    $r->Goal->Citypart($ARGV[1]);
		    last;
		}
	    }
	    if (!$r->Goal->Street && !$r->Goal->City) {
		$self->set_city_or_street($r->Goal, $ARGV[0]);
		$r->Goal->Citypart($ARGV[1]);
	    }
	}
    }
}

sub search {
    my $self = shift;
    my $r = $self->{R};
    $r->search;
}

sub cmdline_output {
    my $self = shift;
    my $r = $self->{R};

    if ($self->{DumpBBD}) {
	print $r->path_to_bbd;
	return;
    }

    print $r->Start->Street;
#XXX
#      if ($multi_from) {
#  	print " ($from_citypart)";
#      }
    print " - ";
    print $r->Goal->Street;
#      if ($multi_to) {
#  	print " ($to_citypart)";
#      }
    print "\n";

    if ($self->{DumpRoute}) {
	$self->_dump_anything($r->RouteInfo);
    } elsif ($self->{DumpPath}) {
	$self->_dump_anything($r->Path);
    } else {
	print
	    join("\n", map { sprintf("%-40s %s", $_->{Street}, $_->{Whole}) }
		 @{ $r->RouteInfo} ), "\n";
    }
}

# As DD or YAML
sub _dump_anything {
    my($self, $data) = @_;
    if ($self->{YAML}) {
	require YAML::Syck;
	print YAML::Syck::Dump($data);
    } else {
	require Data::Dumper;
	print Data::Dumper->new([$data],[])->Indent(1)->Useqq(1)->Dump;
    }
}

sub set_city_or_street {
    my($self, $o, $s) = @_;
    my $r = $self->{R};

    if ($s =~ /^(?:city|ort):(.*)$/) {
	$o->City($1);
	$o->Street(undef);
    } elsif ($s =~ /^-?\d+,-?\d+$/) {
	$o->Coord($s);
	require Karte;
	Karte::preload(qw(Standard Polar));
	$Karte::Polar::obj = $Karte::Polar::obj; # -w
	my($long,$lat) = map { [ Karte::Polar::ddd2dms($_) ] } $Karte::Polar::obj->standard2map(split /,/, $s);
	$o->Street(Karte::Polar::dms_human_readable("lat", @$lat) . ", " .
		   Karte::Polar::dms_human_readable("long", @$long));
	$r->fix_position($o);
    } else {
	$o->Street($s);
    }
}

return 1 if caller() or keys %Devel::Trace::; # XXX Tracer bug

######################################################################

{
    my $o = BBBikeRouting::Cmdline->parse_options;
    my $routing = BBBikeRouting->factory($o->{vehicle})->init_context;
    my $cmd = BBBikeRouting::Cmdline->new($routing);
    $cmd->cmdline_input($o);
    $cmd->search;
    $cmd->cmdline_output;
}

__END__

=head1 NAME

cmdbbbike - a very simple command line tool to BBBike

=head1 SYNOPSIS

    cmdbbbike Startstr Zielstr

  ./cmdbbbike startstr zielstr -dumpbbd | ./miscsrc/bbd2mapservhtml.pl -local > /tmp/mapserver_route.html

=head1 DESCRIPTION

=head2 OPTIONS

=over

=item C<-dumproute>

Dump a route object, as a perl data structure, or as YAML if C<-yaml>
is given.

=item C<-dumppath>

Dump an array of coordinates of the path, as a perl data structure, or
as YAML if C<-yaml> is given.

=back

=cut
