#!/usr/bin/perl
#
# Idea from http://www.fishpool.org/archives/200501/index.html - but completely new implemented...
# 
# Author: Wolfgang Dautermann
# License: GPL.
#
# Version from 2014-12-28
# Changes: 2014-12-28: fixed some typos and some Perl::Critic issues

use strict;
use warnings;

use POSIX;
use Getopt::Long; # parse command line arguments
use Pod::Usage;
use Data::Dumper; # for debugging

use constant TRUE  => 1;
use constant FALSE => 0;

sub checkrecordclass {
    my ($class, @record) = @_ ;
    my $recordclass ;
    my $result = FALSE ;
    foreach my $i (@record) {
	$_ = $i ;
	if (/^CLASS:/) {
	    $recordclass = $_ ; $recordclass =~ s/^CLASS:// ; chomp $recordclass;
	    if ($recordclass eq $class) { $result = TRUE }
	} ;
    } ;
    return $result ;
} ;

sub checkrecordcategory {
    my ($category, @record) = @_ ;
    my $recordcategory ;
    my $result = FALSE ;
    foreach my $i (@record) {
	$_ = $i ;
	if (/^CATEGORIES:/) {
	    $recordcategory = $_ ; $recordcategory =~ s/^CATEGORIES:// ; chomp $recordcategory;
	    if ($recordcategory eq $category) { $result = TRUE }
	} ;
    } ;
    return $result ;
} ;

sub checkpercentcomplete {
    my (@record) = @_ ;
    my $item ;
    my $result = FALSE ;
    foreach my $i (@record) {
	$_ = $i ;
	if (/^PERCENT-COMPLETE:/) {
	    $item = $_ ; $item =~ s/^PERCENT-COMPLETE:// ; chomp $item;
	} ;
    } ;
    return $item ; # returns the % value
} ;

sub getrecord_dtstart {
# Attention: Either
# DTSTART;VALUE=DATE:20030825
# or
# DTSTART:20030822T080000Z

    my (@record) = @_ ;
    my $recorddate ;
    my $result = FALSE ;
    foreach my $i (@record) {
	$_ = $i ;
	if (/^DTSTART:/) {
	    $recorddate = $_ ; $recorddate =~ s/^DTSTART:// ; chomp $recorddate;
	} ;
	$_ = $i ;
	if (/^DTSTART;VALUE=DATE:/) {
	    $recorddate = $_ ; $recorddate =~ s/^DTSTART;VALUE=DATE:// ; chomp $recorddate;
	} ;
    } ;
    return substr($recorddate,0,8) ; # returns something like: 20041123  (= the date 2004-11-23)
} ;

sub getrecord_due {
# Attention: Either
# DUE;VALUE=DATE:20041113
# or
# DUE:20030910T185216Z

    my (@record) = @_ ;
    my $recorddate ;
    my $result = FALSE ;
    foreach my $i (@record) {
	$_ = $i ;
	if (/^DUE:/) {
	    $recorddate = $_ ; $recorddate =~ s/^DUE:// ; chomp $recorddate;
	} ;
	$_ = $i ;
	if (/^DUE;VALUE=DATE:/) {
	    $recorddate = $_ ; $recorddate =~ s/^DUE;VALUE=DATE:// ; chomp $recorddate;
	} ;
    } ;
    # there are VTODOS where there is no DUE-date, return nothing in this case...
    if ($recorddate) {
	return substr($recorddate,0,8) ; # returns something like: 20041123  (= the date 2004-11-23). Ignore time.
    } else { return ; } ;
} ;

sub record_setsummary {
    my ($item, @record) = @_ ;
    my ($i, $recordcategory) ;
    my @outputrecord = () ;
    my $result = FALSE ;
    for ($i=0; $i < @record; $i++) {
	$_ = $record[$i] ;
	if (/^SUMMARY:/) {
	    @outputrecord = (@outputrecord, "SUMMARY:$item\n" ) ;
	    while ($record[$i+1] =~ /^\ .*/) { $i ++ ; } ;  # Skip lines beginning with whitespace
	} else {
	    @outputrecord = (@outputrecord, $record[$i]) ;
	} ;
    } ;
    return @outputrecord ;
} ;

sub record_setdescription {
    my ($item, @record) = @_ ;
    my ($i, $recordcategory) ;
    my @outputrecord = () ;
    my $result = FALSE ;
    for ($i=0; $i < @record; $i++) {
	$_ = $record[$i] ;
	if (/^DESCRIPTION:/) {
	    @outputrecord = (@outputrecord, "DESCRIPTION:$item\n" ) ;
	    while ($record[$i+1] =~ /^\ .*/) { $i ++ ; } ;  # Skip lines beginning with whitespace
	} else {
	    @outputrecord = (@outputrecord, $record[$i]) ;
	} ;
    } ;
    return @outputrecord ;
} ;



my ($notbefore,$notafter,$inputfile,$outputfile,$category,$class,$nocategory,$noclass,$help,$verbose,$recordclass,$recordcategory,$excludecompletedtodos,$excludetodos,$duedatenotbefore,$duedatenotafter,$excludeevents,$setsummary,$setdescription) ;

GetOptions ('notbefore=i' => \$notbefore,    # numeric
            'notafter=i'  => \$notafter,      # numeric
	    'duedatenotbefore=i' => \$duedatenotbefore,    # numeric
            'duedatenotafter=i'  => \$duedatenotafter,      # numeric
#            'input=s'  => \$inputfile,      # string
#            'output=s'  => \$outputfile,      # string
            'category=s'  => \$category,      # string
            'class=s'  => \$class,      # string
            'nocategory=s'  => \$nocategory,      # string
            'noclass=s'  => \$noclass,      # string
	    'exclude-completed-todos' => \$excludecompletedtodos,
	    'exclude-todos' => \$excludetodos,
	    'exclude-events' => \$excludeevents,
            'set-summary=s'  => \$setsummary,      # string
            'set-description=s'  => \$setdescription,      # string
	    'help' => \$help,
	    'verbose'  => \$verbose);  # flag

pod2usage(2) if $help;

my $record = undef;


###################################################################
# KOrganizer writes "VERSION:2.0, but Outlook can only read "VERSION:1.0"
# I hope, kOrganizer can read "VERSION:1.0 too..."
###################################################################

print "BEGIN:VCALENDAR\nPRODID:-//K Desktop Environment//NONSGML KOrganizer 3.2.1//EN\nVERSION:1.0\n";
while (<>) {
    my @record = ();
    my $line = $_ ;
    if (/^BEGIN:VEVENT/) {  # VEVENT Record lesen
	while (<>) {
	    my $recordline = $_ ;
	    if ($recordline =~ /^END:VEVENT/) { last ; } ;
	    @record = (@record, $recordline);
	}; # VEVENT is now stored in @record

	# check if @record should be printed.
	my $printrecord = TRUE ;
	# print record, check conditions.
	if ($excludeevents) { $printrecord = FALSE ; } ; # Do not print record if all VEVENTS should be excluded

	if ($class) { if ( ! checkrecordclass($class, @record)) { $printrecord = FALSE ; } ; } ;
	if ($noclass) { if ( checkrecordclass($noclass, @record)) { $printrecord = FALSE ; } ; } ;

	if ($category) { if ( ! checkrecordcategory($category, @record)) { $printrecord = FALSE ; } ; } ;
	if ($nocategory) { if ( checkrecordcategory($nocategory, @record)) { $printrecord = FALSE ; } ; } ;

	my $date = getrecord_dtstart(@record) ;
	if ($notbefore) { if ($date lt $notbefore) { $printrecord = FALSE ; } ; };
	if ($notafter)  { if ($date gt $notafter) { $printrecord = FALSE ; } ; };

	if ($setsummary)     { @record = record_setsummary($setsummary, @record); } ;
	if ($setdescription) { @record = record_setdescription($setdescription, @record); } ;

	if ($printrecord eq TRUE) { print "BEGIN:VEVENT\n", @record, "END:VEVENT\n\n"; }
    } ;



    if (/^BEGIN:VTODO/) {  # read VTODO Record
	while (<>) {
	    my $recordline = $_ ;
	    if ($recordline =~ /^END:VTODO/) { last ; } ;
	    @record = (@record, $recordline);
	}; # VTODO is now in @record
	# check if @record should be printed.
	my $printrecord = TRUE ;
	# print record, check conditions.
	if ($excludetodos) { $printrecord = FALSE ; } ; # Do not print record if all VTODOS should be excluded

	if ($class) { if ( ! checkrecordclass($class, @record)) { $printrecord = FALSE ; } ; } ;
	if ($noclass) { if ( checkrecordclass($noclass, @record)) { $printrecord = FALSE ; } ; } ;

	if ($category) { if ( ! checkrecordcategory($category, @record)) { $printrecord = FALSE ; } ; } ;
	if ($nocategory) { if ( checkrecordcategory($nocategory, @record)) { $printrecord = FALSE ; } ; } ;

	my $date = getrecord_due(@record) ;
	if ($date) { # only if $date is not undef...
	    if ($duedatenotbefore) { if ($date lt $duedatenotbefore) { $printrecord = FALSE ; } ; };
	    if ($duedatenotafter)  { if ($date gt $duedatenotafter) { $printrecord = FALSE ; } ; };
	} ;

#####################################
###### in TODOs - check (and possibly exclude) 100% completed todos.
#####################################
	my $percent = checkpercentcomplete(@record) ;
	if ($excludecompletedtodos) { if ($percent == 100) { $printrecord = FALSE ; } ; };

	if ($setsummary)     { @record = record_setsummary($setsummary, @record); } ;
	if ($setdescription) { @record = record_setdescription($setdescription, @record); } ;

	if ($printrecord eq TRUE) { print "BEGIN:VTODO\n", @record, "END:VTODO\n\n"; } ;
    } ;
}
print "END:VCALENDAR\n";

__END__

=head1 NAME

    filter-ical.pl - Filters ical Entries

=head1 SYNOPSIS

    filter-ical.pl [options]

     Options:
# not implemented yet  - use STDIN     --input
# not implemented yet  - use STDOUT    --output
       --notbefore=YYYYMMDD         do not print VEVENTS before YYYYMMDD
       --notafter=YYYYMMDD          do not print VEVENTS after YYYYMMDD
       --duedatenotbefore=YYYYMMDD  do not print VTODOS with a duedate before YYYYMMDD
       --duedatenotafter=YYYYMMDD   do not print VTODOS with a duedate after YYYYMMDD
       --category=CATEGORY          print only category CATEGORY
       --class=CLASS                print only class CLASS
       --nocategory=CATEGORY        print every category but CATEGORY
       --noclass=CLASS              print every class but CLASS
       --exclude-completed-todos    exclude VTODOS which have PERCENT-COMPLETE:100
       --exclude-todos              exclude all VTODOS
       --exclude-events             exclude all VEVENTS
       --set-summary="Text"         set every summary to "Text" (e.g. "Keine Zeit").
       --set-description="Text"     set every description to "Text" (e.g. "Keine Zeit").
       --help
# not implemented yet       --verbose


=head1 DESCRIPTION

    filter-ical.pl will filter ical-Files according to some restrictions specified
    as command-line parameters.

=head1 AUTHOR
    Wolfgang Dautermann

=head1 LICENSE AND COPYRIGHT
     GPL

=cut
