The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Labyrinth::Plugin::Images;

use warnings;
use strict;

my $VERSION = '5.14';

=head1 NAME

Labyrinth::Plugin::Images - Plugin Images handler for Labyrinth

=head1 DESCRIPTION

Contains all the image handling functionality for the Labyrinth
framework.

=cut

# -------------------------------------
# Library Modules

use base qw(Labyrinth::Plugin::Base);

use Image::Size;
use File::Copy;
use File::Basename;

use Labyrinth::Audit;
use Labyrinth::Globals  qw(:default);
use Labyrinth::DBUtils;
use Labyrinth::DIUtils;
use Labyrinth::Media;
use Labyrinth::Metadata;
use Labyrinth::MLUtils;
use Labyrinth::Support;
use Labyrinth::Variables;

# -------------------------------------
# Constants

use constant    MaxDefaultWidth     => 120;
use constant    MaxDefaultHeight    => 120;
use constant    MaxDefaultThumb     => 120;

# -------------------------------------
# Variables

# type: 0 = optional, 1 = mandatory
# html: 0 = none, 1 = text, 2 = textarea

my %fields = (
    imageid     => { type => 1, html => 0 },
    image       => { type => 0, html => 0 },
    tag         => { type => 0, html => 1 },
    link        => { type => 0, html => 1 },
    type        => { type => 1, html => 0 },
    href        => { type => 0, html => 0 },
    metadata    => { type => 0, html => 1 },
);

my (@mandatory,@allfields);
for(keys %fields) {
    push @mandatory, $_     if($fields{$_}->{type});
    push @allfields, $_;
}

my $LEVEL = ADMIN;

# -------------------------------------
# The Subs

=head1 PUBLIC INTERFACE METHODS

The following are convience methods to provide the appropriate functionality 
to list the require number of random images for the page.

These are to be deprecated in the future, in favour of using configuration
settings and/or parameter values.

=over 4

=item Random()

Stores a random image in template variable 'irandX', where X is 1.

=item Random4()

Stores 4 random images in template variable 'irandX', where X is 1 to 4.

=item Random6()

Stores 6 random images in template variable 'irandX', where X is 1 to 6.

=item Random8()

Stores 8 random images in template variable 'irandX', where X is 1 to 8.

=back

=cut

sub Random  { RandomN(1);   }
sub Random4 { RandomN(4);   }
sub Random6 { RandomN(6);   }
sub Random8 { RandomN(8);   }

=head1 LOCAL INTERFACE METHODS

=over 4

=item RandomN()

Provide 'n' random images, prefixed in a template variable with 'irand'.

=back

=cut

sub RandomN {
    my $count = shift;
    my @rows = $dbi->GetQuery('hash','GetImagesByType',2);
    my $max = @rows;

    my %blank = (link=>$settings{blank},tag=>'');

    if($max <= $count) {
        foreach my $inx (1..$max) { $tvars{"irand$inx"} = $rows[($inx-1)]; }
        return;
    }

    my (%done,@random);
    srand;
    while(1) {
        my $index = int((rand) * $max);
        next    if($done{$index});
        push @random, $rows[$index];
        $done{$index} = 1;
        last    if(@random >= $count);
    }

    foreach my $inx (1..$count) { $tvars{"irand$inx"} = $random[($inx-1)]; }
}

=head1 ADMIN INTERFACE METHODS

Note that in all cases the images referred to do not include photos uploaded
via the Album plugin, for photo albums.

=over 4

=item List

List all uploaded images.

=item Add

Create a template variable hash for a new image.

=item Edit

Edit the attributes of a given image.

=item EditAmendments

Additional drop downs and fields for editing.

=item Save

Save a given image.

=item Delete

Delete a given image.

=item Gallery

Provide a set of images as a gallery for selection.

=back

=cut

sub List {
    return  unless AccessUser($LEVEL);

    my @delete = CGIArray('DELETE');
    if(@delete) {
        $cgiparams{'imageid'} = $_;
        Delete();
    }

    my $key = $cgiparams{'searchmeta'} ? 'MetaImages' : 'AllImages';
    $cgiparams{'searchmeta'} =~ s/[,\s]+/,/g;

    my @where = ();
    push @where, "i.type=$cgiparams{'stockid'}"             if($cgiparams{'stockid'});
    push @where, "m.tag IN ($cgiparams{'searchmeta'})"      if($cgiparams{'searchmeta'});
    my $where = @where ? 'WHERE '.join(' AND ',@where) : '';

    my @rows = $dbi->GetQuery('hash',$key,{where=>$where});
    foreach (@rows) { $_->{typename} = StockName($_->{type}); }
    $tvars{data} = \@rows   if(@rows);

    $tvars{ddstock} = StockSelect();
}

sub Add {
    return  unless AccessUser($LEVEL);

    my %data = (
        imageid     => 0,
        tag         => '',
        metadata    => '',
        link        => $settings{blank},
        ddstock     => StockSelect(),
    );

    $tvars{data} = \%data;
}

sub Edit {
    return  unless AccessUser($LEVEL);
    return  unless $cgiparams{'imageid'};

    my @rows = $dbi->GetQuery('hash','GetImageByID',$cgiparams{'imageid'});
    return  unless(@rows);

    $tvars{data} = $rows[0];
    EditAmendments();
}

sub EditAmendments {
    $tvars{data}->{metadata}    = MetaGet($cgiparams{'imageid'},['Image'])  if($cgiparams{'imageid'});
    $tvars{data}->{typename}    = StockName($tvars{data}->{type});
    $tvars{data}->{ddstock}     = StockSelect($tvars{data}->{type});

    for(keys %fields) {
        if($fields{$_}->{html} == 1)    { $tvars{data}->{$_} = CleanHTML($tvars{data}->{$_}) }
        elsif($fields{$_}->{html} == 2) { $tvars{data}->{$_} = SafeHTML($tvars{data}->{$_}) }
    }

    return  unless($tvars{data}->{link});

    # Get the size of image
    ($tvars{data}->{x_resize},$tvars{data}->{y_resize})
        = ResizeDimensions($tvars{data}->{dimensions},"$settings{webdir}/$tvars{data}->{link}",$tvars{maxpicwidth},$tvars{maxpicheight});
}

sub Save {
    return  unless AccessUser($LEVEL);
    return  unless AuthorCheck('GetImageByID','imageid',$LEVEL);
    EditAmendments();

    for(keys %fields) {
           if($fields{$_}->{html} == 1) { $cgiparams{$_} = CleanHTML($cgiparams{$_}) }
        elsif($fields{$_}->{html} == 2) { $cgiparams{$_} = CleanTags($cgiparams{$_}) }
        elsif($fields{$_}->{html} == 3) { $cgiparams{$_} = CleanLink($cgiparams{$_}) }
    }

    my $link = $tvars{data}->{link};
    return  if FieldCheck(\@allfields,\@mandatory);

    if($cgiparams{image}) {
        my ($name,$filename) = CGIFile('image',$tvars{data}->{type});
        unless($name) { # blank if anything goes wrong
            $tvars{errcode} = 'ERROR';
            return;
        }

        my $i = Labyrinth::DIUtils->new("$settings{webdir}/$filename");
        $i->reduce(MaxDefaultWidth,MaxDefaultHeight);

        $tvars{data}->{link} = $filename;
    } else {
        $tvars{data}->{link} = $link;
    }

    $cgiparams{imageid} = SaveImage(    $cgiparams{imageid},
                                        $tvars{data}->{tag},
                                        $tvars{data}->{link},
                                        $tvars{data}->{type},
                                        $tvars{data}->{href});

    my @metadata = $tvars{data}->{metadata} ? split(qr/[, ]+/,$tvars{data}->{metadata}) : ();
    MetaSave($cgiparams{imageid},['Image'],@metadata);
}

sub Delete {
    return  unless AccessUser($LEVEL);
    return  unless($cgiparams{'imageid'});

    # check whether image still referenced
    if(ImageCheck($cgiparams{'imageid'})) {
        $tvars{errcode} = 'MESSAGE';
        $tvars{errmess} = 'Sorry cannot delete that image, it is used within other areas of the site.';
        return;
    }

    my @rows = $dbi->GetQuery('hash','GetImageByID',$cgiparams{'imageid'});

    # do the delete
    if($dbi->DoQuery('DeleteImage',$cgiparams{'imageid'})) {
        unlink "$settings{webdir}/" . $rows[0]->{link};
    }
}

my @blanks = (
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
{ imageid=>1,link=>$settings{blank},tag=>'',height=>100,width=>100 },
);

sub Gallery {
    return  unless AccessUser(EDITOR);
    my $start     = $cgiparams{'start'}     || 2;
    my $key = '';

    if($cgiparams{'searchmeta'}) {
        $key = 'Meta';
        $cgiparams{'searchmeta'} =~ s/[,\s]+/,/g;
        $cgiparams{'searchmeta'} = join(",", map {"'$_'"} split(",",$cgiparams{'searchmeta'}));
    }

    my $where;
    $where .= " AND i.type IN ($cgiparams{'imagetype'})"        if($cgiparams{'imagetype'});
    $where .= " AND m.tag IN ($cgiparams{'searchmeta'})"        if($cgiparams{'searchmeta'});

    my @rows = $dbi->GetQuery('hash',$key.'Gallery',{where=>$where},$start);
    for(@rows) {
        ($_->{width},$_->{heigth})
            = ResizeDimensions($_->{dimensions},"$settings{webdir}/$_->{link}",100,100);
    }

    $tvars{next} = $rows[9]->{imageid}  unless(@rows < 10);
    push @rows, @blanks;
    $tvars{data} = \@rows   if(@rows);
    my @prev = $dbi->GetQuery('hash',$key.'GalleryMin',{where=>$where},$start);

    $tvars{prev}      = $prev[8]->{imageid} unless(@prev < 9);
    $tvars{imagetype} = $cgiparams{'imagetype'};
    $tvars{ddstock}   = StockSelect();
}

1;

__END__

=head1 SEE ALSO

L<Labyrinth>

=head1 AUTHOR

Barbie, <barbie@missbarbell.co.uk> for
Miss Barbell Productions, L<http://www.missbarbell.co.uk/>

=head1 COPYRIGHT & LICENSE

  Copyright (C) 2002-2014 Barbie for Miss Barbell Productions
  All Rights Reserved.

  This module is free software; you can redistribute it and/or
  modify it under the Artistic License 2.0.

=cut