#!/usr/bin/perl
#
# gareth@osoal.org.nz | http://osoal.org.nz
# The One Short Of A Llama Project

# create table cartoon
# (
#     id int unsigned,
#     time int unsigned,
#     title tinytext,
# );

use strict;
use OneShortOfALlama;
use DBI;
use POSIX;

#
#
#

sub CARTOON_TITLE()   { 1 << 0; }
sub CARTOON_EXISTS()  { 1 << 1; }
sub CARTOON_PICTURE() { 1 << 2; }

#
#
#

my($CartoonConvert, $CartoonImages, $CartoonLoad, @CartoonDays, @CartoonMonths, %CartoonMethods);

$CartoonConvert = '/usr/X11R6/bin/convert';
$CartoonImages  = '/var/www/htdocs/www.osoal.org.nz/pics/cartoons';
$CartoonLoad    = 5;

@CartoonDays    = qw/Sunday Monday Tuesday Wednesday Thursday Friday Saturday/;
@CartoonMonths  = qw/January Febuary March April May June July August September October November December/;

%CartoonMethods =
    (
     'Add'            => \&cartoon_create,
     'Modify'         => \&cartoon_create,
     'Submit'         => \&cartoon_submit,
     'Update'         => \&cartoon_update,
     'Remove'         => \&cartoon_destroy,
     'Confirm Remove' => \&cartoon_destroy_confirm,
     'Focus'          => \&cartoon_focus,
     'List'           => \&cartoon_list
     );

#
#
#

sub cartoon_authenticate($$$)
{
    my($dbh, $nickname, $hash, $uid, $gid, $passwd);

    $dbh      = shift(@_);
    $nickname = shift(@_);
    $hash     = shift(@_);

    if ($nickname && $hash)
    {
        ($uid, $gid, $passwd)
            = $dbh->selectrow_array(sprintf('select uid, gid, passwd from
                                             users where (nickname = %s)', $dbh->quote($nickname)));

        if (crypt($passwd, $nickname) eq $hash)
        {
            return (+{
                uid => $uid,
                gid => $gid
            });
        }
    }

    return ();
}

sub cartoon_error($)
{
    my($error) = shift(@_);
    print('<font face="Arial, Helvetica, sans-serif" color="#cc0000" size="-1"><b>', $error, '</b></font>');
}

sub cartoon_permissions()
{
    print('Permission denied');
}

sub cartoon_ordinal($)
{
    my($date, $val);

    $date = shift(@_);
    $val  = ($date > 10 && $date < 14) ? 0 : $date % 10;

    if    ($val == 1) { return ('st'); }
    elsif ($val == 2) { return ('nd'); }
    elsif ($val == 3) { return ('rd'); }
    else              { return ('th'); }
}

sub cartoon_date($)
{
    my($date, $month, $year, $day);
    (undef, undef, undef, $date, $month, $year, $day, undef, undef) = localtime(shift(@_));

    return (sprintf('%s %d%s of %s, %d',
                    $CartoonDays[$day], $date, cartoon_ordinal($date), $CartoonMonths[$month], $year + 1900));
}

#
#
#

sub cartoon_create($$$;$)
{
    my($dbh, $auth, $var, $errors);

    $dbh    = shift(@_);
    $auth   = shift(@_);
    $var    = shift(@_);
    $errors = shift(@_) || FALSE;

    unless ($auth->{'gid'} == 1)
    {
	cartoon_permissions();
	return ();
    }

    if ($var->{'option'} eq 'Modify')
    {
	($var->{'title'})
	    = $dbh->selectrow_array(sprintf('select title from cartoons where (id = %d)', $var->{'id'}));
    }

    print('<form method="POST" action="', $ENV{'SCRIPT_NAME'}, '" enctype="multipart/form-data">
           <table cellpadding="3" cellspacing="0" border="0">
             <tr>
               <td><font face="Arial, Helvetica, sans-serif">Title</font></td>
               <td><font face="Arial, Helvetica, sans-serif">
                 <input type="text" name="title" value="', quote($var->{'title'}), '" size="40"></font></td>
               <td>');

    if ($errors & CARTOON_TITLE)
    {
	cartoon_error('You must supply a title');
    }
    elsif ($errors & CARTOON_EXISTS)
    {
	cartoon_error('That title already exists');
    }

    print('</td>
             </tr>
             <tr>
               <td><font face="Arial, Helvetica, sans-serif">Picture</font></td>
               <td><font face="Arial, Helvetica, sans-serif">');

    if ($var->{'option'} eq 'Modify' || $var->{'option'} eq 'Update')
    {
	print('[ <a href="/pics/cartoons/', $var->{'id'}, '.png"><b><small>Picture...</small></b></a> ]<br>', "\n");
    }

    print('<input type="file" name="file" value="" size="31"></font></td>
               <td>');

    if ($errors & CARTOON_PICTURE)
    {
	cartoon_error('You must supply a cartoon');
    }

    print('</td>
             </tr>
             <tr>
               <td colspan="2">
               <table cellpadding="0" cellspacing="0" border="0" width="100%">
                 <tr>
                   <td><font face="Arial, Helvetica, sans-serif">');

    if ($var->{'option'} eq 'Modify' || $var->{'option'} eq 'Update')
    {
	print('<input type="hidden" name="id" value="', $var->{'id'}, '">
               <input type="submit" name="option" value="Update">', "\n");
    }
    else
    {
	print('<input type="submit" name="option" value="Submit">', "\n");
    }

    print('</font></td>
                   <td><div align="right"><img src="/pics/icons/oneshortofallama.png" alt="One Short Of A Llama"></div></td>
                 </tr>
               </table>
               </td>
             </tr>
           </table>
           </form>', "\n");
}

sub cartoon_parse($$$)
{
    my($dbh, $auth, $var, $errors, $buf);

    $dbh    = shift(@_);
    $auth   = shift(@_);
    $var    = shift(@_);
    $errors = FALSE;

    for $buf (qw/title/)
    {
	$var->{$buf} =~ s/\r//g;
	$var->{$buf} =~ s/^\s*(.*?)\s*$/$1/;
    }

    if ($var->{'title'} =~ m/\S/o)
    {
	my($id);

	if ($id = $dbh->selectrow_array(sprintf('select id from cartoons
                                                 where (title = %s)', $dbh->quote($var->{'title'}))))
	{
	    if ($id && ($var->{'id'} != $id))
	    {
		$errors |= CARTOON_EXISTS;
	    }
	}
    }
    else
    {
	$errors |= CARTOON_TITLE;
    }

    unless ($var->{'option'} eq 'Modify' || $var->{'option'} eq 'Update')
    {
	unless ($var->{'file'})
	{
	    $errors |= CARTOON_PICTURE;
	}
    }

    return ($errors);
}

sub cartoon_picture($$$)
{
    my($dbh, $auth, $var, $file, $mask);
    local(*DIR, *FILE);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless ($var->{'file'})
    {
	return (FALSE);
    }

    $mask = umask(000);

    unless (-d "$CartoonImages/$$var{id}")
    {
	unless (mkdir("$CartoonImages/$$var{id}", 0700))
	{
	    cartoon_error("mkdir: $!");
	    return (FALSE);
	}
    }

    unless (sysopen(FILE, "$CartoonImages/$$var{id}/unknown", O_CREAT | O_TRUNC | O_WRONLY, 0644))
    {
	cartoon_error("open: $!");
	return (FALSE);
    }

    syswrite(FILE, $var->{'file'});
    close(FILE);

    system($CartoonConvert,
	   "$CartoonImages/$$var{id}/unknown", "$CartoonImages/$$var{id}/$$var{id}.png");

    if (-e "$CartoonImages/$$var{id}/$$var{id}.png")
    {
	system($CartoonConvert, "-size", "160",
	       "$CartoonImages/$$var{id}/$$var{id}.png", "$CartoonImages/$$var{id}/$$var{id}.thumbnail.png");

	if (-e "$CartoonImages/$$var{id}/$$var{id}.thumbnail.png")
	{
	    rename("$CartoonImages/$$var{id}/$$var{id}.png",
		   "$CartoonImages/$$var{id}.png");

	    rename("$CartoonImages/$$var{id}/$$var{id}.thumbnail.png",
		   "$CartoonImages/$$var{id}.thumbnail.png");
	}
    }

    unless (opendir(DIR, "$CartoonImages/$$var{id}"))
    {
	cartoon_error("opendir: $!");
	return (FALSE);
    }

    while (defined($file = readdir(*DIR)))
    {
	if (-f "$CartoonImages/$$var{id}/$file")
	{
	    unlink("$CartoonImages/$$var{id}/$file");
	}
    }

    closedir(DIR);
    rmdir("$CartoonImages/$$var{id}");

    umask($mask);

    unless (-e "$CartoonImages/$$var{id}.png")
    {
	cartoon_error('Picture conversion failed');
	return (FALSE);
    }

    return (TRUE);
}

sub cartoon_submit($$$)
{
    my($dbh, $auth, $var, $errors);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless ($auth->{'gid'} == 1)
    {
	cartoon_permissions();
	return ();
    }

    if ($errors = cartoon_parse($dbh, $auth, $var))
    {
	cartoon_create($dbh, $auth, $var, $errors);
	return ();
    }

    $var->{'id'} = $dbh->selectrow_array('select max(id) from cartoons') + 1;

    unless (cartoon_picture($dbh, $auth, $var))
    {
	return ();
    }

    $dbh->do(sprintf('insert into cartoons (id, time, title)
                      values (%d, %d, %s)',
		     $var->{'id'}, time(), $dbh->quote($var->{'title'})));

    cartoon_focus($dbh, $auth, $var);
}

sub cartoon_update($$$)
{
    my($dbh, $auth, $var, $errors);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless ($auth->{'gid'} == 1)
    {
	cartoon_permissions();
	return ();
    }

    unless ($var->{'id'} =~ m/^\d+$/o)
    {
	cartoon_error('Invalid id#');
	return ();
    }

    if ($errors = cartoon_parse($dbh, $auth, $var))
    {
	cartoon_create($dbh, $auth, $var, $errors);
	return ();
    }

    if ($var->{'file'})
    {
	unless (cartoon_picture($dbh, $auth, $var))
	{
	    return ();
	}
    }

    $dbh->do(sprintf('update cartoons set title = %s
                      where (id = %d)', $dbh->quote($var->{'title'}), $var->{'id'}));
    
    cartoon_focus($dbh, $auth, $var);
}

sub cartoon_destroy($$$)
{
    my($dbh, $auth, $var, $file);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless ($auth->{'gid'} == 1)
    {
	cartoon_permissions();
	return ();
    }

    unless ($var->{'id'} =~ m/^\d+$/o)
    {
	cartoon_error('Invalid id#');
	return ();
    }

    for $file ("$$var{id}.png", "$$var{id}.thumbnail.png")
    {
	unlink("$CartoonImages/$file");
    }

    $dbh->do(sprintf('delete from cartoons where (id = %d)', $var->{'id'}));
    cartoon_list($dbh, $auth, $var);
}

sub cartoon_destroy_confirm($$$)
{
    my($dbh, $auth, $var);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless ($auth->{'gid'} == 1)
    {
	cartoon_permissions();
	return ();
    }

    print('<br>
           <font face="Arial, Helvetica, sans-serif">
           Removed cartoons cannot be restored, are you sure you want to do this?<br>
           <br>
           <div align="center">
             [ <b><a href="', $ENV{'SCRIPT_NAME'}, '?option=Remove&id=', $var->{'id'}, '">Confirm</a></b> |
               <b><a href="', $ENV{'SCRIPT_NAME'}, '">Cancel</a></b> ]
           </div>
           </font>', "\n");
}

sub cartoon_focus($$$)
{
    my($dbh, $auth, $var, $time, $title, $prev, $next);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless (($time, $title) = $dbh->selectrow_array(sprintf('select time, title from cartoons
                                                             where (id = %d)', $var->{'id'})))
    {
	cartoon_error('Invalid id#');
	return ();
    }

    print('<div align="center">[ ');

    if ($prev = $dbh->selectrow_array(sprintf('select max(id) from cartoons
                                               where (id < %d)', $var->{'id'})))
    {
	print('<a href="', $ENV{'SCRIPT_NAME'}, '?option=Focus&id=', $prev, '"><b>Previous</b></a> | ');
    }

    print('<a href="', $ENV{'SCRIPT_NAME'}, '?option=List&page=', encode($var->{'page'}), '&load=', encode($var->{'load'}), '"><b>List</b></a>', "\n");

    if ($auth->{'gid'} == 1)
    {
	print(' | <a href="', $ENV{'SCRIPT_NAME'}, '?option=Confirm+Remove&id=', $var->{'id'}, '"><b>Remove</b></a>
                | <a href="', $ENV{'SCRIPT_NAME'}, '?option=Modify&id=', $var->{'id'}, '"><b>Modify</b></a> ');
    }

    if ($next = $dbh->selectrow_array(sprintf('select min(id) from cartoons
                                               where (id > %d)', $var->{'id'})))
    {
	print(' | <a href="', $ENV{'SCRIPT_NAME'}, '?option=Focus&id=', $next, '"><b>Next</b></a> ');
    }

    print(' ]<br>
             <br>
             <br>
             <font face="Arial, Helvetica, sans-serif" size=+1><em><b>`', quote($title), '\'</b></em></font>
             <br>
             <br>
             <br>
             <img src="/pics/cartoons/', $var->{'id'}, '.png" alt="">
           </div>', "\n");
}

sub cartoon_list($$$)
{
    my($dbh, $auth, $var, $rows, $sth, $pages, $title, $time, $offset, $id);

    $dbh  = shift(@_);
    $auth = shift(@_);
    $var  = shift(@_);

    unless (($var->{'load'} =~ m/^\d+$/o) && $var->{'load'})
    {
	$var->{'load'} = $CartoonLoad;
    }

    $rows  = $dbh->selectrow_array('select count(*) from cartoons');
    $pages = ceil($rows / $var->{'load'});

    unless ($var->{'page'} =~ m/^\d+$/o && $var->{'page'} && $var->{'page'} <= $pages)
    {
	$var->{'page'} =  1;
    }

    print('<form method="GET" action="', $ENV{'SCRIPT_NAME'}, '">
           <input type="hidden" name="page" value="', $var->{'page'}, '">

           <div align="center">
             [ ');

    if ($auth->{'gid'} == 1)
    {
	print('<a href="', $ENV{'SCRIPT_NAME'}, '?option=Add"><b>Add Cartoon</b></a> | ');
    }

    if ($var->{'page'} < $pages)
    {
	print('<a href="', $ENV{'SCRIPT_NAME'}, '?option=List&page=', $var->{'page'} + 1, '&load=', $var->{'load'}, '"><b>Previous</b></a> | ');
    }

    print(' <b>Display</b> <input type="text" name="load" value="', quote($var->{'load'}), '" size="3"> <b>Cartoons</b> ');

    if ($var->{'page'} > 1)
    {
	print(' | <a href="', $ENV{'SCRIPT_NAME'}, '?option=List&page=', $var->{'page'} - 1, '&load=', $var->{'load'}, '"><b>Next</b></a>');
    }



    print('  ]
           <br><img vspace=20 src="/pics/misc/pow-title.png" border=0><br>
           </div>', "\n");

    unless ($rows)
    {
	return ();
    }

    $offset = ($var->{'page'} - 1) * $var->{'load'};

    $sth = $dbh->prepare(sprintf('select id, time, title from cartoons
                                  order by time desc limit %d,%d', $offset, $var->{'load'}));
    $sth->execute();

    unless ($sth->rows())
    {
	return ();
    }


    print('<table cellpadding="3" cellspacing="0" border="0">', "\n");
    $sth->bind_columns(\$id, \$time, \$title);

    while ($sth->fetch())
    {
	print('<tr>
                 <td align="right"><a href="', $ENV{'SCRIPT_NAME'}, '?option=Focus&id=', $id, '&page=', $var->{'page'}, '&load=', $var->{'load'}, '">
                   <img src="/pics/cartoons/', $id, '.thumbnail.png" width="120" border="1"></a></td>
                 <td align="left">
                   <font face="Arial, Helvetica, sans-serif">
                   <ul>`<em><b>', quote($title), '</b></em>\' <small><br>', cartoon_date($time), '</small></ul>
                   </font>
                 </td>
               </tr>', "\n");
    }

    print('</table>', "\n");
}

#
#
#

sub main()
{
    my($dbh, $var, $auth, $cookie, $handler);

    header('Puddles of Wisdom', 'cartoons.png', '/');

    print('<div align="center">
           <table width="600" cellpadding="0" cellspacing="0" border="0">
             <tr>
               <td>', "\n\n");

    if ($dbh = DBI->connect("dbi:mysql:$MySQLserver;database=osoal", $MySQLuser, $MySQLpasswd))
    {
        $var    = variables();
        $cookie = cookie('osoal');
        $auth   = cartoon_authenticate($dbh, $cookie->{'nickname'}, $cookie->{'passwd'});

        if ($handler = $CartoonMethods{$var->{'option'}})
        {
            $handler->($dbh, $auth, $var);
        }
        else
        {
            cartoon_list($dbh, $auth, $var);
        }

        $dbh->disconnect();
    }
    else
    {
        cartoon_error(quote("DBI->connect: $DBI::errstr"));
    }

    print('    </td>
             </tr>
           </table>
           </div>', "\n\n");

    footer();
}

main();
