#!/usr/bin/perl 
#===============================================================================
#
#         FILE:  gtd.pl
#
#        USAGE:  ./gtd.pl <Options> "<parameters>"
#
#  DESCRIPTION: A desktop command line companion to mobileGTD on a s60 v3 
#               Symbian phone
#
# REQUIREMENTS:  Perl
#       AUTHOR:  Daryn Hanright
#      VERSION:  1.0
#      CREATED:  16/01/09 15:12:18 NZDT
#     REVISION:  ---
#===============================================================================

#    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/>.

use strict;
use warnings;
use Data::Dumper;

my $basedir = "/home/user/gtd";
my $dir = "$basedir/\@Projects";
my %gtd = &readStuff;
#print Dumper %gtd;

my $stuffToDo = $ARGV[0];
my $whatToDo = $ARGV[1];
#$whatToDo = "[SOME TEXT] p:0 a:0 f:Poo s:+";

if (!$whatToDo) {
    $whatToDo = "[] p: a: f: s:";
}

if (!$stuffToDo) {
    $stuffToDo = "help";
}

my ($p) = $whatToDo =~ m@p:(.*?)(\s|$)@g;
my ($a) = $whatToDo =~ m@a:(.*?)(\s|$)@g;
my ($f) = $whatToDo =~ m@f:(.*?)(\s|$)@g;
my ($s) = $whatToDo =~ m@s:(.*?)(\s|$)@g;
my ($text) = $whatToDo =~ m@\[(.*?)\](\s|$)@g;

if ("list" =~ /^$stuffToDo$/i) { listProjects(); }
elsif ("listall" =~ /^$stuffToDo$/i) { listProjectsWithActions(); }
elsif ("listpa" =~ /^$stuffToDo$/i) { listProjectActions($p,$s,$f);}
elsif ("status" =~ /^$stuffToDo$/i) { changeStatusAction($p,$a,$s); }
elsif ("addp" =~ /^$stuffToDo$/i) { addProject ($text); }
elsif ("add" =~ /^$stuffToDo$/i) { addActionToProject ($s,$text,$f,$p); }
elsif ("dela" =~ /^$stuffToDo$/i) { deleteAction ($p,$a); }
elsif ("delp" =~ /^$stuffToDo$/i) { deleteProject ($p); }
elsif ("proj" =~ /^$stuffToDo$/i) { projectProcess ($p,"\@Done"); }
elsif ("review" =~ /^$stuffToDo$/i) { projectProcess ($p,"\@Review"); }
elsif ("defer" =~ /^$stuffToDo$/i) { projectProcess ($p,"\@Someday"); }
elsif ("tickle" =~ /^$stuffToDo$/i) { projectProcess ($p,"\@Tickle"); }
elsif ("actoday" =~ /^$stuffToDo$/i) { actionToday ($p,$a,"\@Today"); }
elsif ("today" =~ /^$stuffToDo$/i) { whatsToday (); }
elsif ("dtoday" =~ /^$stuffToDo$/i) { doneToday ($a); }
elsif ("info" =~ /^$stuffToDo$/i) { addUpdateInfo ($p,$text); }
elsif ("folder" =~ /^$stuffToDo$/i) { changeActionFolder ($p,$a,$f); }
elsif ("projrn" =~ /^$stuffToDo$/i) { renameProject ($p,$text); }
elsif ("other" =~ /^$stuffToDo$/i) { otherStuff (); }
elsif ("act" =~ /^$stuffToDo$/i) { activateProject ($p); }
elsif ("search" =~ /^$stuffToDo$/i) { searchProject ($text); }
elsif ("sync" =~ /^$stuffToDo$/i) { rsyncProject ($text); }
elsif ("backup" =~ /^$stuffToDo$/i) { backupStuff ($text); }
elsif ("help" =~ /^$stuffToDo$/i) { helpStuff(); }
else { helpStuff(); }

sub helpStuff {
    print "A MobileGTD command line companion written in Perl\n";
    print "By Daryn Hanright\n";
    print "Usage: gtd.pl <Options> \"<parameters>\"\n";
    print "==================================================\n";
    print "Options:\n";
    print "     list - list all projects\n";
    print "     listall - list all projects with actions\n";
    print "     listpa - list all actions for a given project. Can be filtered by status & folder - parameters: p,s,f\n";
    print "     status - change status of action in given project - parameters: p,a,s\n";
    print "     add - add action to project - parameters: [TEXT],p,f,s\n";
    print "     addp - add project - parameters: [TEXT]\n";
    print "     dela - delete action from given project - parameters: p,a\n";
    print "     delp - delete project - parameters: p\n";
    print "     proj - move project to \@Done - parameters: p\n";
    print "     review - move project to \@Review - parameters: p\n";
    print "     defer - move project to \@Someday - parameters: p\n";
    print "     tickle - move project to \@Tickle - parameters: p\n";
    print "     actoday - copy action to \@Today - parameters: p,a\n";
    print "     today - what actions am I doing today\n";
    print "     dtoday - action done today - parameters: a\n";
    print "     projrn - rename project - parameters: p,[TEXT]\n";
    print "     info - add/update info of project - parameters: p,[TEXT]\n";
    print "     other - list projects deferred, in review etc etc\n";
    print "     act - activate project from other - parameters: p\n";
    print "     search - does a basic grep of projects - parameters: [TEXT]\n";
    print "     sync - does a sync of 2 gtd folders using unison - parameters: [TEXT]\n";
    print "     backup - copies using rsync gtd folders to another folder - parameters: [TEXT]\n";
    print "     folder - change folder of action in given project - parameters: p,a,f\n";
    print "\n";
    print "parameters:\n";
    print "     p:<n> - project number\n";
    print "     a:<n> - action number\n";
    print "     s:+/-/! - status of project\n";
    print "     f:<n> - folder of project\n";
    print "     [TEXT] - text to be added\n";
    print "\n";
    print "Example usages:\n";
    print "list actions in given project:\n";
    print "     gtd.pl listpa \"p:0\"\n";
    print "list actions in given project within a folder:\n";
    print "     gtd.pl listpa \"p:0 f:FolderName\"\n";
    print "list actions in given project given a status:\n";
    print "     gtd.pl listpa \"p:0 s:+\"\n";
    print "add an action to a project:\n";
    print "     gtd.pl add \"p:0 f:FolderName s:- [this is a test action]\"\n";
    print "delete an action from a project:\n";
    print "     gtd.pl dela \"p:0 a:2\"\n";
    print "add a project:\n";
    print "     gtd.pl addp \"[project name]\"\n";
    print "change status of action:\n";
    print "     gtd.pl status \"p:0 a:2 s:-\"\n";
    print "change folder of action:\n";
    print "     gtd.pl folder \"p:0 a:2 f:NewFolderName\"\n";
    print "copy action to \@Today:\n";
    print "     gtd.pl actoday \"p:0 a:2\"\n";
    print "view actions today:\n";
    print "     gtd.pl today\n";
    print "done action from today (get num from 'gtd.pl today'):\n";
    print "     gtd.pl dtoday \"a:0\"\n";
    print "\n";
}

# TODO

sub rsyncProject {
    my ($mount) = @_;
    print "sudo unison $basedir $mount\n";
    system ("sudo unison $basedir $mount");
}

sub backupStuff {
    my ($mount) = @_;
    print "sudo rsync -capz $basedir $mount\n";
    system ("sudo rsync -capz $basedir $mount");
}

sub searchProject {
    my ($term) = @_;
    system ("grep -i $term $dir\/*.prj");
}


sub whatsToday {
    opendir (D1, "$basedir/\@Today");
    my @f1 = readdir(D1);
    closedir (D1);
    my $i = 0;
    foreach my $t1 (@f1) {
        my ($matching) = $t1 =~ m@\.act$@g;
        if ($matching) {
            $t1 =~ s@.act@@g;
            print "\[$i\] $t1\n";
            $i++;
        }
    }
}

sub doneToday {
    my ($actionPassed) = @_;
    opendir (D1, "$basedir/\@Today");
    my @f1 = readdir(D1);
    closedir (D1);
    my $i = 0;
    foreach my $t1 (@f1) {
        my ($matching) = $t1 =~ m@\.act$@g;
        if ($matching) {
            if ($actionPassed == $i) {
                unlink ("$basedir/\@Today/$t1");
            }
            $i++;
        }
    }
}

sub otherStuff {
    my @all = &getOtherStuff();    
    my $num = 0;
    foreach my $files (@all) {
        my ($matching) = $files =~ m@\.prj$@g;
        if ($matching) {
            my ($dir,$fileName) = split '\^',$files;
            print "\[$num\] $dir - $fileName\n";
            $num++;
        }
    }
}

sub activateProject {
    my ($countPassed) = @_;
    my @all = &getOtherStuff();
    my $num = 0;
    foreach my $files (@all) {
        my ($matching) = $files =~ m@\.prj$@g;
        if ($matching) {
            my ($dirTemp,$fileName) = split '\^',$files;
            if ($num == $countPassed) { 
                system ("mv $dir/$dirTemp/$fileName $dir");
            }
            $num++;
        }
    }
}

sub getOtherStuff {
    opendir (D1, "$dir/\@Review");
    my @f1 = readdir(D1);
    closedir (D1);
    my $i = 0;
    foreach my $t1 (@f1) {
        $f1[$i] = "\@Review^" . $t1;
        $i++;
    }
    opendir (D2, "$dir/\@Done");
    my @f2 = readdir(D2);
    closedir (D2);
    $i = 0;
    foreach my $t2 (@f2) {
        $f2[$i] = "\@Done^" . $t2;
        $i++;
    }
    opendir (D3, "$dir/\@Someday");
    my @f3 = readdir(D3);
    closedir (D3);
    $i = 0;
    foreach my $t3 (@f3) {
        $f3[$i] = "\@Someday^" . $t3;
        $i++;
    }
    opendir (D4, "$dir/\@Tickle");
    my @f4 = readdir(D4);
    closedir (D4);
    $i = 0;
    foreach my $t4 (@f4) {
        $f4[$i] = "\@Tickle^" . $t4;
        $i++;
    }
    my @all = (@f1,@f2,@f3,@f4);
    return @all;
}

sub readStuff {
    opendir (DIR, $dir);
    my @FILES = readdir(DIR);
    closedir(DIR);
    my %gtd = ();
    my @gtdData = ();
    my $i = 0;
    foreach my $files (@FILES) {
        my ($matching) = $files =~ m@\.prj$@g;
        if ($matching) {
            open (DAT, $dir."/".$files) || die ("Could not open file");
            $files =~ s@\.prj@@g; 
            @gtdData=<DAT>;
            for ($i = 0; $i < @gtdData; $i++) {
                my $data = $gtdData[$i];
                my ($status) = $data =~ m@^[+-]\s+@g;
                my ($folder) = $data =~ m@^[+-]\s+(.*?)\s+@g;
                my $tempdata = $data;
                $tempdata =~ s@^[+-]\s+@@g;
                if ($folder) {
                    $tempdata =~ s@^$folder@@g;
                }
                $tempdata =~ s/^\s+//;
                $tempdata =~ s/\s+$//;
                if ($status) {
                    $status =~ s/^\s+//;
                    $status =~ s/\s+$//;
                    my ($testi) = $i =~ m@^\d$@;
                    if ($testi) {
                        $i = "0" . $i;
                    }
                    $gtd{$files}{$i}{"status"} = $status; 
                    $gtd{$files}{$i}{"action"} = $tempdata;
                    $gtd{$files}{$i}{"folder"} = $folder;
                } else {
                    $gtd{$files}{$i}{"do"} = $data; 
                }
            }
            close(DAT);
            $i = 0;
        }
    }
    return %gtd;
}

# list all projects
sub listProjects {
    my $countProjects2 = 0;
    print "======================================\n";
    print "Current Projects\n";
    while (my ( $key, $value ) = each(%gtd)) {
        print "\[$countProjects2\] - $key\n";
        $countProjects2++;
    }
    print "\n";
}

sub addProject {
    my ($title) = @_;
    my $file = $dir . "/" . $title . ".prj";
    open (DAT, ">$file") || die ("Could not open file");
    print DAT "# DO: put desctiption of project here\n";
    close(DAT);
}

sub renameProject {
    my ($countPassed,$newProjectName) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    foreach my $key3 (sort (keys(%$project))) {
        my $entryStatus = $project->{$key3}->{"status"};
        my $entryAction = $project->{$key3}->{"action"};
        my $entryFolder = $project->{$key3}->{"folder"};
        if ($key3 == $countPassed) {
            my $projFile = $dir."/".$newProjectName.".prj";
            unlink ($dir."/".$projectName.".prj");
            printProject($projFile, %$project);
            printAction($entryStatus,$entryAction,$entryFolder,$newProjectName);
        }
    }
}

# list all projects with actions
sub listProjectsWithActions {
    my $countProjects = 0;
    while (my ( $key, $value ) = each(%gtd)) {
        print "======================================\n";
        print "$countProjects - $key\n";
        foreach my $key3 (sort (keys(%$value))) {
            my $entryStatus = $value->{$key3}->{"status"};
            my $entryAction = $value->{$key3}->{"action"};
            my $entryFolder = $value->{$key3}->{"folder"};
            my $entryDo = $value->{$key3}->{"do"};
            if ($entryDo) {
                print "$entryDo";
            } else {
                print "\[$key3\] $entryStatus $entryAction ($entryFolder)\n";
            }
        }
        print "\n";
        $countProjects++;
    }
}

# list given project with actions
# example - list project 0
sub listProjectActions {
    my ($countPassed,$statusPassed,$folderPassed) = @_;
    if (!$statusPassed) {
        $statusPassed = "all";
    }
    if (!$folderPassed) {
        $folderPassed = "all";
    }
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    print "======================================\n";
    print "Project: \[$countPassed\] $projectName\n";
    foreach my $key3 (sort (keys(%$project))) {
        my $entryStatus = $project->{$key3}->{"status"};
        my $entryAction = $project->{$key3}->{"action"};
        my $entryFolder = $project->{$key3}->{"folder"};
        my $entryDo = $project->{$key3}->{"do"};
        if ($entryDo) {
            print "$entryDo\n";
        } else {
            if (($statusPassed eq $entryStatus) && ($folderPassed eq $entryFolder)) {
                print "\[$key3\] $entryStatus $entryAction ($entryFolder)\n";
            } 
            if (($statusPassed eq $entryStatus) && ($folderPassed eq "all")) {
                print "\[$key3\] $entryStatus $entryAction ($entryFolder)\n";
            }
            if (($folderPassed eq $entryFolder) && ($statusPassed eq "all")){
                print "\[$key3\] $entryStatus $entryAction ($entryFolder)\n";
            }
            if (($statusPassed eq "all") && ($folderPassed eq "all")){
                print "\[$key3\] $entryStatus $entryAction ($entryFolder)\n";
            }
        }
    }
    print "======================================\n";
}

# change status of action within project
sub changeStatusAction {
    my ($countPassed,$actionPassed,$actionChange) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    foreach my $key3 (sort (keys(%$project))) {
        my $entryStatus = $project->{$key3}->{"status"};
        my $entryAction = $project->{$key3}->{"action"};
        my $entryFolder = $project->{$key3}->{"folder"};
        if ($key3 == $actionPassed) {
            my $projFile = $dir."/".$projectName.".prj";
            $project->{$key3}->{"status"} = $actionChange;
            printProject($projFile, %$project);
            printAction($actionChange,$entryAction,$entryFolder,$projectName);
        }
    }
}

sub changeActionFolder {
    my ($countPassed,$actionPassed,$folderChange) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    foreach my $key3 (sort (keys(%$project))) {
        my $entryStatus = $project->{$key3}->{"status"};
        my $entryAction = $project->{$key3}->{"action"};
        my $entryFolder = $project->{$key3}->{"folder"};
        if ($key3 == $actionPassed) {
            my $projFile = $dir."/".$projectName.".prj";
            my $oldFolder = $project->{$key3}->{"folder"};
            $project->{$key3}->{"folder"} = $folderChange;
            printProject($projFile, %$project);
            if (-d $basedir . "/" . $folderChange) {
                # print "everything cool";
            } else {
                mkdir $basedir . "/" . $folderChange or die;
            }
            $entryAction =~ s@ @\\ @g;

            system ("mv " . $basedir . "/" . $oldFolder . "/" . $entryAction . ".act " .  $basedir . "/" . $folderChange);
        }
    }
}

# delete action
sub deleteAction {
    my ($countPassed,$actionPassed) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    foreach my $key3 (sort (keys(%$project))) {
        my $entryStatus = $project->{$key3}->{"status"};
        my $entryAction = $project->{$key3}->{"action"};
        my $entryFolder = $project->{$key3}->{"folder"};
        if ($key3 == $actionPassed) {
            delete $project->{$key3}; 
            my $projFile = $dir."/".$projectName.".prj";
            printProject($projFile, %$project);
            unlink ($basedir."/".$entryFolder."/".$entryAction.".act");
        }
    }
}

# delete project
sub deleteProject {
    my ($countPassed) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    my $projFile = $dir."/".$projectName.".prj";
    unlink ($projFile);
}

sub addUpdateInfo {
    my ($countPassed, $info) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    my $projFile = $dir."/".$projectName.".prj";
    my $data = '';
    open (FILE, "<$projFile");
    read FILE, $data, 100000;
    close FILE;
    open (FILE, ">$projFile");
    my ($matchDO) = $data =~ m@^#\sDO:(.*)@g;
    if ($matchDO) {
        $data =~ s@$matchDO@ $info@g;
        print FILE $data;
    } else {
        print FILE "# DO: " . $info . "\n" . $data;
    }
    close FILE;
}

sub projectProcess {
    my ($countPassed,$folder) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    my $projFile = $dir."/".$projectName.".prj";
    if (-d $dir . "/$folder") {
        #print "everything good";
    } else {
        mkdir $dir . "/$folder" or die;
    }
    system ("mv $projFile $dir/$folder");
}

sub actionToday {
    my ($countPassed, $actionPassed, $folder) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ($countPassed == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $project = $gtd{$projectName};
    if (-d $basedir . "/$folder") {
        #print "everything good";
    } else {
        mkdir $basedir . "/$folder" or die;
    }
    foreach my $key3 (sort (keys(%$project))) {
        my $entryStatus = $project->{$key3}->{"status"};
        my $entryAction = $project->{$key3}->{"action"};
        my $entryFolder = $project->{$key3}->{"folder"};
        $entryAction =~ s@ @\\ @g;
        if ($key3 == $actionPassed) {
            system ("cp $basedir/$entryFolder/$entryAction.act $basedir/$folder");
        }
    }
}

# print out project
sub printProject {
    my ($passedFile, %passedGTD) = @_;
    my $tempFile = $passedFile;
    $tempFile =~ s@ @\\ @g;
    #print "$passedFile";
    #system ("cp $tempFile $tempFile.bak");
    open (DAT, ">$passedFile") || die ("Could not open file");
    foreach my $key3 (sort (keys(%passedGTD))) {
        my $projStatus = $passedGTD{$key3}{"status"};
        my $projAction = $passedGTD{$key3}{"action"};
        my $projFolder = $passedGTD{$key3}{"folder"};
        my $projDo = $passedGTD{$key3}{"do"};
        if ($key3 == 0) {
            print DAT "$projDo";
        } else {
            print DAT "$projStatus $projFolder $projAction\n";
        }
    }
    close(DAT);
}

sub printAction {
    my ($entrystatus,$entryaction,$entryfolder,$projectname) = @_;
    #$entryaction =~ s@ @\\ @g;
    my $file = $basedir . "/" . $entryfolder . "/" . $entryaction . ".act";
    open (DAT, ">$file") || die ("Could not open file");
    print DAT "$entrystatus $entryfolder $entryaction\n";
    print DAT "Project: $projectname";
    close(DAT);
}

sub addActionToProject {
    my ($entrystatus,$entryaction,$entryfolder,$projectcount) = @_;
    my $countProjects = 0;
    my $projectName = '';
    while (my $key = each(%gtd)) {
        if ( $projectcount == $countProjects) {
            $projectName = $key;
        }
        $countProjects++;
    }
    my $proj = $dir."/".$projectName.".prj";
    my $file = $basedir . "/" . $entryfolder . "/" . $entryaction . ".act";
    if (-d $basedir . "/" . $entryfolder) {
        # print "everything cool";
    } else {
        mkdir $basedir . "/" . $entryfolder or die;
    }
    open (FILE, ">>$proj") || die ("Could not open file");
    print FILE "$entrystatus $entryfolder $entryaction\n";
    close(FILE);
    open (DAT, ">$file") || die ("Could not open file");
    print DAT "$entrystatus $entryfolder $entryaction\n";
    print DAT "Project: $projectName";
    close(DAT);
}
