#!/usr/bin/perl

# Copyright (C) 2010, 2011, 2015 Thorsten Kukuk
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# in Version 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA  02110-1301, USA.

=head1 NAME

geo-waypoints - Create GPX file with waypoints from coordinates

=head1 SYNOPSIS

geo-waypoints [options] [[-f] input.txt|name latitude longitude [desc]]

=head1 DESCRIPTION

geo-waypoints creates a GPX file from a list of coordinates.

=head1 OPTIONS

  -a|--add-comment    Add comment to description
  -f|--file <file>    Text file with coordinates
  -s|--symbol <type>  The waypoint types [Geocache]
  --dump-config       Write arguments as default config and exit
  --version           Print version number and exit
  --usage             Display usage
  --man               Display manual page
  -h|-?|--help	      Help

=head1 INPUT

The input file has the format:

  name, latitude longitude[, desc][# comment]

Empty lines or lines starting with a # will be ignored.

=head1 SYMBOLS
Valid symbols are:
  Hotel:		Lodging
  Geocache:		Geocache

=head1 COPYRIGHT

Copyright (c) 2010, 2011, 2015 by Thorsten Kukuk.  All rights reserved.

This package is free software; you can redistribute it and/or modify
it under the GPL version <http://gnu.org/licenses/gpl2.html>.
There is NO WARRANTY, to the extent permitted by law.

=cut

use strict;
use warnings;
use Pod::Usage;
use Config::IniFiles;
use utf8;
use open ':encoding(utf8)';
binmode(STDOUT, ":utf8");

#
# process command line arguments
#
use Getopt::Long;
use GEO::Coords;

my $help = 0;
my $man = 0;
my $usage = 0;
my $version = 0;
my $dump_config = 0;
my $homedir = '';

if ($ENV{HOME}) {
  $homedir = $ENV{HOME};
} elsif ($ENV{HOMEDRIVE} && $ENV{HOMEPATH}) {
  $homedir = $ENV{HOMEDRIVE}."/".$ENV{HOMEPATH};
}
my $cfgname = $homedir."/.geo-tools.cfg";

if (!-r $cfgname) {
  my $cfg = new Config::IniFiles(-default => "Global",
                                 -nocase => 1);
  $cfg->AddSection("geo-waypoints");
  $cfg->newval("geo-waypoints", "symbol", "Geocache");
  $cfg->WriteConfig($cfgname);
}

my $cfg = new Config::IniFiles(-file => $cfgname,
                               -default => "Global");
if (!$cfg->SectionExists("geo-waypoints")) {
  $cfg->AddSection("geo-waypoints");
  $cfg->newval("geo-waypoints", "symbol", "Geocache");
  $cfg->WriteConfig($cfgname);
}

my $coords = $cfg->val("geo-waypoints", "coodinates");
my $symbol = $cfg->val("geo-waypoints", "symbol", "Geocache");
my $addcomment = $cfg->val("geo-waypoints", "addcomment", 0);


GetOptions('a|add-comment:1' => \$addcomment,
	   'f|file=s' => \$coords,
	   's|symbol=s' => \$symbol,
	   'dump-config' => \$dump_config,
	   'version' => \$version,
	   'man' => \$man,
	   'usage' => \$usage,
	   'help|h|?' => \$help) or pod2usage(2);
pod2usage(0) if $help;
pod2usage(-exitstatus => 0, -verbose => 2) if $man;
pod2usage(-exitstatus => 0, -verbose => 0) if $usage;

if ($version) {
  print "geo-waypoints (geo-tools) 1.23\n";
  exit;
}

if ($dump_config) {
  WriteConfig();
  exit;
}


my %Waypoints = ();
my $minlat = 0xFFFFFFFF;
my $minlon = 0xFFFFFFFF;
my $maxlat = -0xFFFFFFFF;
my $maxlon = -0xFFFFFFFF;

if ($coords && $coords ne '' && -r $coords) {
  pod2usage (2) if ($#ARGV >= 0);
  readfile ($coords);
} elsif ($#ARGV >= 0) {
  my $Line = '';

  foreach (@ARGV) {
    if (-r $_) {
      readfile ($_);
    } elsif ($Line eq '') {
      $Line=$_;
    } else{
      $Line .= ", ".$_;
    }
  }
  AddWaypoint($Line) unless ($Line eq '');
} elsif (($#ARGV < 0) ||($#ARGV == 0 && $ARGV[0] eq "-")) {
  # read from tty
  while (<>) {
    AddWaypoint($_);
  }
} else {
  pod2usage (2);
}

if (keys(%Waypoints) >=  0) {

  print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
  print "<gpx
  version=\"1.0\"
  creator=\"geo-waypoints - http://www.thkukuk.de/geocaching/\"
  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  xmlns=\"http://www.topografix.com/GPX/1/0\"
  xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd\">\n";
  my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time());
  $year += 1900;
  $mon += 1;
  printf "  <time>%d-%02d-%02dT%02d:%02d:%02d</time>\n",
    $year, $mon, $mday, $hour, $min, $sec;
  print "  <bounds minlat=\"$minlat\" minlon=\"$minlon\" maxlat=\"$maxlat\" maxlon=\"$maxlon\"/>\n";

  my ($k, $v);
  while (($k,$v) = each %Waypoints) {
    PrintGPXWaypoint($k, $v);
  }

  print "</gpx>\n";
}
exit;

sub WriteConfig
{
  $cfg->newval("geo-waypoints", "coodinates", $coords);
  $cfg->newval("geo-waypoints", "symbol", $symbol);
  $cfg->newval("geo-waypoints", "addcomment", $addcomment);

  $cfg->WriteConfig($cfgname);
}


sub readfile {
  my $file = $_[0];

  open(COORDSFILE, "<", $file);
  my @Lines = readline(*COORDSFILE);
  foreach my $Line (@Lines) {
    AddWaypoint($Line);
  }
  close COORDSFILE;
}

sub PrintGPXWaypoint {
  my $ID = $_[0];
  my $wpt = $_[1];
  my $Note;
  my $Comment;

  if ($wpt->{Note} && length($wpt->{Note}) > 0) {
    $Note=$wpt->{Note};
    $Note =~ s/\s*$//;
  }

  if ($addcomment && $wpt->{Comment} && length($wpt->{Comment}) > 0) {
    $Comment=$wpt->{Comment};
    $Comment =~ s/\s*$//;
    if ($Note && length($Note) > 0) {
      $Note .= "\n".$Comment;
    } else {
      $Note = $Comment;
    }
  }

  print "  <wpt lat=\"$wpt->{Latitude}\" lon=\"$wpt->{Longitude}\">\n";
  print "    <name>$ID</name>\n";
  if ($Note) {
    $Note =~ s/&/&amp;/g;
    $Note =~ s/</&lt;/g;
    $Note =~ s/>/&gt;/g;
    print "    <cmt>$Note</cmt>\n";
    print "    <desc>$Note</desc>\n";
  }
  print "    <sym>$symbol</sym>\n";
  print "  </wpt>\n";
}

sub AddWaypoint {
  my $Line = $_[0];
  my @Fields = SplitInputLine($Line);
  if ($#Fields > 0) {
    my ($lat, $lon) = GEO::Coords::parse2($Fields[1]);
    if (!defined $lat || !defined $lon) {
      print STDERR "Cannot parse/incomplete coordinates: '$Fields[1]'\n";
      exit 1;
    }
    $Waypoints{$Fields[0]} = {Latitude => $lat,
			      Longitude => $lon,
			      Note => $Fields[2],
			      Comment => $Fields[3]};
    $minlat = $lat if $lat < $minlat;
    $minlon = $lon if $lon < $minlon;
    $maxlat = $lat if $lat > $maxlat;
    $maxlon = $lon if $lon > $maxlon;
  }
}

sub SplitInputLine
{
  my $Line = $_[0];
  my @Fields = ();
  my $comment;
  chomp($Line);

  if ($Line =~ /^\s*\#/) {
    return @Fields;
  }

  return @Fields if (length($Line) == 0);

  if ($Line =~ /.*\#/) {
    $comment = $Line;
    $comment =~ s/.*\#\s*//;
    $Line =~ s/\s*\#.*//;
  }

  if ($Line =~ /\s*([-\w\s\.:]+)\s*,\s*([^,]+)\s*,\s*(.*)/) {
    $Fields[0] = $1;
    $Fields[1] = $2;
    $Fields[2] = $3;
  } elsif ($Line =~ /\s*([-\w\s\.:]+)\s*,\s*([^,]+)\s*/) {
    $Fields[0] = $1;
    $Fields[1] = $2;
  } else {
    print "ERROR: Cannot parse: $Line\n";
    #exit 1;
  }

  $Fields[3] = $comment;

  return @Fields;

}
