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

#
# Author: Slaven Rezic
#
# Copyright (C) 2008,2014,2016,2021,2022,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://www.rezic.de/eserte/
#

use strict;
use FindBin;
use lib ("$FindBin::RealBin/..",
	 "$FindBin::RealBin/../lib",
	);

use File::Basename qw(basename);
use Getopt::Long;

use GPS::GpsmanData::Any;

sub usage (;$) {
    my $msg = shift;
    print STDERR $msg, "\n" if $msg;
    die <<EOF;
usage: $0 [--check-roundtrip] [--if-roundtrip-ok] [-o ...] [-timeoffset hours|automatic] [-type-to-vehicle] [-guess-device] gpxfile
EOF
}

my $mode = basename($0) =~ /any2gpsman/ ? 'any' : 'gpx';

my $do_check_roundtrip;
my $if_roundtrip_ok;
my $outfile;
my $timeoffset;
my $type_to_vehicle;
my $guess_device;
my $debug;
GetOptions(
	   'check-roundtrip!' => \$do_check_roundtrip,
	   'if-roundtrip-ok' => \$if_roundtrip_ok,
	   'out-file|o=s' => \$outfile,
	   'timeoffset=s' => \$timeoffset,
	   'type-to-vehicle!' => \$type_to_vehicle,
	   'guess-device!' => \$guess_device,
	   'debug!' => \$debug,
	  )
    or die usage;
my $file = shift;
if (!defined $file || $file eq '-') {
    if ($mode eq 'any') {
	die "Reading files from stdin is not supported with any2gpsman.\n";
    }
    if ($do_check_roundtrip || $if_roundtrip_ok) {
	die "-check-roundtrip or -if-roundtrip-ok is not supported when reading GPX file from stdin.\n";
    }
    if (!defined $file) { # be loud only if run without arguments
	warn "Reading GPX file from stdin...\n";
    }
    $file = \*STDIN;
}
@ARGV and usage "Please specify only one gpx file";

my @gps_gpsmandata_any_options;
if (defined $timeoffset) {
    push @gps_gpsmandata_any_options, timeoffset => $timeoffset;
}
if (defined $type_to_vehicle) {
    push @gps_gpsmandata_any_options, typetovehicle => $type_to_vehicle;
}
if (defined $guess_device) {
    push @gps_gpsmandata_any_options, guessdevice => $guess_device;
}

if ($do_check_roundtrip) {
    my $success = check_roundtrip();
    exit($success ? 0 : 1);
} else {
    if ($if_roundtrip_ok) {
	my $success = check_roundtrip();
	die "Roundtrip check failed, stop conversion.\n" if !$success;
    }
    my $gpsman;
    if ($mode eq 'any') {
	$gpsman = GPS::GpsmanData::Any->load($file, @gps_gpsmandata_any_options, debug => $debug);
    } else {
	$gpsman = GPS::GpsmanData::Any->load_gpx($file, @gps_gpsmandata_any_options);
    }
    if ($outfile) {
	my $outdir = File::Basename::dirname($outfile);
	if (!$outdir) {
	    die "Directory for $outfile does not exist";
	}
	require File::Temp;
	require File::Basename;
	my $tmp = File::Temp->new(UNLINK => 1, SUFFIX => '.gpsman', DIR => $outdir);
	chmod 0644, $tmp;
	print $tmp $gpsman->as_string;
	close $tmp
	    or die "Writing to temporary file $tmp failed: $!";
	rename $tmp, $outfile
	    or die "Rename $tmp -> $outfile failed: $!";
	$tmp->unlink_on_destroy(0);
    } else {
	print $gpsman->as_string;
    }
}

sub check_roundtrip {
    require GPS::GpsmanData::TestRoundtrip;
    GPS::GpsmanData::TestRoundtrip::gpx2gpsman2gpx($file, @gps_gpsmandata_any_options);
}

__END__

=head1 NAME

gpx2gpsman - convert GPX files to GPSMan files

=head1 SYNOPSIS

Convert without a roundtrip check:

    gpx2gpsman [-timeoffset hours|automatic] source.gpx -o target.trk

Convert only if a roundtrip check was successful:

    gpx2gpsman [-timeoffset hours|automatic] -if-roundtrip-ok source.gpx -o target.trk

Just do a roundtrip check:

    gpx2gpsman [-timeoffset hours|automatic] -check-roundtrip source.gpx

Support for other file formats (see L<GPS::GpsmanData::Any> for
supported formats):

    any2gpsman file -o target.trk

=head1 DESCRIPTION

Convert GPX files to GPSMan files. The conversion is done using the
module L<GPS::GpsmanData::Any>.

If the I<source.gpx> filename is omitted, or C<-> is used instead,
then the GPX file is expected to be read from stdin. This is not
possible if the C<-check-roundtrip> or C<-if-roundtrip-ok> options are
set, and also not possible with C<any2gpsman>.

=head1 OPTIONS

=over

=item C<-timeoffset ...>

Set the time offset in the generated files to the given amount in
hours. If C<automatic> is used as the option value, then heuristics is
used to get to the time offset by date and location (see
L<Time::Zone::By4D>). If none is set, then Zulu time is used.

=item C<-o ...>

Define a output file for the converted GPSMan data. If C<-o> is not
set, then the output is written to stdout.

=item C<-if-roundtrip-ok>

Do the conversion only if a roundtrip check (see
L<GPS::GpsmanData::TestRoundtrip>) was successful. If the roundtrip
check was not successful, then the program exits with a non-zero
value.

=item C<-check-roundtrip>

Do just a roundtrip check without any conversions. If the roundtrip
check was not succesful, then the program exits with a non-zero value.

=back

=head1 AUTHOR

Slaven Rezic

=head1 SEE ALSO

L<GPS::GpsmanData::Any>, L<GPS::GpsmanData::TestRoundtrip>.

=cut
