#!/usr/bin/perl -w

=head1 NAME

dfpilottodo-gtodo - parse a QSF XML file and prepare an XML file for GTodo 

=head1 DATAFREEDOM

These scripts developed from the 'pilot-qof' package but now include
support for other packages and formats and will continue to be extended
along the lines of http://www.data-freedom.org/ - liberating user data 
from the application. Therefore, the datafreedom scripts use a 'df' prefix.

The scripts continue to be developed within the pilot-qof CVS until such
time as the scripts are sufficiently cohesive to form a new source package.

Please feel free to contribute any of your own scripts, under the provisions
of the GNU General Public Licence v3 or later, via the QOF-devel mailing list.
http://lists.sourceforge.net/lists/listinfo/qof-devel

=head1 VERSION

Version 0.0.1

=head1 SYNOPSIS

 dfpilottodo-gtodo FILENAME
 dfpilottodo-gtodo -h|--help|--version

=head1 DESCRIPTION

dfpilottodo-gtodo parses a QSF XML file output by pilot-qof
-d pilot_todo and prepares an XML file suitable for GTodo.

Specify '-' as the filename to parse STDIN.

e.g.
 pilot-qof -x data.xml -d pilot_todo -t 2006-11-09 | dfpilottodo-gtodo -

=head1 OBJECTS

L<http://qof.sourceforge.net/>

L<http://pilot-qof.sourceforge.net/>

=head1 AUTHOR

Neil Williams, C<< <codehelp at debian.org> >>

=head1 BUGS

Please report bugs via the pilot-qof package, either
in the Debian BTS or via SourceForge trackers.

=head1 COPYRIGHT & LICENSE

  Copyright 2007 Neil Williams.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 3 of the License, or
  (at your option) any later version.

  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, see <http://www.gnu.org/licenses/>.

=cut

# need to correlate Number::Format with the Palm Default Currency Table

# need to prepare the GTodo XML file using similar code to QSFWrite.
# see XSL for missing data and required output.

require 5.004;
use strict;
use POSIX qw(locale_h);
use locale;
use Date::Format;
use XML::QOFQSF qw(QSFParse);
use Number::Format qw(:subs :vars);
use Config::Auto;
use File::HomeDir;
use Text::FormatTable;
use Math::BigInt;
use Data::Random qw(:all);

my $our_version = "0.0.1";
sub usageversion {
    print(STDERR <<END)
dfpilottodo-gtodo version $our_version

Usage:
 dfpilottodo-gtodo FILENAME
 dfpilottodo-gtodo -h|--help|--version

Options:
 -h|--help:           print this usage message and exit
 --version:           print this usage message and exit

dfpilottodo-gtodo parses a QSF XML file output by pilot-qof
-d pilot_todo and prepares an XML file suitable for GTodo.

Specify '-' as the filename to parse STDIN.

e.g.
pilot-qof -x data.xml -d pilot_todo -t 2006-11-09 | dfpilottodo-gtodo -

END
        || die "$0: failed to write usage: $!\n";
exit 0;
}

my $stdin = "false";
while( @ARGV ) {
    $_= shift( @ARGV );
    if (/^-$/) {
 		$stdin = "true";
    	next;
    }
    last if m/^--$/;
    if (!/^-/) {
        unshift(@ARGV,$_);
        last;
    }
    if (/^(-h|--help|--version)$/) {
        &usageversion();
        exit( 0 );
    }
}

my $home = File::HomeDir->my_home;
my $datafreedom_dir = "$home/.datafreedom";
mkdir ($datafreedom_dir) if (! -d $datafreedom_dir);
my $cfile = $datafreedom_dir . "/currency";
if (! -f $cfile)
{
	open (CFG, ">$cfile");
	print CFG "\# config file for datafreedom-perl\n";
	print CFG "\# used by xml-invoice\n";
	print CFG "\# Omit the currency symbols when specifying the rate\n";
	print CFG "\# and use . as the decimal point (i.e. locale C).\n";
	print CFG "\# e.g. for a rate of \$15.45\n";
	print CFG "\# weekday_hourly_rate: 15.45\n";
	print CFG "weekday_hourly_rate:\n";
	print CFG "weekend_hourly_rate:\n";
	print CFG "mileage_rate:\n";
	close (CFG);
	die "Cannot create config file $cfile: $!\n" if (! -f $cfile);
}

my $file = "";
$file = "-" if ($stdin eq "true");
$file = $ARGV[0] if ($stdin eq "false");
&usageversion if (!$file);
die "Cannot find $file. Please specify an invoice XML file.\n" 
	if ((! -f $file) && ($file ne '-'));

my $config = Config::Auto::parse("$cfile", format => "colon");
my $rate1 = 0;
$rate1 += $config->{'weekday_hourly_rate'}
	if ($config->{'weekday_hourly_rate'} ne "");
my $rate2 = 0;
$rate2 += $config->{'weekend_hourly_rate'} 
	if ($config->{'weekend_hourly_rate'} ne "");
my $mrate = 0;
$mrate += $config->{'mileage_rate'} 
	if ($config->{'mileage_rate'} ne "");

if (($rate1 == 0) || ($rate2 == 0) || ($mrate == 0))
{
	print "weekday_hourly_rate=$rate1\tweekend_hourly_Rate=$rate2\tmileage_rate=$mrate\n";
	die "Please specify some rates to use in $cfile\n" 
}

my $lconv = POSIX::localeconv();

my %obj = QSFParse("$file");
my $todos = $obj{'pilot_todo'};
my $todo_count = @$todos;

if ($todo_count == 0)
{
	warn "Empty file: $file\n";
	exit(0);
}

my $template = "%A, %o %B %Y";
my $template2 = "%H:%M:%S %P";
my $template3 = "%H hrs, %M mins";
my $currency = "";
$currency = $lconv->{int_curr_symbol} if ($lconv->{int_curr_symbol});
$currency =~ s/ //;
my $symbol = "";
$symbol = $lconv->{currency_symbol} if ($lconv->{currency_symbol});
$symbol =~ s/ //g;
my $hours = 0;
my $charge = 0;
my $miles = 0;
my $materials = 0;
my $decimal_point = ".";
$decimal_point = $lconv->{decimal_point} if ($lconv->{decimal_point});
my $thousands_sep = ",";
$thousands_sep = $lconv->{thousands_sep} if ($lconv->{thousands_sep});

my $amount = new Number::Format(-thousands_sep   => $thousands_sep,
                              -decimal_point   => $decimal_point,
                              -int_curr_symbol => $symbol);

my $table = Text::FormatTable->new('20l 40l');
$table->head('Charge', 'Item');
$table->rule('-');
my $cell = "";
my $cell2 = "";

# process the addressbook details of the contact to be invoiced.
foreach my $c (@$contacts)
{
	$cell = "\nBranch: " . $c->category . ". " . $c->entryCompany . ", ";
	$cell .= $c->entryAddress;
	$table->row('', $cell);
}
# calculate how long the work took and how much to charge
foreach my $a (@$appointments)
{
	my $diff = ($a->end_time - $a->start_time) / 3600;
	$cell = "";
	$cell2 = "";
	$cell .= time2str($template3, ($a->end_time - $a->start_time - 3600));
	$hours += ($a->end_time - $a->start_time) / 3600;
	if (time2str("%w", $a->start_time) ge "6")
	{
		$charge += $diff * $rate2;
		$cell .= " @ " . $amount->format_price($rate2, 2, 2) . "/hr";
		$cell2 .= $amount->format_price(($diff * $rate2), 2, 2);
		$table->row($cell2, $cell);
	}
	else
	{
		$charge += $diff * $rate1;
		$cell .= " @ " . $amount->format_price($rate1, 2, 2) . "/hr";
		$cell2 .= $amount->format_price(($diff * $rate1), 2, 2);
		$table->row($cell2, $cell);
	}
}
$table->rule('');
# Add expenses and mileage claims.
foreach my $e (@$expenses)
{
	$cell2 = "";
	$cell = "Expenses: ";
	if ($e->type_of_expense eq "Mileage")
	{
		$miles += $e->expense_amount;
		$cell .= $e->expense_city . " " . time2str($template, $e->expense_date) . "\n";
		$cell .= $e->expense_amount . " miles @ ";
		$cell .= $amount->format_price($mrate, 2) . "/mile = ";
		$cell2 .= $amount->format_price(($miles * $mrate), 2);
		$table->row($cell2, $cell);
	}
	else
	{
		$materials += $e->expense_amount;
		$cell .= $e->expense_city . " " . time2str($template, $e->expense_date) . "\n";
		warn ("Currency mismatch!" . $currency . ":" . $e->kvp_mnemonic) 
			if ($currency ne $e->kvp_mnemonic);
		$cell .= $e->type_of_expense . ": ";
		$cell2 .= $amount->format_price($e->expense_amount, 2);
		$table->row($cell2, $cell);
	}
}
my $gt = $amount->format_price(($charge + ($miles * $mrate) + $materials), 2);
$table->rule('-');
$table->row($gt, 'Grand Total');
$table->rule('-');
print $table->render(20);
