#!/usr/bin/perl

# Copyright (C) 2010, 2011 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-fetchpqs - download GPX file from geocaching.com

=head1 SYNOPSIS

geo-fetchpqs [options] <PQuery> ...

=head1 DESCRIPTION

Download pocket querys files from geocaching.com

=head1 OPTIONS

  -d|--dir <dir>            Store files in <dir> (default local directory)
  -f|--fixgpx               Run geo-fixgpx with the downloaded GPX file
  -l|--list                 List all for download availbe pocket querys
  -p|--password <password>  Password for geocaching.com
  -u|--user <account>       geocaching.com account
  -q|--quiet                Don't print any status messages
  -r|--rename               Rename gpx files after unpacking
  -x|--unzip                Unzip and delete *.zip files
  --logout                  Logout after download of GPX file
  --dump-config             Write current options as default to config
  --version                 Print version and exit
  --usage                   Print usage
  --man                     Display manual page
  -h|-?                     Help

=cut

use strict;
use warnings;
use Pod::Usage;
use File::Path;
#use File::stat;
use Config::IniFiles;
use GEO::GC;
use Archive::Zip qw(:ERROR_CODES);

#
# process command line arguments
#
use Getopt::Long;
my $help = 0;
my $man = 0;
my $version = 0;
my $usage = 0;
my $dir;
my $dump_config = 0;
my $homedir = '';
my $listpqs = 0;

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-fetchpqs");
  $cfg->newval("geo-fetchpqs", "save_cookies", 1);
  $cfg->WriteConfig($cfgname);
}

my $cfg = new Config::IniFiles(-file => $cfgname,
                               -default => "Global");
if (!$cfg->SectionExists("geo-fetchpqs")) {
  $cfg->AddSection("geo-fetchpqs");
  $cfg->newval("geo-fetchpqs", "save_cookies", 1);
  $cfg->WriteConfig($cfgname);
}
my $save_cookies = $cfg->val("geo-fetchpqs", "save_cookies", 1);
my $sleep = $cfg->val("geo-fetchpqs", "sleep", 6);
my $gcuser = $cfg->val("geo-fetchpqs", "gcuser");
my $gcpassword = $cfg->val("geo-fetchpqs", "gcpassword");
my $quiet = $cfg->val("geo-fetchpqs", "quiet");
my $fixgpx = $cfg->val("geo-fetchpqs", "fixgpx", 0);
my $logout = $cfg->val("geo-fetchpqs", "logout", 0);
my $unzip =  $cfg->val("geo-fetchpqs", "unzip", 0);
my $rename = $cfg->val("geo-fetchpqs", "rename", 0);

GetOptions('d|dir=s' => \$dir,
	   'u|user=s' => \$gcuser,
	   'f:1' => \$fixgpx,
	   'fixgpx!' => \$fixgpx,
	   'p|password=s' => \$gcpassword,
	   'logout!' => \$logout,
	   'l|list' => \$listpqs,
	   'r:1' => \$rename,
	   'rename!' => \$rename,
	   'x:1' => \$unzip,
	   'z:1' => \$unzip,
	   'unzip!' => \$unzip,
	   'dump-config' => \$dump_config,
	   'q' => \$quiet,
	   'quiet!' => \$quiet,
	   '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-fetchpqs (geo-tools) 1.23\n";
  exit;
}

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

my $gc = new GEO::GC(save_cookies => $save_cookies, sleep => $sleep,
		     quiet => $quiet,
		     account => $gcuser, password => $gcpassword);

if ($listpqs) {
  if ($#ARGV >= 0) {
    pod2usage(-exitstatus => 1, -verbose => 0);
  }
  my @pqs = $gc->listpqs();
  if ($#pqs < 0) {
    print "No pocket querys found!\n";
  } else {
    printf "%-30s Waypoints   File Size\n", "Name";
    for (my $i = 0; $i <= $#pqs; $i++) {
      my ($name, $size, $count) = $pqs[$i][0];
      printf "%-30s  %6s    %10s\n", $pqs[$i][0], $pqs[$i][2], $pqs[$i][1];
    }
  }
} else {
  my @PQUERYS;
  if ($#ARGV >= 0) {
    @PQUERYS = (@ARGV);
  }
  else {
    push @PQUERYS, '*';
  }

  mkpath($dir, {verbose => 1, mode => 0755}) if ($dir);

  foreach my $pq (@PQUERYS) {
    my @downloads = $gc->fetchpqs($pq, $dir);

    if ($unzip && $#downloads >= 0) {
      for (my $i = 0; $i <= $#downloads; $i++) {
	my @gpxlist;
	my @gpxlist_end;
	my $zip = Archive::Zip->new();
	my $zipfile = $downloads[$i][1];
	$zipfile = $dir . "/" . $zipfile if $dir;

	my $status = $zip->read($zipfile);
	die "Read of $downloads[$i][0] failed: $status\n" if $status != AZ_OK;

	print "Unpacking $zipfile ...\n" unless $quiet;
	if ($dir) {
	  $zip->extractTree('', "$dir/");
	} else {
	  $zip->extractTree();
	}

	if ($rename) {
	  my @members = $zip->members();
	  foreach my $mem (@members) {
	    my $dst;
	    my $filename = $mem->fileName();
	    $filename = $dir . "/" . $filename if ($dir);

	    if ($filename =~ m/-wpts.gpx/i) {
	      $dst = $downloads[$i][0] . "-wpts.gpx";
	    } else {
	      $dst = $downloads[$i][0] . ".gpx";
	    }
	    $dst = $dir . "/" . $dst if ($dir);
	    print "Rename $filename to $dst ...\n" unless $quiet;
	    rename ($filename, $dst);

	    if ($dst =~ m/-wpts/i) {
	      push @gpxlist_end, $dst;
	    } else {
	      push @gpxlist, $dst;
	    }
	  }
	} else {
	  my @members = $zip->members();
	  foreach my $mem (@members) {
	    my $dst = $mem->fileName();
	    $dst = $dir . "/" . $dst if ($dir);

	    if ($dst =~ m/-wpts/i) {
	      push @gpxlist_end, $dst;
	    } else {
	      push @gpxlist, $dst;
	    }
	  }
	}

	# Delete zip file
	if (unlink ($zipfile) == 0) {
	  print STDERR "Error deleting $zipfile\n";
	} else {
	  print "$zipfile deleted\n" unless $quiet;
	}

	if ($fixgpx) {
	  print "Running geo-fixgpx @gpxlist @gpxlist_end...\n" unless $quiet;
	  system("geo-fixgpx", "--no-warn", "--no-remove-archived",
		 "--no-remove-disabled", "--no-date", "--quiet",
		 @gpxlist, @gpxlist_end);
	  if ($? != 0) {
	    die "Running geo-fixgpx on @gpxlist @gpxlist_end failed!\n";
	  } else {
	    # Remove -mod from filename
	    foreach my $filename (@gpxlist, @gpxlist_end) {
	      my $fixgpx_filename = $filename;
	      $fixgpx_filename =~ s/.gpx$/-mod.gpx/;
	      rename ($fixgpx_filename, $filename);
	    }
	  }
	}
      }
    }
  }
}

if ($logout) {
  $gc->random_sleep($gc->sleep);
  $gc->logout();
}

exit;

sub WriteConfig
{
  $cfg->newval("geo-fetchpqs", "save_cookies", $save_cookies);
  $cfg->newval("geo-fetchpqs", "quiet", $quiet);
  $cfg->newval("geo-fetchpqs", "fixgpx", $fixgpx);
  $cfg->newval("geo-fetchpqs", "unzip", $unzip);
  $cfg->newval("geo-fetchpqs", "rename", $rename);
  $cfg->newval("Global", "gcuser", $gcuser);
  $cfg->newval("Global", "gcpassword", $gcpassword);
  $cfg->newval("Global", "logout", $logout);
  $cfg->newval("Global", "sleep", $sleep);
  $cfg->WriteConfig($cfgname);
}
