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

#
# Author: Slaven Rezic
#
# Copyright (C) 1998,2002,2008,2013,2023 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.de
#

# This script is primarily used for converting radwege data.
# There are two modes:
#   -exact: exact conversion for data used for routing, and with the new
#           line_do_offset bbd directive may also be used for plotting
#   -noexact: radwege are displaced by a delta for drawing the
#             cyclepaths next to the street (using the -delta option);
#             obsoleted by the new capability of setting
#	      line_do_offset for "exact" data 
#
# The script may also be misused for creating an area around a
# path, e.g. for creating an entry for weblinks.bbd. Use the
#   -join -delta ...
# options.

use strict;
use File::Basename;
use FindBin;
use lib ("$FindBin::RealBin/..", "$FindBin::RealBin/../lib");
use Karte;
use Radwege;
use Getopt::Long;

use constant PI => 4 * atan2(1, 1); # 3.141592653

# mit -exact wird keine Versetzung der Radwege durchgefhrt
# somit kann die erzeugte Datei fr ein Optimierungs-Netz (siehe Strassen.pm,
# Package StrassenNetz) verwendet werden.
my $exact = 0;
my $join = 1; # XXX join lines not implemented yet!
my $inmap = "Standard";
my $outmap = "Standard";
my $conv;
my $conv_code;
my $oldfmt;
my $delta = 20;
my $datadir = $ENV{BBBIKE_DATADIR} || "$FindBin::RealBin/../data";

if (!GetOptions("exact!" => \$exact,
		"join!" => \$join, # XXX document!
		"inmap=s" => \$inmap,
		"outmap=s" => \$outmap,
		"conv=s" => \$conv_code,
		"noconv" => sub { $conv = sub { @_ } },
		"oldfmt!" => \$oldfmt,
		"delta=f" => \$delta,
		"datadir=s" => \$datadir,
	       )) {
    die <<EOF;
Usage: $0 [-[no]exact]
          [-inmap map] [-outmap map] [-conv convcode] [-datadir directory]
          [-noconv] [-oldfmt] < infile > outfile

-exact:      create an exact database (for the routing engine)
-noexact:    create a database with displaced lines (for the mapping engine)
-delta:      delta for displaced lines (default: $delta)
-inmap map:  use this Karte::* map for the source
-outmap map: use this Karte::* map for the destination
-conv code:  use the specified source code for the conversion subroutine
-noconv:     do not convert (by default:
             convert from $inmap to $outmap)
-oldfmt:     obsolete
-datadir:    use another datadir instead of $datadir
-combinedir: combine directions for RW6 type (NYI!)
EOF
}

# XXX NYI
my %combinetype = map {($Radwege::category_code{$_},1)} qw(ruhig);

if ($oldfmt) {
    die <<'EOF'
-oldfmt not supported anymore. Please convert from old format to new
format with:

cd .../bbbike/data
perl -I.. -MRadwege -F'\t' -nale 'print "\t$Radwege::category_code{$F[2]};$Radwege::category_code{$F[3]} $F[0] $F[1]"' radwege-orig

EOF

}

if (!$conv) {
    if (!$conv_code) {
	Karte::preload($inmap, $outmap);
	$conv = sub {
	    $Karte::map_by_modname{$inmap}->map2map
		($Karte::map_by_modname{$outmap}, @_)
	    };
    } else {
	$conv = eval $conv_code;
	die $@ if $@;
    }
}

my @radweg;

my $s;
my $getnext;
my %rev_category_code;
{
    require Strassen::Core;
    $s = Strassen->new("-");
    $s->init;
    %rev_category_code = reverse %Radwege::category_code;
    my $r;   # current street record
    my $rci; # current street coord counter
    $getnext = sub {
	if (!$r || @{$r->[Strassen::COORDS()]} == $rci) {
	    $r = $s->next;
	    return if !@{ $r->[Strassen::COORDS()] };
	    $rci = 1;
	}
	if (@{ $r->[Strassen::COORDS()] } < 2) {
	    die "Sollte mindestens zwei Koordinaten enthalten, Position " . $s->pos . ", Zeile <" . Strassen::arr2line2($r) . ">";
	}

	# Currently, the "?" in RW...? are ignored
	my $cat = $r->[Strassen::CAT()];
	$cat =~ s{\?($|;)}{$1}g;

	my($cat_hin, $cat_rueck);
	if ($cat =~ /;/) {
	    my($hin,$rueck) = split /;/, $cat;
	    $cat_hin   = $rev_category_code{$hin} || "kein";
	    $cat_rueck = $rev_category_code{$rueck} || "kein";
	} else {
	    $cat_hin   = $rev_category_code{$cat};
	    $cat_rueck = $rev_category_code{$cat};
	}
	my @coords;
	if ($join) {
	    @coords = @{$r->[Strassen::COORDS()]}; $rci = @{$r->[Strassen::COORDS()]}-1;
	} else {
	    @coords = @{$r->[Strassen::COORDS()]}[$rci-1, $rci];
	}	
	$rci++;
	($cat_hin, $cat_rueck, @coords);
    };
}

if ($exact) {
    # With these directives the "exact" file is also suitable for
    # plotting.
    print <<EOF;
#: line_do_offset: 1
#: line_arrow: none
#:
EOF
}

while(1) {
    my($hin, $rueck, @l) = $getnext->();
    last if !defined $l[0];
    die "Hin is undefined, Position " . $s->pos . ", Record " . Strassen::arr2line2($s->get($s->pos)) if !defined $hin;
    die "Rueck is undefined, Position " . $s->pos . ", Record " . Strassen::arr2line2($s->get($s->pos)) if !defined $rueck;

    my $do_hin   = exists $Radwege::category_code{$hin} && $Radwege::category_code{$hin} ne "RW0";
    my $do_rueck = exists $Radwege::category_code{$rueck} && $Radwege::category_code{$rueck} ne "RW0";

    my(@x,@y,@dx,@dy);
    for my $i (0 .. $#l) {
	($x[$i], $y[$i]) = split(/,/, $l[$i]);
	($x[$i], $y[$i]) = $conv->($x[$i], $y[$i]);
	#XXX $Karte::Berlinmap1996::obj->map2standard($x[$i], $y[$i]);
    }

    #require Data::Dumper; print STDERR "Line " . __LINE__ . ", File: " . __FILE__ . "\n" . Data::Dumper->new([$s->get($s->pos)],[qw()])->Indent(1)->Useqq(1)->Dump; # XXX

    for my $i (1 .. $#l) {
	my $alpha = atan2($y[$i]-$y[$i-1], $x[$i]-$x[$i-1]);
	my $beta  = $alpha - PI/2;
	my($dx, $dy);
	if ($exact) {
	    ($dx, $dy) = (0, 0);
	} else {
	    #	($dx, $dy) = (int($delta*cos($beta)), int($delta*sin($beta)));
	    ($dx, $dy) = ($delta*cos($beta), $delta*sin($beta));
	}
	$dx[$i] = $dx;
	$dy[$i] = $dy;
	if ($i == 1) {
	    $dx[0] = $dx[1];
	    $dy[0] = $dy[1];
	}
	if (!$exact && $join && $i < $#l) {
	    #XXX implementation missing!
	    # This would try to join adjacent lines
	    # note that this is only useful if the streets are
	    # actually combined (which can be accomplished
	    # by calling combined_streets before)
	}
    }

    if ($do_hin) {
	print "\t" . $Radwege::category_code{$hin};
	for my $i (0 .. $#l) {
	    print " " . join(",", map { int } ($x[$i]+$dx[$i], $y[$i]+$dy[$i]));
	}
	print "\n";
    }
    if ($do_rueck) {
	print "\t" . $Radwege::category_code{$rueck};
	for my $i (reverse(0 .. $#l)) {
	    print " " . join(",", map { int } ($x[$i]-$dx[$i], $y[$i]-$dy[$i]));
	}
	print "\n";
    }
}

__END__

