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

#
# Author: Slaven Rezic
#

#
# To create a .bbd file of all .bbr files:
#   cd ~/.bbbike/route/touren
#   ~/src/bbbike/miscsrc/bbr2bbd -cat '#800000' -f -usebasename -dest /tmp *.bbr
#   cat /tmp/*.bbd > /tmp/all
#   mv /tmp/all /tmp/all.bbd
#
# Create with offsetted lines which may indicate direction
#   ~/src/bbbike/miscsrc/bbr2bbd -cat '#800000' -f -usebasename -cat 'X;' *.bbr -o /tmp/output.bbd
#
# Use a final arrow:
#   ~/src/bbbike/miscsrc/bbr2bbd -cat '#800000' -f -usebasename -cat 'X;' -glob-dir line_arrow=last *.bbr -o /tmp/output.bbd
#
# Split polylines (notable slower rendering in bbbike):
#   ~/src/bbbike/miscsrc/bbr2bbd -cat '#800000' -f -usebasename -cat 'X;' -glob-dir line_arrow=last -split-line *.bbr -o /tmp/output.bbd
#

use strict;
use FindBin;
use lib ("$FindBin::RealBin/..",
	 "$FindBin::RealBin/../lib",
	);
#use vars qw($coords_ref $realcoords_ref $search_route_points_ref);
my %opt = (cat => "X", name => "Route", f => 0, usebasename => 0);
use Getopt::Long;
use File::Basename;
use Route;
use Route::Heavy;

if (!GetOptions(\%opt,
		"cat=s", "cats=s", "name=s", "dest=s", "f", "usebasename",
		"route-data","data-route", "o=s",
		"include-length-to-name", "include-moddate-to-name",
		'glob-dir|global-directive=s@', 'split-line',
	       )) {
    die "usage:
    $0 [-cat category | -cats category,category,...] [-name routename]
       [-usebasename] [-dest directory] [-o file] [-f]
       [-data-route] [-route-data]
       [-include-length-to-name] [-include-moddate-to-name]
       [-globdir key=val ...] [-split-line]
       [from to | files ...]
";
}

my $cat_i = 0;
my @cats;
if ($opt{cats}) { # use round-robin categories
    @cats = split /,/, $opt{cats};
}

if ($opt{dest}) {
    warn "Using batch conversion to directory $opt{dest}\n";
    if (!-d $opt{dest} || !-w $opt{dest}) {
	die "$opt{dest} is no directory or not writable";
    }
    foreach my $f (@ARGV) {
	my $dest = basename($f);
	$dest =~ s/\.bbr$/\.bbd/g;
	eval {
	    convert_one_file($f, "$opt{dest}/$dest");
	};
	if ($@) {
	    warn $@;
	}
    }
} elsif ($opt{o}) {
    if (!$opt{f}) {
	if (-e $opt{o}) {
	    die "$opt{o} already exists, please remove or use -f";
	}
    }
    open my $ofh, '>', $opt{o}
	or die "Can't write to $opt{o}: $!";
    for my $f (@ARGV) {
	convert_one_file($f, $ofh);
    }
    close $ofh
	or die "Error while writing to $opt{o}: $!";
} else {
    convert_one_file(@ARGV[0,1]);
}

sub convert_one_file {
    my $in_file  = shift;
    my $out_file_or_fh = shift;

    if (defined $in_file) {
	open(IN, "< $in_file") or die "Can't open $in_file: $!";
    } else {
	open(IN, "<&STDIN");
    }

    my $ofh;
    my $ofh_opened;
    my $open_out_file = sub {
	if (ref $out_file_or_fh eq 'GLOB') {
	    $ofh = $out_file_or_fh;
	} else {
	    my $out_file = $out_file_or_fh;
	    if (defined $out_file) {
		if ($in_file eq $out_file) {
		    die "In and out files are the same";
		}
		if (-e $out_file && !$opt{f}) {
		    die "$out_file already exists";
		}
		open $ofh, '>', $out_file
		    or die "Can't create $out_file: $!";
	    } else {
		open $ofh, '>&', \*STDOUT;
	    }
	    $ofh_opened = 1;
	}
    };

    my $first_line = scalar <IN>;
    my $conversion;
    if ($opt{"data-route"}) {
	$conversion = "bbd2bbr";
    } elsif ($opt{"route-data"}) {
	$conversion = "bbr2bbd";
    } else {
	# guess conversion
    }
    my @in_data;
    if (defined $first_line && $first_line =~ /^\#BBBike\s+route/) {
	$conversion = "bbr2bbd" if !defined $conversion;
    } else {
	if (defined $first_line && $first_line =~ /^\s*\#/) {
	    while(<IN>) {
		if (!/^\s*\#/) {
		    $first_line = $_;
		    last;
		}
	    }
	}
	# This heuristic may fail...
	if (defined $first_line && $first_line =~ /^([^\t]*)\t(\S+)\s+([-+0-9].*)$/) {
	    $conversion = "bbd2bbr" if !$conversion;
	    @in_data = ($1, $2, $3);
	} else {
	    #warn "<$in_file>: Unknown input file format, assuming Route file";
	    $conversion = "bbr2bbd" if !$conversion;
	}
    }
    close IN;

    if ($conversion eq 'bbr2bbd') {
	my $name = $opt{name};
	if ($opt{usebasename}) {
	    ($name) = fileparse($in_file, "\\..+\$");
	}
	my $cat;
	if (@cats) {
	    $cat = $cats[$cat_i++];
	    if ($cat_i > $#cats) {
		$cat_i = 0;
	    }
	} else {
	    $cat = $opt{cat};
	}
	my $route = Route->load_bbr_as_object($in_file);
	my $str = $route->as_strassen(name => $name, cat => $cat, fuzzy => 1);
	if (!$str) {
	    die "Die Datei <$in_file> enthlt keine Route."
	}
	if ($opt{'include-length-to-name'} || $opt{'include-moddate-to-name'}) {
	    my $len = 0;
	    my $moddate;

	    if ($opt{'include-length-to-name'}) {
		require BBBikeUtil;
		require Strassen::Stat;
		$str->init;
		while(1) {
		    my $ret = $str->next;
		    last if !@{ $ret->[Strassen::COORDS()] };
		    $len += Strassen::total_len($ret);
		}
	    }

	    if ($opt{'include-moddate-to-name'}) {
		my(@s) = stat($in_file);
		if (@s) {
		    my @l = localtime $s[9];
		    $moddate = sprintf "%04d-%02d-%02d", $l[5]+1900, $l[4]+1, $l[3];
		}
	    }

	    my $new_str = Strassen->new;
	    $str->init;
	    while(1) {
		my $ret = $str->next;
		last if !@{ $ret->[Strassen::COORDS()] };
		if ($len) {
		    $ret->[Strassen::NAME()] .= " (" . BBBikeUtil::m2km($len) . ")";
		}
		if ($moddate) {
		    $ret->[Strassen::NAME()] .= " (" . $moddate . ")";
		}
		if ($opt{'split-line'}) {
		    for my $c_i (1 .. $#{ $ret->[Strassen::COORDS()] }) {
			my($from, $to) = @{ $ret->[Strassen::COORDS()] }[$c_i-1,$c_i];
			$new_str->push([$ret->[Strassen::NAME()], [$from, $to], $ret->[Strassen::CAT()]]);
		    }
		} else {
		    $new_str->push($ret);
		}
	    }
	    $str = $new_str;
	}
	if (@{ $opt{'glob-dir'} || [] }) {
	    my %key2vals;
	    # gather first
	    for my $glob_dir (@{ $opt{'glob-dir'} }) {
		my($k,$v) = split /=/, $glob_dir, 2;
		push @{ $key2vals{$k} }, $v;
	    }
	    $str->set_global_directives(\%key2vals);
	}
	$open_out_file->();
	print $ofh $str->as_string;

## XXX not used anymore (?)
# 	require Safe;
# 	my $compartment = new Safe;
# 	$compartment->share(qw($realcoords_ref $coords_ref
# 			       $search_route_points_ref
# 			      ));
# 	$compartment->rdo($in_file);

# 	die "Die Datei <$in_file> enthlt keine Route."
# 	    if (!defined $realcoords_ref);

# 	if (defined $coords_ref) {
# 	    warn "Achtung: <$in_file> enthlt altes Routen-Format.\n".
# 		"Koordinaten knnen verschoben sein!\n";
# 	}

# 	my $name = $opt{name};
# 	if ($opt{usebasename}) {
# 	    ($name) = fileparse($in_file, "\\..+\$");
# 	}
# 	print $ofh "$name\t$opt{cat}";
# 	foreach (@$realcoords_ref) {
# 	    print $ofh " " . $_->[0] . "," . $_->[1];
# 	}
# 	print $ofh "\n";
    } else { # bbd2bbr
	my @coords = split(/\s+/, $in_data[2]);
	$open_out_file->();
	print $ofh "#BBBike Route\n";
	print $ofh "\$realcoords_ref = [";
	foreach (@coords) {
	    print $ofh "[" . $_ . "],";
	}
	print $ofh "];\n";
	print $ofh "\$search_route_points_ref = [";
	print $ofh "['" . $coords[0] . "','m'],";
	print $ofh "['" . $coords[-1] . "','a'],";
	print $ofh "];\n";
    }

    if ($ofh_opened) {
	close $ofh
	    or die "Error while closing output filehandle: $!";
    }
}

__END__
