#!/usr/bin/perl
#
# Copyright 2006 Katipo Communications.
# Parts Copyright 2009 Foundations Bible College.
#
# This file is part of Koha.
#
# Koha 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.
#
# Koha 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 Koha; if not, see <https://www.gnu.org/licenses>.

use Modern::Perl;

use CGI         qw ( -utf8 );
use XML::Simple qw( XMLin XMLout );
use autouse 'Data::Dumper' => qw(Dumper);

use C4::Auth     qw( get_template_and_user );
use C4::Output   qw( output_html_with_http_headers );
use C4::Creators qw(
    get_all_image_names
    get_barcode_types
    get_font_types
    get_text_justification_types
    get_unit_values
);
use C4::Patroncards;
use Koha::Logger;

my $cgi = CGI->new;
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
    {
        template_name => "patroncards/edit-layout.tt",
        query         => $cgi,
        type          => "intranet",
        flagsrequired => { tools => 'label_creator' },
    }
);

my $op            = $cgi->param('op')            || 'new';    # make 'new' the default operation if none is submitted
my $layout_id     = $cgi->param('layout_id')     || $cgi->param('element_id') || '';
my $layout_choice = $cgi->param('layout_choice') || '';
my $layout        = '';
my $layout_xml    = undef;

my $units           = get_unit_values();
my $font_types      = get_font_types();
my $alignment_types = get_text_justification_types();
my $barcode_types   = get_barcode_types();
my $image_sources   = [
    { type => 'none',           name => 'None',         selected => 1 },
    { type => 'patronimages',   name => 'Patron Image', selected => 0 },
    { type => 'creator_images', name => 'Other Image',  selected => 0 },
];
my $image_names = get_all_image_names();
unshift @$image_names, { type => 'none', name => 'Select Image', selected => 1 };

sub _set_selected {
    my ( $selection, $source_list ) = @_;
    my @select_list =
        ();    # we must make a copy of the referent otherwise we modify the original which causes bad things to happen
    my $selected = 0;
SET_SELECTED:
    foreach my $type (@$source_list) {
        if ( ($selection) && ( $type->{'type'} eq $selection ) )
        {      # even if there is no current selection we must still build the select box
            $selected = 1;
        } else {
            $selected = 0;
        }
        push @select_list, { type => $type->{'type'}, name => $type->{'name'}, selected => $selected };
    }
    return \@select_list;
}

if ( $op eq 'edit_form' ) {
    warn sprintf( "Error performing '%s': No 'layout_id' passed in.", $op ) unless ($layout_id);
    $layout     = C4::Patroncards::Layout->retrieve( layout_id => $layout_id );
    $layout_xml = XMLin( $layout->get_attr('layout_xml'), ForceArray => 1 );

    #       Handle text fields...
    my $field_number = 0;
    my @text_fields  = ();
    if ( $layout_xml->{'text'} ) {
        while ( scalar @{ $layout_xml->{'text'} } ) {
            $field_number++;
            push @text_fields, (
                "field_" . $field_number           => 1,    # indicate field as currently "selected" for display in form
                "field_" . $field_number . "_text" => shift @{ $layout_xml->{'text'} },
            );
            my $field_params = shift @{ $layout_xml->{'text'} };
            push @text_fields, (
                "field_" . $field_number . "_llx"          => $field_params->{'llx'},
                "field_" . $field_number . "_lly"          => $field_params->{'lly'},
                "field_" . $field_number . "_height_scale" => $field_params->{'height_scale'},
                "field_" . $field_number . "_width_scale"  => $field_params->{'width_scale'},
                "field_" . $field_number . "_font"         => _set_selected( $field_params->{'font'}, $font_types ),
                "field_" . $field_number . "_font_size"    => $field_params->{'font_size'},
                "field_"
                    . $field_number
                    . "_text_alignment" => _set_selected( $field_params->{'text_alignment'}, $alignment_types ),
            );
        }
    }

    #   Handle fields not currently used
UNUSED_TEXT_FIELDS:
    for ( my $field = $field_number + 1 ; $field < 4 ; $field++ ) {    # limit 3 text fields
        push @text_fields, (
            "field_$field" . "_font"           => get_font_types(),
            "field_$field" . "_text_alignment" => get_text_justification_types(),
        );
    }

    #   Handle images...
    my $image_count = 0;
    my @images      = ();
    foreach my $image ( keys %{ $layout_xml->{'images'} } ) {
        $image_count++;
        push @images, (
            $image . "_image" => "$image",
            $image . "_Dx"    => $layout_xml->{'images'}->{$image}->{'Dx'},
            $image . "_Tx"    => $layout_xml->{'images'}->{$image}->{'Tx'},
            $image . "_Ty"    => $layout_xml->{'images'}->{$image}->{'Ty'},
            $image
                . "_image_source" => _set_selected(
                $layout_xml->{'images'}->{$image}->{'data_source'}->[0]->{'image_source'}, $image_sources
                ),
            $image
                . "_image_name" =>
                _set_selected( $layout_xml->{'images'}->{$image}->{'data_source'}->[0]->{'image_name'}, $image_names ),
        );
    }

    #   Handle image fields not currently used
UNUSED_IMAGE_FIELDS:
    for ( my $image = $image_count + 1 ; $image < 3 ; $image++ ) {    #limit 2 images
        push @images, (
            "image_$image" . "_image_source" => $image_sources,
            "image_$image" . "_image_name"   => $image_names,
        );
    }

    #   Handle barcodes...
    my @barcode = ();
    foreach my $barcode_param ( keys %{ $layout_xml->{'barcode'}->[0] } ) {
        push @barcode,
            (
            (
                $barcode_param eq 'type'
                ? ( "barcode_"
                        . $barcode_param => _set_selected( $layout_xml->{'barcode'}->[0]->{'type'}, $barcode_types ) )
                : ( "barcode_" . $barcode_param => $layout_xml->{'barcode'}->[0]->{$barcode_param} )
            )
            );
    }

    foreach my $unit (@$units) {
        if ( $unit->{'type'} eq $layout->get_attr('units') ) {
            $unit->{'selected'} = 1;
        } else {
            $unit->{'selected'} = 0;
        }
    }

    $template->param(
        layout_id   => $layout->get_attr('layout_id') > -1 ? $layout->get_attr('layout_id') : '',
        layout_name => $layout->get_attr('layout_name'),
        page_side   => ( $layout_xml->{'page_side'} eq 'F' ? 0 : 1 ),
        guide_box   => $layout_xml->{'guide_box'},
        guide_grid  => $layout_xml->{'guide_grid'},
        units       => $units,
        @barcode,
        barcode_type => _set_selected( $layout_xml->{'barcode'}->[0]->{'type'}, $barcode_types ),
        @text_fields,
        @images,
        guidebox => 0,
    );
    output_html_with_http_headers $cgi, $cookie, $template->output;
    exit;
} elsif ( $op eq 'cud-save' ) {
    my $format_string = undef;
    my $layout        = {};
    my $layout_name   = undef;
    my $layout_id     = undef;
    my $text_lines    = [];
    my $array_index   = 0;
    my $image_select  = 0;
    my $field_enabled = 0;

    # $image_names was already fetched above (and already includes 'none')
    my %valid_images = map { $_->{'type'} => 1 } @$image_names;

CGI_PARAMS:

    foreach my $parameter ( $cgi->multi_param() )
    {    # parse the field values and build a hash of the layout for conversion to xml and storage in the db
        if ( $parameter =~ m/^field_([0-9])_(.*)$/ ) {
            my $field_number = $1;
            my $field_data   = $2;
            $field_enabled = $field_number if $field_data eq 'enable';
            next CGI_PARAMS unless $field_number == $field_enabled;
            if ( $field_data eq 'text' ) {
                push @$text_lines, $cgi->multi_param($parameter);
                if ( $array_index <= 0 ) {
                    $array_index++;
                } else {
                    $array_index += 2;    # after hitting 1, increment by 2 so counting odds
                }
            } elsif ( $array_index > 0 ) {
                $text_lines->[$array_index]->{$field_data} = $cgi->param($parameter);
            }
        } elsif ( $parameter =~ m/^barcode_(.*)$/ ) {
            $field_enabled = $1 if $1 eq 'print';
            next CGI_PARAMS unless defined $field_enabled && $field_enabled eq 'print';
            $layout->{'barcode'}->{$1} = $cgi->param($parameter);
        } elsif ( $parameter =~ m/^image_([0-9])_(.*)$/ ) {
            my $image_number = $1;
            my $image_data   = $2;
            $field_enabled = $image_number if $cgi->param( "image_$image_number" . "_image_source" ) ne 'none';
            next CGI_PARAMS unless $image_number == $field_enabled;
            my $param_value = $cgi->param($parameter);

            # Sanitize image_name
            my ($image_suffix) = $image_data =~ m/^image_(.*)$/;
            my $field_name = $image_suffix // $image_data;
            if ( $field_name eq 'name' && $param_value && !exists $valid_images{$param_value} ) {
                Koha::Logger->get->warn(
                    sprintf( "Rejecting unknown image_name '%s' submitted for patroncard layout", $param_value ) );
                $param_value = undef;
            }
            if ( defined $image_suffix ) {
                $layout->{'images'}->{"image_$image_number"}->{'data_source'}->{"image_$image_suffix"} = $param_value;
            } else {
                $layout->{'images'}->{"image_$image_number"}->{$image_data} = $param_value;
            }
        } else {
            $layout_name            = $cgi->param($parameter) if $parameter eq 'layout_name';
            $layout_id              = $cgi->param($parameter) if $parameter eq 'layout_id';
            $layout->{'units'}      = $cgi->param($parameter) if $parameter eq 'units';
            $layout->{'page_side'}  = $cgi->param($parameter) if $parameter eq 'page_side';
            $layout->{'guide_box'}  = $cgi->param($parameter) if $parameter eq 'guide_box';
            $layout->{'guide_grid'} = $cgi->param($parameter) if $parameter eq 'guide_grid';
        }
    }
    $layout->{'text'} = $text_lines;
    my @params = ( layout_name => $layout_name, layout_id => $layout_id, layout_xml => XMLout($layout) );
    push( @params, units => $layout->{'units'} ) if $layout->{'units'};
    if ($layout_id) {    # if a label_id was passed in, this is an update to an existing layout
        $layout = C4::Patroncards::Layout->retrieve( layout_id => $layout_id );
        $layout->set_attr(@params);
        $layout_id = $layout->save();
    } else {             # if no label_id, this is a new layout so insert it
        $layout    = C4::Patroncards::Layout->new(@params);
        $layout_id = $layout->save();
    }
    print $cgi->redirect(
        "manage.pl?card_element=layout" . ( $layout_id == -1 ? "&element_id=$layout_id&op=$op&error=101" : '' ) );
    exit;
} elsif ( $op eq 'new' ) {    # this is a new layout
    $layout = C4::Patroncards::Layout->new();
    my @fields = ();
    for ( my $field = 0 ; $field < 4 ; $field++ ) {    # limit 3 text fields
        push @fields, (
            "field_$field" . "_font"           => get_font_types(),
            "field_$field" . "_text_alignment" => get_text_justification_types(),
        );
    }

    my @images = ();
    for ( my $image = 0 ; $image < 3 ; $image++ ) {    #limit 2 images
        push @images, (
            "image_$image" . "_image_source" => $image_sources,
            "image_$image" . "_image_name"   => $image_names,
        );
    }

    $template->param(
        units => get_unit_values(),
        @fields,
        barcode_type => get_barcode_types(),
        @images,
    );

    output_html_with_http_headers $cgi, $cookie, $template->output;
    exit;
} else {    # trap unsupported operation here
    warn sprintf( "Unsupported operation type submitted: %s", $op );
    print $cgi->redirect("manage.pl?card_element=layout&element_id=$layout_id&error=201");
    exit;
}

__END__
