#!/usr/bin/perl
use strict;
use Tk;
use Tk::ROText;
use Getopt::Long;
use DBI;

my (%title, %description, %priority, %taskid, %offset,
    $app, $menubar, $filemenu, $itemmenu, $helpmenu, $listbox, $textfield);

my $dotfile = sprintf('%s/.muchtodo', $ENV{HOME});
my %opts = get_prefs($dotfile) if (-f $dotfile);

list_options(\%opts);
my $userid = get_or_insert_user();


GetOptions(\%opts,
           'delay=i',
           'geometry=s',
           'verbose');

apply_defaults(\%opts);
list_options(\%opts) if ($opts{verbose});

main();

select(undef,undef,undef,$opts{delay}) if defined($opts{delay});

MainLoop();
quit();


sub main
{
    my ($grid_width, $tot_width, $scroll_width);

    if (defined $opts{scrollwidth} && $opts{scrollwidth} =~ /(\d+)\/(\d+)/)
    {
        $grid_width = $2;
        $tot_width = sprintf('%%%d', $2);
        $scroll_width = sprintf('%%%d', $1);
    }
    else
    {
        ($grid_width, $tot_width, $scroll_width) = (40, '%40', '%10');
    }

    $app = MainWindow->new();
    $app -> geometry($opts{geometry});
    $app -> configure(-background => 'white');
    $app -> title("Much To Do About Nothing");
    $app -> formGrid($grid_width,30);

    ($menubar = $app->Frame()) -> form(-in	=> $app,
                                       -fill	=> 'both',
                                       -left	=> '%0',
                                       -right	=> $tot_width,
                                       -top	=> '%0');

    $menubar -> configure(-background => 'white');

    ($filemenu = $menubar->Menubutton(-text		=> 'File',
                                      -activebackground	=> 'yellow',
                                      -relief		=> 'raised',
                                      -tearoff		=> 0,
                                      -borderwidth	=> 2)) -> pack (-side => 'left',
                                                                        -padx => 2,
                                                                        -pady => 2);

    $filemenu->command(-label		=> 'Quit',
                       -accelerator	=> 'Alt+Q',
                       -underline	=> 0,
                       -command		=> \&quit);

    ($itemmenu = $menubar->Menubutton(-text		=> 'Reminders',
                                      -activebackground	=> 'yellow',
                                      -relief   	=> 'raised',
                                      -tearoff		=> 0,
                                      -borderwidth	=> 2)) -> pack (-side => 'left',
                                                                        -padx => 2);

    $itemmenu->command(-label		=> 'New',
                       -accelerator	=> 'Alt+N',
                       -underline	=> 0,
                       -command		=> \&add_reminder);


    $itemmenu->command(-label		=> 'Edit',
                       -accelerator	=> 'Alt+E',
                       -underline	=> 0,
                       -command		=> \&listbox_dclick_event);


    $itemmenu->command(-label		=> 'Delete',
                       -accelerator	=> 'Alt+D',
                       -underline	=> 0,
                       -command		=> \&listbox_delete_event);

    $itemmenu->command(-label		=> 'Reload All',
                       -accelerator	=> 'Alt+R',
                       -underline	=> 0,
                       -command		=> \&reload_tasks);

    ($helpmenu = $menubar->Menubutton(-text		=> 'Help',
                                      -activebackground	=> 'yellow',
                                      -relief   	=> 'raised',
                                      -tearoff		=> 0,
                                      -borderwidth	=> 2)) -> pack (-side => 'right',
                                                                        -padx => 2);

    $helpmenu->command(-label		=> 'About',
                       -accelerator	=> 'Alt+A',
                       -underline	=> 0,
                       -command		=> \&about);

    ($listbox = $app->Scrolled('Listbox',
                               -background		=> 'white',
                               -selectbackground	=> 'yellow',
                               -scrollbars		=> 'ow',
                               -font			=> $opts{font},
                               -width			=> 25,
                               -height			=> 12)) -> form(-in	=> $app,
                                                                        -fill	=> 'both',
                                                                        -left	=> ['%0',5],
                                                                        -right	=> $scroll_width,
                                                                        -top	=> ['%0',32],
                                                                        -bottom	=> ['%30',-5]);

    $listbox->bind('<1>', \&listbox_click_event);
    $listbox->bind('<Double-1>', \&listbox_dclick_event);

    ($textfield = $app->Scrolled('ROText',
                                 -background		=> 'white',
                                 -selectbackground	=> 'white',
                                 -scrollbars		=> 'ow',
                                 -font			=> $opts{boldfont},
                                 -width			=> 50,
                                 -height		=> 15,
                                 -padx			=> 5,
                                 -pady			=> 5,
                                 -wrap			=> 'word')) -> form(-in		=> $app,
                                                                            -fill	=> 'both',
                                                                            -left	=> $scroll_width,
                                                                            -right	=> [$tot_width,-5],
                                                                            -top	=> ['%0',32],
                                                                            -bottom	=> ['%30',-5]);

    $app->bind('<Alt-a>' => \&about);
    $app->bind('<Alt-d>' => \&listbox_delete_event);
    $app->bind('<Alt-e>' => \&listbox_dclick_event);
    $app->bind('<Alt-n>' => \&add_reminder);
    $app->bind('<Alt-q>' => \&quit);
    $app->bind('<Control-q>' => \&quit);
    $app->bind('<Alt-r>' => \&reload_tasks);

    reload_tasks();
    $listbox->selectionSet(0,0);
}


sub delete_reminder
{
    my ($taskid) = @_;
    my ($dialog, $title, $sure, $okbutton, $cancelbutton, $timer);

    $dialog = MainWindow->new();
    $dialog -> title("Delete Reminder");
    $dialog -> configure(-background => 'white');
    $dialog -> formGrid(10,3);

    ($title = $dialog->Label(-text		=> sprintf('Delete %s', $title{$taskid}),
                             -font		=> $opts{boldfont},
                             -foreground	=> '#666699', 
                             -background	=> 'white', 
                             -anchor		=> 'center', 
                             -relief		=> 'flat', 
                             -width		=> 30, 
                             -height		=> 1)) -> form(-in	=> $dialog,
                                                               -fill	=> 'both',
                                                               -left	=> ['%0',5],
                                                               -right	=> ['%10',-5],
                                                               -top	=> ['%0',5],
                                                               -bottom	=> ['%1',-5]);

    ($sure = $dialog->Label(-text		=> 'Are You Sure?', 
                             -font		=> $opts{boldfont},
                             -foreground	=> 'red', 
                             -background	=> 'white', 
                             -anchor		=> 'center', 
                             -relief		=> 'flat', 
                             -width		=> 30, 
                             -height		=> 1)) -> form(-in	=> $dialog,
                                                               -fill	=> 'both',
                                                               -left	=> ['%0',5],
                                                               -right	=> ['%10',-5],
                                                               -top	=> ['%1',5],
                                                               -bottom	=> ['%2',-5]);

    ($okbutton = $dialog->Button(-text			=> 'Kill It!',
                                 -command		=> sub {
                                                                   $textfield->delete('1.0', 'end');
                                                                   $listbox->delete('active');
                                                                   delete_task($userid, $taskid);
                                                                   reload_tasks();
                                                                   $listbox->selectionSet(0,0);
                                                                   $timer = $okbutton->after(10, sub { $dialog->destroy(); } );
                                                               },
                                 -activebackground	=> 'red',
                                 -anchor		=> 'center',
                                 -relief		=> 'raised',
                                 -width			=> 4,
                                 -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%2',-25],
                                                                       -right	=> ['%5',-5],
                                                                       -top	=> ['%2',5],
                                                                       -bottom	=> ['%3',-5]);

    ($cancelbutton = $dialog->Button(-text		=> 'Never Mind',
                                     -command		=> sub {
                                                                  $timer = $okbutton->after(10, sub { $dialog->destroy(); } );
                                                               },
                                     -activebackground	=> 'yellow',
                                     -anchor		=> 'center',
                                     -relief		=> 'raised',
                                     -width		=> 4,
                                     -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%5',5],
                                                                       -right	=> ['%8',25],
                                                                       -top	=> ['%2',5],
                                                                       -bottom	=> ['%3',-5]);

    $dialog->bind('<Control-w>' => sub { $dialog->destroy(); });
}


sub add_reminder
{
    my ($dialog, $label, $label2, $title, $textbox, $radio1, $radio2, $radio3, $radio4, $radio5,
        $priority, $okbutton, $cancelbutton, $reminder, $text, $timer);

    $dialog = MainWindow->new();
    $dialog -> title("New Reminder");
    $dialog -> configure(-background => 'white');
    $dialog -> geometry("500x500");
    $dialog -> formGrid(10,10);

    ($label = $dialog->Label(-text		=> 'Title and Priority:',
                             -font		=> $opts{boldfont},
                             -foreground	=> 'blue', 
                             -background	=> 'white', 
                             -anchor		=> 'w', 
                             -relief		=> 'flat', 
                             -width		=> 24, 
                             -height		=> 1)) -> form(-in	=> $dialog,
                                                               -fill	=> 'both',
                                                               -left	=> ['%0',5],
                                                               -right	=> ['%4',-5],
                                                               -top	=> ['%0',5],
                                                               -bottom	=> ['%0',35]);

    ($title = $dialog->Text(-width		=> 20, 
                            -height		=> 1,
                            -background		=> 'white',
                            -selectbackground	=> 'yellow',
                            -font		=> $opts{boldfont},
                            -wrap		=> 'none')) -> form(-in		=> $dialog,
                                                                    -fill	=> 'both',
                                                                    -left	=> ['%4'],
                                                                    -right	=> ['%10',-5],
                                                                    -top	=> ['%0',5],
                                                                    -bottom	=> ['%0',35]);

    ($radio1 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Highest',
                                    -value		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%0',5],
                                                                       -right	=> ['%2'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio2 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'High',
                                    -value		=> 2)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%2'],
                                                                       -right	=> ['%4'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio3 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Medium',
                                    -value		=> 3)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%4'],
                                                                       -right	=> ['%6'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio4 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Low',
                                    -value		=> 4)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%6'],
                                                                       -right	=> ['%8'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio5 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Lowest',
                                    -value		=> 5)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%8'],
                                                                       -right	=> ['%10',-5],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    $radio3->select;

    ($textbox = $dialog->Scrolled('Text',
                                  -width		=> 50, 
                                  -padx			=> 5, 
                                  -pady			=> 5, 
                                  -height		=> 1,
                                  -background		=> 'white',
                                  -selectbackground	=> 'yellow',
                                  -scrollbars		=> 'ow',
                                  -font			=> $opts{boldfont},
                                  -wrap			=> 'word')) -> form(-in		=> $dialog,
                                                                            -fill	=> 'both',
                                                                            -left	=> ['%0',5],
                                                                            -right	=> ['%10',-5],
                                                                            -top	=> ['%0',75],
                                                                            -bottom	=> ['%10',-35]);


    ($okbutton = $dialog->Button(-text			=> 'OK',
                                 -command		=> sub {
                                                                   chomp($reminder = $title->get('1.0', 'end'));
                                                                   chomp($text = $textbox->get('1.0', 'end'));
                                                                   insert_task($userid, $reminder, $priority, $text);
                                                                   reload_tasks();
                                                                   load_reminder($taskid{$reminder});
                                                                   select_reminder($reminder);
                                                                   $timer = $okbutton->after(10, sub { $dialog->destroy(); } );
                                                               },
                                 -activebackground	=> 'green',
                                 -anchor		=> 'center',
                                 -relief		=> 'raised',
                                 -width			=> 4,
                                 -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%3',5],
                                                                       -right	=> ['%5',-5],
                                                                       -top	=> ['%10',-30],
                                                                       -bottom	=> ['%10',-5]);

    ($cancelbutton = $dialog->Button(-text		=> 'Cancel',
                                     -command		=> sub { $timer = $okbutton->after(10, sub { $dialog->destroy(); } ); },
                                     -activebackground	=> 'yellow',
                                     -anchor		=> 'center',
                                     -relief		=> 'raised',
                                     -width		=> 4,
                                     -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%5',5],
                                                                       -right	=> ['%7',-5],
                                                                       -top	=> ['%10',-30],
                                                                       -bottom	=> ['%10',-5]);

    $dialog->bind('<Control-w>' => sub { $dialog->destroy(); });
}


sub edit_reminder
{
    my ($taskid) = @_;
    my ($dialog, $title, $titlebox, $textbox, $okbutton, $cancelbutton, $savebutton,
        $text, $priority, $label1, $label2, $radio1, $radio2, $radio3, $radio4, $radio5,
        $timer);

    $title = $title{$taskid};
    $priority = $priority{$taskid};
    $text = $description{$taskid};

    $dialog = MainWindow->new();
    $dialog -> title(sprintf("Edit '%s'", $title));
    $dialog -> configure(-background => 'white');
    $dialog -> geometry("500x500");
    $dialog -> formGrid(10,10);

    ($label1 = $dialog->Label(-text		=> 'Title and Priority:',
                              -font		=> $opts{boldfont},
                              -foreground	=> 'blue', 
                              -background	=> 'white', 
                              -anchor		=> 'w', 
                              -relief		=> 'flat', 
                              -width		=> 8, 
                              -height		=> 1)) -> form(-in	=> $dialog,
                                                               -fill	=> 'both',
                                                               -left	=> ['%0',5],
                                                               -right	=> ['%4',-5],
                                                               -top	=> ['%0',5],
                                                               -bottom	=> ['%0',35]);

    ($titlebox = $dialog->Text(-width		=> 20, 
                            -height		=> 1,
                            -background		=> 'white',
                            -selectbackground	=> 'yellow',
                            -font		=> $opts{boldfont},
                            -wrap		=> 'none')) -> form(-in		=> $dialog,
                                                                    -fill	=> 'both',
                                                                    -left	=> ['%4'],
                                                                    -right	=> ['%10',-5],
                                                                    -top	=> ['%0',5],
                                                                    -bottom	=> ['%0',35]);

    $titlebox->Contents($title{$taskid});

    ($radio1 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Highest',
                                    -value		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%0',5],
                                                                       -right	=> ['%2'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio2 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'High',
                                    -value		=> 2)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%2'],
                                                                       -right	=> ['%4'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio3 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Medium',
                                    -value		=> 3)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%4'],
                                                                       -right	=> ['%6'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio4 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Low',
                                    -value		=> 4)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%6'],
                                                                       -right	=> ['%8'],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($radio5 = $dialog->Radiobutton(-variable		=> \$priority,
                                    -foreground		=> 'black', 
                                    -background		=> 'white', 
                                    -activebackground	=> 'yellow', 
                                    -activeforeground	=> 'blue', 
                                    -selectcolor	=> 'red', 
                                    -relief		=> 'flat', 
                                    -text		=> 'Lowest',
                                    -value		=> 5)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%8'],
                                                                       -right	=> ['%10',-5],
                                                                       -top	=> ['%0',40],
                                                                       -bottom	=> ['%0',70]);

    ($textbox = $dialog->Scrolled('Text',
                                  -width		=> 50, 
                                  -height		=> 12,
                                  -padx			=> 5, 
                                  -pady			=> 5, 
                                  -background		=> 'white',
                                  -selectbackground	=> 'yellow',
                                  -scrollbars		=> 'ow',
                                  -font			=> $opts{boldfont},
                                  -wrap			=> 'word')) -> form(-in		=> $dialog,
                                                                            -fill	=> 'both',
                                                                            -left	=> ['%0',5],
                                                                            -right	=> ['%10',-5],
                                                                            -top	=> ['%0',75],
                                                                            -bottom	=> ['%10',-35]);

    $textbox->insert('1.0', $text);

    ($okbutton = $dialog->Button(-text			=> 'OK',
                                 -command		=> sub {
                                                                   chomp($title = $titlebox->Contents());
                                                                   chomp($text = $textbox->Contents());
                                                                   update_task($userid, $taskid, $title, $priority, $text);
                                                                   reload_tasks();
                                                                   load_reminder($taskid{$title});
                                                                   select_reminder($title);
                                                                   $timer = $okbutton->after(10, sub { $dialog->destroy(); } );
                                                               },
                                 -activebackground	=> 'green',
                                 -anchor		=> 'center',
                                 -relief		=> 'raised',
                                 -width			=> 4,
                                 -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%2',10],
                                                                       -right	=> ['%4',-10],
                                                                       -top	=> ['%10',-30],
                                                                       -bottom	=> ['%10',-5]);

    ($savebutton = $dialog->Button(-text		=> 'Update',
                                   -command		=> sub {
                                                                   chomp($title = $titlebox->Contents());
                                                                   chomp($text = $textbox->Contents());
                                                                   update_task($userid, $taskid, $title, $priority, $text);
                                                                   reload_tasks();
                                                                   load_reminder($taskid{$title});
                                                                   select_reminder($title);
                                                               },
                                   -activebackground	=> 'cyan',
                                   -anchor		=> 'center',
                                   -relief		=> 'raised',
                                   -width		=> 4,
                                   -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%4',10],
                                                                       -right	=> ['%6',-10],
                                                                       -top	=> ['%10',-30],
                                                                       -bottom	=> ['%10',-5]);

    ($cancelbutton = $dialog->Button(-text		=> 'Cancel',
                                     -command		=> sub { $timer = $okbutton->after(10, sub { $dialog->destroy(); } ); },
                                     -activebackground	=> 'yellow',
                                     -anchor		=> 'center',
                                     -relief		=> 'raised',
                                     -width		=> 4,
                                     -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%6',10],
                                                                       -right	=> ['%8',-10],
                                                                       -top	=> ['%10',-30],
                                                                       -bottom	=> ['%10',-5]);

    $dialog->bind('<Control-w>' => sub { $dialog->destroy(); });
}


sub about
{
    my ($dialog, $title, $text, $okbutton, $credit, $timer);
    $dialog = MainWindow->new();
    $dialog -> title("Nothing Much About...");
    $dialog -> configure(-background => 'white');
    $dialog -> geometry("600x750");
    $dialog -> formGrid(10,10);

    ($title = $dialog->Label(-text		=> 'Nothing Much About "Much To Do"',
                             -font		=> $opts{boldfont},
                             -foreground	=> 'blue', 
                             -background	=> 'white', 
                             -anchor		=> 'center', 
                             -relief		=> 'flat', 
                             -width		=> 50, 
                             -height		=> 1)) -> form(-in	=> $dialog,
                                                               -fill	=> 'both',
                                                               -left	=> ['%0',5],
                                                               -right	=> ['%10',-5],
                                                               -top	=> ['%0',5],
                                                               -bottom	=> ['%0',35]);

    ($text = $dialog->ROText(-width			=> 30, 
                             -height			=> 2,
                             -padx			=> 5, 
                             -pady			=> 5, 
                             -relief			=> 'flat',
                             -spacing3		=> 10,
                             -foreground		=> 'blue', 
                             -background		=> 'white', 
                             -selectforeground	=> 'blue', 
                             -selectbackground	=> 'white', 
                             -font			=> $opts{font},
                             -wrap			=> 'word')) -> form(-in		=> $dialog,
                                                                            -fill	=> 'both',
                                                                            -left	=> ['%0',20],
                                                                            -right	=> ['%10',-20],
                                                                            -top	=> ['%0',30],
                                                                            -bottom	=> ['%10',-70]);

    $text->insert('1.0',
"This is version 2.2 of Much To Do About Nothing, a simple to-do list application written using Perl/Tk and Perl DBI.  It is free software; you may do whatever you want with it, so long as you credit the author.  Don't expect too much from it; it was written to learn PerlTk, and it's very basic.
This release uses a MySQL database to store reminders, but it can be easily modified for any database with a DBD module available.  The database must be created by hand at present.  Every attempt is made to make database transactions atomic and not hold the database open.
There is no set limit upon the number or length of reminders.  Reminders are displayed in order of priority from highest to lowest, then alphabetically by title.
Click on a reminder's title in the left pane to view it on the right pane.  You can add, delete or edit reminders, or re-sort the list, using the Reminders menu.  (You must have a reminder title selected in the listbox to edit that reminder.)  You can also edit a reminder by double-clicking its title in the left pane.  You can re-prioritize a reminder when you edit it.  The Update button in the Edit window saves your changes, and updates the left-pane list, without closing the Edit window.
The font and geometry can be set in a ~/.muchtoto file using the following simple syntax:
    geometry: 800x800
    font: -*-CG Omega-medium-r-normal--*-140-*-*-p-*-iso8859
    boldfont: -*-CG Omega-bold-r-normal--*-140-*-*-p-*-iso8859
If not specified, the geometry defaults to 800x600, and the normal and bold fonts default to CG Omega.  If normal font is specified but bold isn't, it will be assumed you want the bold version of your specified normal font as your bold font.
If you don't have CG Omega, you'll probably want to change it to, for example, Helvetica, but I'm touting CG Omega because it's a marvellously clear font for both titles and body text (though its true beauty doesn't become apparent until you print it), yet almost unknown and grossly underappreciated.
BUGS: Widget geometries are precalculated for the default font, and may require minor tweaking if you use a significantly different sized font.");

    ($okbutton = $dialog->Button(-text			=> 'OK',
                                 -command		=> sub {
                                                                   $timer = $okbutton->after(10, sub { $dialog->destroy(); } );
                                                               },
                                 -activebackground	=> 'yellow',
                                 -anchor		=> 'center',
                                 -relief		=> 'raised',
                                 -width			=> 4,
                                 -height		=> 1)) -> form(-in	=> $dialog,
                                                                       -fill	=> 'both',
                                                                       -left	=> ['%4',5],
                                                                       -right	=> ['%6',-5],
                                                                       -top	=> ['%10',-60],
                                                                       -bottom	=> ['%10',-30]);

    ($credit = $dialog->Label(-text		=> 'Much To Do About Nothing v2.2, August 5 2007, Phil V. Stracchino <alaric@caerllewys.net>',
                              -font		=> $opts{font},
                              -foreground	=> 'blue', 
                              -background	=> 'white', 
                              -anchor		=> 'center', 
                              -relief		=> 'flat', 
                              -width		=> 50, 
                              -height		=> 1)) -> form(-in	=> $dialog,
                                                               -fill	=> 'both',
                                                               -left	=> ['%0',5],
                                                               -right	=> ['%10',-5],
                                                               -top	=> ['%10',-25],
                                                               -bottom	=> ['%10',-5]);

    $dialog->bind('<Control-w>' => sub { $dialog->destroy(); });
}


sub insert_task
{
    my ($userid, $title, $priority, $reminder) = @_;
    my ($dbh, $sth, $query);

    $title =~ s/(['"])/\\$1/g;
    $reminder =~ s/(['"])/\\$1/g;

    $query = sprintf('INSERT INTO task (userid, title, priority, reminder) VALUES (%d,\'%s\',%d, \'%s\')',
                     $userid,
                     $title,
                     $priority,
                     $reminder);

    $dbh = open_db();
    $dbh->do($query) || die "Error:" . $dbh->errstr . "\n";
    $dbh->commit || die "Error:" . $dbh->errstr . "\n";
    $dbh->disconnect();
}


sub update_task
{
    my ($userid, $taskid, $title, $priority, $reminder) = @_;
    my ($dbh, $sth, $query);

    $title =~ s/(['"])/\\$1/g;
    $reminder =~ s/(['"])/\\$1/g;

    $query = sprintf('UPDATE task SET title=\'%s\', priority=%d, reminder=\'%s\' WHERE userid=%d AND taskid=%d',
                     $title,
                     $priority,
                     $reminder,
                     $userid,
                     $taskid);

    $dbh = open_db();
    $dbh->do($query) || die "Error:" . $dbh->errstr . "\n";
    $dbh->commit || die "Error:" . $dbh->errstr . "\n";
    $dbh->disconnect();
}


sub delete_task
{
    my ($userid, $taskid) = @_;
    my ($dbh, $sth, $query, $title);

    $title = $title{$taskid};    

    $dbh = open_db();
    $sth = $dbh->prepare("DELETE FROM task WHERE userid=$userid AND taskid=$taskid") || die "Error:" . $dbh->errstr . "\n";
    $sth->execute || die "Error:" . $dbh->errstr . "\n";
    $sth->finish();
    $dbh->commit || die "Error:" . $dbh->errstr . "\n";
    $dbh->disconnect();

    delete($taskid{$title});
    delete($title{$taskid});
    delete($priority{$taskid});
    delete($description{$taskid});
}


sub load_tasks
{
    my ($userid) = @_;
    my ($sth, $dbh);
    my $row = 0;

    $dbh = open_db();
    $sth = $dbh->prepare("SELECT taskid,title,priority,reminder FROM task WHERE userid=$userid order by priority,title,taskid") || die "Error:" . $dbh->errstr . "\n";
    $sth->execute || die "Error:" . $dbh->errstr . "\n";
    while (my $ref = $sth->fetchrow_arrayref)
    {
        $title{$$ref[0]} = $$ref[1];
        $taskid{$$ref[1]} = $$ref[0];
        $priority{$$ref[0]} = $$ref[2];
        $description{$$ref[0]} = $$ref[3];
        $offset{$$ref[1]} = $row++;
    }
    $sth->finish();
    $dbh->disconnect();

    return (scalar keys %title);
}


sub get_or_insert_user
{
    my $user = $ENV{'USER'};
    my ($dbh, $sth, $id, $ref);

    $dbh = open_db();
    $sth = $dbh->prepare("SELECT userid FROM user where user='$user'") || die "Error:" . $dbh->errstr . "\n";
    $sth->execute || die "Error:" . $dbh->errstr . "\n";
    until ($ref = $sth->fetchrow_arrayref)
    {
        $sth = $dbh->prepare("INSERT INTO user (user) VALUES ('$user')") || die "Error:" . $dbh->errstr . "\n";
        $sth->execute || die "Error:" . $dbh->errstr . "\n";
        $sth = $dbh->prepare("SELECT userid FROM user where user='$user'") || die "Error:" . $dbh->errstr . "\n";
        $sth->execute || die "Error:" . $dbh->errstr . "\n";
    }
    $id = $$ref[0];
    $sth->finish();
    $dbh->commit || die "Error:" . $dbh->errstr . "\n";
    $dbh->disconnect();

    return ($id);
}


sub open_db
{
    my $home = $ENV{'HOME'};
    my ($dsn, $dbh, $user, $password);

    $dsn = "DBI:mysql:database=todo;"
         . "%s"
         . "mysql_read_default_group=todo;"
         . "mysql_read_default_file=$home/.my.cnf;"
         . "mysql_mysql_client_found_rows=TRUE;"
         . "mysql_mysql_ssl=TRUE";
    $dsn = sprintf($dsn, $opts{sqlhost}
                         ? sprintf('host=%s;port=%s;',
                                   $opts{sqlhost},
                                   $opts{sqlport} ? $opts{sqlport} : '3306')
                         : 'host=localhost;');

    $dbh = DBI->connect($dsn, undef, undef, {RaiseError => 1, AutoCommit => 0});
    return ($dbh);
}


sub reload_tasks
{
    %title = ();
    %taskid = ();
    %description = ();
    %priority = ();
    load_tasks($userid);
    if (scalar keys %title)
    {
        while($listbox->index('end'))
        {
            $listbox->delete('end');
        }
        foreach my $id (sort myorder keys %title)
        {
            my $title = sprintf ("[%d]  %s", $priority{$id}, $title{$id});
            $listbox->insert('end', $title);
        }
        load_reminder((sort myorder keys %title)[0]);
    }
}


sub myorder
{
    $priority{$a} <=> $priority{$b}
    or
    $title{$a} cmp $title{$b}
}


sub listbox_click_event
{
    my $text = $listbox->getSelected;
    if ($text)
    {
        $text =~ s/^\[\d+\]\s+//;
        load_reminder($taskid{$text});
    }
}


sub listbox_dclick_event
{
    my $text = $listbox->getSelected;
    if ($text)
    {
        $text =~ s/^\[\d+\]\s+//;
        load_reminder($taskid{$text});
        edit_reminder($taskid{$text});
    }
}


sub load_reminder
{
    my ($taskid) = @_;

    $textfield->delete('1.0', 'end');
    $textfield->insert('end', $description{$taskid});
}


sub select_reminder
{
    my $title = $_[0];

    my $id = $offset{$title};
    $listbox->selectionSet($id,$id);
}


sub listbox_delete_event
{
    my $text = $listbox->getSelected;
    if ($text)
    {
        $text =~ s/^\[\d+\]\s+//;
        delete_reminder($taskid{$text});
    }
}


sub quit
{
    exit(0);
}


sub get_prefs
{
    my %o;

    open(PREFS, $_[0]);
    while (<PREFS>)
    {
        next if (/^#/);
        if (/^(\S.*\S)\s*:\s+(\S.*\S)\s*$/)
        {
            $o{$1} = $2;
        }
    }

    return(%o);
}


sub apply_defaults
{
    my $o = $_[0];

    $o->{geometry} = '800x600' unless ($o->{geometry});
    $o->{font} = '-*-CG Omega-medium-r-normal--*-140-*-*-p-*-iso8859' unless ($o->{font});
    (($o->{boldfont} = $o->{font}) =~ s/medium/bold/) unless ($o->{boldfont});
}


sub list_options
{
    my $o = $_[0];

    print "Options:\n";
    foreach my $key (sort keys %$o)
    {
        printf("\t%-12s : %s\n",
               $key,
               $o->{$key});
    }
}
