#!/usr/bin/env perl
use strictures 2;

use GIS::Distance;
use Module::Find qw( findallmod );
use Getopt::Long;

Getopt::Long::Configure(qw(
    gnu_getopt no_ignore_case
));

GetOptions(
    'pp!'           => \my $do_pp,
    'xs!'           => \my $do_xs,
    'geo'           => \my $do_geo,

    'precision|p=i' => \my $precision,

    'h|help'        => \my $help,
) or die "Unable to process options!\n";

if ($help) {
    require Pod::Usage;
    Pod::Usage::pod2usage( -verbose => 2 );
    exit 0;
}

$do_pp = 1 if !defined $do_pp;
$do_xs = 1 if !defined $do_xs;

$precision ||= 12;

my @coords;

# Beirut to Dimashq.
@coords = ( 33.863146, 35.52824, 33.516496, 36.287842 );

# https://github.com/bluefeet/Geo-Distance/issues/15
#@coords = ( 52.484977, 13.385900, 52.485033, 13.370897 );

my %distances;

{
    my @formulas = (
        grep { $_ !~ m{::Formula} }
        grep { $_ ne 'GIS::Distance::Constants' }
        grep { $_ ne 'GIS::Distance::Fast' }
        findallmod('GIS::Distance')
    );

    @formulas = (
        grep { $_ !~ m{::Fast::} }
        @formulas
    ) if !$do_xs;

    @formulas = (
        grep { $_ =~ m{::Fast::} }
        @formulas
    ) if !$do_pp;

    foreach my $formula (@formulas) {
        my $gis = GIS::Distance->new( $formula );
        my $km = $gis->distance( @coords )->km();
        $distances{ $formula } = $km;
    }
}

if ($do_geo and $do_pp) {
    require Geo::Distance;
    Geo::Distance->import();
    my @formulas = @Geo::Distance::FORMULAS;

    foreach my $formula (@formulas) {
        my $geo = Geo::Distance->new();
        $geo->formula( $formula );
        my $km = $geo->old_distance( 'kilometer', reverse @coords );
        $distances{ "Geo::Distance-$formula" } = $km;
    }
}

if ($do_geo and $do_xs) {
    require Geo::Distance::XS;
    Geo::Distance::XS->import();
    my @formulas = @Geo::Distance::XS::FORMULAS;

    foreach my $formula (@formulas) {
        my $geo = Geo::Distance->new();
        $geo->formula( $formula );
        my $km = $geo->distance( 'kilometer', reverse @coords );
        $distances{ "Geo::Distance::XS-$formula" } = $km;
    }
}

my %formulas_by_distance;
foreach my $formula (keys %distances) {
    my $distance = sprintf("%.0${precision}f", $distances{$formula});
    my $formulas = $formulas_by_distance{ $distance } ||= [];
    push @$formulas, $formula;
}

foreach my $distance (sort keys %formulas_by_distance) {
  print "$distance:\n";
  print map { " - $_\n" } sort @{ $formulas_by_distance{$distance} };
}

__END__

=head1 NAME

author/distances - Display the distance generated by all the formulas.

=head1 SYNOPSIS

    # List distances for every GIS::Distance and GIS::Distance::Fast
    # formula.
    author/distances
    
    # List distances for every GIS::Distance::Fast and
    # Geo::Distance::XS formula.
    author/distances --geo --no-pp
    
    # Displays this handy documentation!
    author/distances --help

=head1 OPTIONS

=head2 pp

    --no-pp

Disable the C<pp> option, meaning no pure-perl formulas will
be included.

=head2 xs

    --no-xs

Disable the C<xs> option, meaning no XS formulas will
be included.

=head2 geo

    --geo

L<Geo::Distance> and/or L<Geo::Distance::XS> formulas will be
included.

=head2 precision

    --precision=14
    -p 8

When grouping formulas format the timing to this number of
decimal places.

The default is C<12>, which does a good job of grouping the
formulas which really are producing the exact same result.

=head2 help

    --help
    -h

Displays this handy documentation!

=head1 AUTHORS AND LICENSE

See L<GIS::Distance/AUTHORS> and L<GIS::Distance/LICENSE>.

=cut

