#!/usr/bin/perl -w

use strict;

use FindBin;
use lib ("$FindBin::RealBin/..",
	 "$FindBin::RealBin/../lib",
	);
use Getopt::Long;
use Strassen::Core;
use Strassen::GeoJSON;

sub usage {
    die <<EOF;
usage: $0 [-compact|-nocompact|-multiline] [-bbbgeojsonp] [-combine [-combinemodule A::B::C]] [-manipulatemodule A::B::C] bbdfile
EOF
}

my $pretty = 1;
my $multiline = 0;
my $utf8 = 0;
my $combine;
my $combinemodule;
my $manipulatemodule;
my $bbbgeojsonp;
GetOptions(
	   "compact"     => sub {
	       $multiline = 0;
	       $pretty = 0;
	       $utf8 = 1;
	   },
	   "multiline"   => sub {
	       $multiline = 1;
	       $pretty = 0;
	       $utf8 = 1;
	   },
	   "combine!"     => \$combine,
	   "combinemodule=s" => \$combinemodule,
	   "manipulatemodule=s" => \$manipulatemodule,
	   "bbbgeojsonp!" => \$bbbgeojsonp,
	  ) or usage();

my $file = shift || usage();
my $s = Strassen->new($file, UseLocalDirectives => 1);
my $s_geojson = Strassen::GeoJSON->new($s);
if ($bbbgeojsonp) {
    print "// generated with bbd2geojson from BBBike distribution, see\n";
    print "// https://github.com/eserte/bbbike/blob/master/miscsrc/bbd2geojson\n";
}
print $s_geojson->bbd2geojson(bbbgeojsonp => $bbbgeojsonp, pretty => $pretty, utf8 => $utf8, multiline => $multiline, combine => $combine, combinemodule => $combinemodule, manipulatemodule => $manipulatemodule);
print "\n";

__END__

=head1 NAME

bbd2geojson - convert BBD files to GeoJSON files

=head1 SYNOPSIS

    bbd2geojson [-compact|-nocompact|-multiline] [-combine [-combinemodule A::B::C]] [-manipulatemodule A::B::C] [-bbbgeojsonp] bbdfile > output.geo.json

=head1 DESCRIPTION

Create a GeoJSON file from a BBBike data file (bbd). Options:

=over

=item C<-compact>

Create somewhat smaller output: don't create a "pretty" json,
resulting in a one-line (and diff-unfriendly) file, and use utf-8
encoding instead of javascript escape sequences (which are usually
some bytes longer).

=item C<-multiline>

For GeoJSON with a FeatureCollection: put every feature in a separate
line. This might generate diff- and rsync-friendly output, but still
quite compact in contract to the default output style.

Create

=item C<-combine>

Combine features with same coordinates into a single feature, joining
the names (separated with a HTML C<< <br/> >>).

=item C<-combinemodule I<module>>

Use a custom module for combining features. See L</CUSTOM COMBINING>
for more details.

=item C<-manipulatemodule I<module>>

Use a custom module for manipulating feature. See L</CUSTOM MANIPULATION>
for more details.

=item C<-bbbgeojsonp>

Create a JSONP-like file. For details, see L<Strassen::GeoJSON/JSONP
support>.

=back

=head2 CUSTOM COMBINING

Combining features e.g. with the same coordinate may be done in a
custom way using a module specified with the C<-combinemodule> option.
This module should be implemented as a normal perl OO module with a
constructor C<new> and the following methods:

=over

=item C<< add_first(rec => I<$strassenrecord>, feature => I<$feature>) >>

Called if the coordinate was encountered the first time. May be used
to remember the given "Strassen" record and the GeoJSON feature.

=item C<< maybe_append(rec => I<$strassenrecord>) >>

Called to check if the given "Strassen" record may be combined with an
existing feature (e.g. because it has the same coordinate). Should
return true if this is the case, otherwise false.

=item C<< flush() >>

May be used to actually do the combines. May be an empty method if the
combines were already done in C<maybe_append>.

=back

Please see the source code of L<Strassen::GeoJSON> for a package named
C<< Strassen::GeoJSON::CombineFeatureNames >> and the test file
F<t/strassen-geojson.t> for sample implementations.

=head2 CUSTOM MANIPULATION

Manipulating a feature (e.g. its properties) may be done in a custom
way using a module specified with the C<-manipulatemodule> option.
This module should be implemented as a normal perl OO module with a
constructor C<new> (which in this case usually just blesses an empty
hash) and the following method:

=over

=item C<< manipulate_feature(I<$feature>, I<$bbd_record>, I<$bbd_directives>) >>

The I<$feature> can be manipulated, e.g. fields in C<properties>
added, changed or removed. The <$bbd_record> (a hash with name,
category and coordinates, see L<Strassen::Core>) and
C<$bbd_directives> (a HoA containing local directives for the current
record) is also given. The return value is ignored.

=back

Please see the test file F<t/strassen-geojson.t> for a sample
implementation.

=head1 AUTHOR

Slaven Rezic

=head1 SEE ALSO

L<Strassen::GeoJSON>.

=cut
