# +-----------------------------------------------------------------------+
# | pLoader - a Perl photo uploader for Piwigo                            |
# +-----------------------------------------------------------------------+
# | Copyright(C) 2008-2010 Piwigo Team                  http://piwigo.org |
# +-----------------------------------------------------------------------+
# | 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                                          |
# |                                                                       |
# | 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, write to the Free Software           |
# | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
# | USA.                                                                  |
# +-----------------------------------------------------------------------+
package Uploader::GUI::Frame;
use strict;
use Data::Dumper;
use Carp;
use Wx;
use Wx::DND;
use Wx qw/
             wxCLIP_CHILDREN
             wxYES_NO
             wxYES
             wxICON_QUESTION
             wxITEM_NORMAL
             wxID_OK
             wxDEFAULT_FRAME_STYLE
             wxVERTICAL
             wxGROW
             wxSHAPED
             wxBITMAP_TYPE_JPEG
             wxBITMAP_TYPE_GIF
             wxBITMAP_TYPE_PNG
             wxBITMAP_TYPE_ANY
             wxTB_FLAT
             wxTB_TEXT
             wxSIZE
             wxWHITE
             wxBLACK
             wxID_CANCEL
             wxFD_OPEN
             wxFD_MULTIPLE
             wxALL
             wxGROW
             wxDefaultPosition
             wxDefaultSize
             wxTheApp
             wxIMAGE_LIST_NORMAL
             wxNO_BORDER
             wxTE_MULTILINE
             wxTE_READONLY
             wxITEM_NORMAL 
             wxBORDER_NONE
             wxNullBitmap 
             wxTR_MULTIPLE
             wxTR_EXTENDED
             wxTR_HIDE_ROOT
             wxTR_HAS_BUTTONS
             wxTR_EDIT_LABELS
             wxMAXIMIZE
             wxOK
             wxICON_EXCLAMATION
             wxICON_INFORMATION
             WXK_DELETE
             wxHORIZONTAL
             wxVERTICAL
             wxEXPAND
             wxSWISS
             wxNORMAL
             wxBOLD
             wxALIGN_CENTER
         /;
use base qw/Wx::Frame Class::Accessor::Fast/;
use File::Spec;
use Wx::Locale qw/:default/;
use POSIX qw(ceil floor);

require Win32 if($^O =~ /MSWin32/);



my @properties = 
    qw/
          progressdlg
          upload_progressdlg
          imageviewer
          imageviewer_img
          tree
          tree_root
          treeimglist
          tree_item_default
          pwg
          logwnd
          oldlogwnd
          categories
          imagelist
          image_preview_dlg
          image_prop_piwigo
          exif_dlg
          image_prop_tags
          global_settings_dlg
          piwigo_property_list
          exif_properties
          global_settings
          toolbar
          branding
          current_imageviewer_index
          imageviewer_mnu
          tree_mnu
          imageviewer_select_multi
          frameLayout
          piwigo_tags
          image_tags
          piwigo_photo_properties
          piwigo_photo_properties_dlg
          piwigo_photo_properties_tags
          image_preview_need_refresh
          imageviewer_refresh
          imageviewer_item_refresh
          horizontal_splitter
          destination_category_dlg
          destination_categories
          categories_treectrl
      /;
__PACKAGE__->mk_accessors( @properties );

use Wx::Perl::TextValidator;
use Uploader::GUI::wxImageListCtrl;
use Uploader::GUI::wxPropertyListDlg;
use Uploader::GUI::wxGlobalSettings;
use Uploader::GUI::wxImagePreview;
use Uploader::GUI::wxPhotoProperties;
use Uploader::GUI::wxImageReuploadDlg;
use Uploader::GUI::wxImageProcessingProgressDlg;
use Uploader::GUI::wxDestinationCategoryDlg;
use Uploader::GUI::wxCategoryTreeCtrl;
use utf8;
$|=1;

my $ID_TREE_CTX_MENU = 20000 ;
my $ID_IMAGEVIEWER_CTX_MENU = 20100 ;


sub new {
    my( $class, $params ) = @_;

    my $self  = $class->SUPER::new( 
        undef, 
        -1, 
        $params->{title},
        wxDefaultPosition,
        wxDefaultSize, 
        wxDEFAULT_FRAME_STYLE
    );


    $self->pwg( $params->{pwg} );
    $self->imagelist( $params->{imagelist} );


    $self->imagelist->pwg(
        $self->pwg
    );

    $self->imagelist->categories(
        []
    );


    $self->init_gui_callbacks;
    $self->init_properties_dlg_bindings;
    $self->init_frame;
    $self->init_menus;
    $self->init_event_handlers;
    $self->init_image_types;   

    $self->imageviewer->SelectItem(
        $self->current_imageviewer_index
    ) if $self->imageviewer->GetItemCount;
   
    # if file in command line parameters, try to load
    my $files = wxTheApp->argv;
    $self->SetNewFiles($files) if scalar @$files;

    $self->Show;
    $self;
}


sub init_gui_callbacks {
    my ( $self ) = @_;

    # callback for GUI refresh : add thumbnail images to the imageviewer control
    $self->imagelist->SetNewFilesViewerRefreshCallback(
        sub { $self->SetNewFilesViewerRefresh(@_) }
    );

    # callback for GUI refresh : progress dialog display of thumbnail image being created
    $self->imagelist->SetNewFilesProgressCallback(
        sub { $self->SetNewFilesProgress(@_) }
    );

    $self->imagelist->SetNewFilesDisplayEndInfoCallback(
        sub { $self->SetNewFilesDisplayEndInfo(@_) }
    );

    # callback for GUI refresh : remove thumbnail images from imageviewer control
    $self->imagelist->UploadImagesViewerCallback(
        sub { $self->UploadImagesViewerRefresh(@_) }
    );
    
    $self->imagelist->ReuploadCallback(
    sub 
    {
        Uploader::GUI::wxImageReuploadDlg->new(
        { 
            title => gettext("Photo update management"),
            properties => 
            {
                $main::ID_REUPLOAD_ACTION_FILES => 
                {
                    selection=>sub {$self->imagelist->reupload_action_files(@_)},
                    label=>gettext("What shall we do with files? (thumbnail, resized, high resolution)"),
                    labels=>[
                        gettext("nothing"),
                        gettext("replace"),
                    ],
                },
                $main::ID_REUPLOAD_ACTION_PROPERTIES => 
                { 
                    selection=>sub{$self->imagelist->reupload_action_properties(@_)},
                    label=>gettext("What shall we do with single value properties?(caption, comment, author, create date)"),
                    labels=>[
                        gettext("nothing"),
                        gettext("fill if empty (only replace properties currently empty in Piwigo)"),
                        gettext("replace"),
                    ],
                },
                $main::ID_REUPLOAD_ACTION_PROPERTIES_M =>
                { 
                    selection=>sub{$self->imagelist->reupload_action_properties_m(@_)},
                    label=>gettext("What shall we do with multiple values properties? (categories, tags)"),
                    labels=>[
                        gettext("nothing"),
                        gettext("append (keep existing and add new)"),
                        gettext("replace"),
                    ],
                },
                $main::ID_REUPLOAD_NOT_ASK => 
                { 
                    value=>sub{$self->imagelist->reupload_not_ask(@_)}, 
                    label=>gettext("Do not ask me again"),
                },
                $main::ID_REUPLOAD_TEXT => 
                { 
                    label=>gettext("A least one photo has already been added in the past."),
                },
            },
        } )->ShowModal();}
    );


    # callback for GUI refresh : progress dialog display current uploaded image
    $self->imagelist->progress_thumbnail_refresh(
        sub { $self->UploadProgressThumbnailRefresh(@_) }
    );

    $self->imagelist->progress_msg_refresh(
        sub { $self->UploadProgressMessageRefresh(@_) }
    );

    $self->imagelist->progress_msg_details_refresh(
        sub { $self->UploadProgressMessageDetailsRefresh(@_) }
    );

    $self->imagelist->progressbar_refresh(
        sub { $self->UploadProgressBarRefresh(@_) }
    );
    
    $self->imagelist->progress_endinfo_refresh(
        sub { $self->UploadDisplayEndInfo(@_) }
    );
}


sub init_properties_dlg_bindings {
    my ( $self ) = @_;

    $self->piwigo_photo_properties(
        {
            $main::CAPTION => { label=>gettext("Caption")},
            $main::PHOTO_PROPERTIES_CAPTION => {
                multi_selection_mode => sub { $self->multi_selection_mode },
                string_selection => sub { return 1; },
                value => sub {
                    $self->imagelist->SetImageSelectionName(@_);
                    $self->multi_selection_mode ?
                    $self->imagelist->image_selection_name :
                    $self->imagelist->current_image->site_name;
                },
                pre_process => sub { sub { $self->imagelist->GetCurrentImageCaption(@_); } },
                choices =>
                [
                    map { gettext $_ } @{wxTheApp->caption_patterns}
                ],
                frame_callback => sub { $self->imageviewer_item_refresh(1); },
            },
            $main::COMMENT => { label=>gettext("Comment")},
            $main::PHOTO_PROPERTIES_COMMENT => {
                value => sub { 
                    $self->multi_selection_mode ?
                    $self->imagelist->SetImageSelectionComment(@_):
                    $self->imagelist->current_image->site_comment(@_) 
                },
                frame_callback => sub { $self->imageviewer_item_refresh(1); },
            },
            $main::AUTHOR => { label=>gettext("Author")},
            $main::PHOTO_PROPERTIES_AUTHOR => { 
                value => sub { 
                    $self->multi_selection_mode ?
                    $self->imagelist->SetImageSelectionAuthor(@_):
                    $self->imagelist->current_image->site_author(@_) 
                },
                frame_callback => sub { $self->imageviewer_item_refresh(1); },
            },
            $main::TAGS => { label=>gettext("Tags")},
            $main::CREATE_DATE => { label=>gettext("Create date")},
            $main::PHOTO_PROPERTIES_CREATE_DATE => { 
                value => sub { 
                    $self->multi_selection_mode ?
                    $self->imagelist->SetImageSelectionCreateDate(@_):
                    $self->imagelist->current_image->create_date(@_) 
                },
                frame_callback => sub { $self->imageviewer_item_refresh(1); },
            },
            $main::PRIVACY_LEVEL => { label=>gettext("Who can see?")},
            $main::PHOTO_PROPERTIES_PRIVACY_LEVEL => {
                selection => sub {
                    $self->multi_selection_mode ? 
                    $self->imagelist->SetImageSelectionPrivacyLevel(@_):
                    $self->imagelist->current_image->privacy_level(@_)
                },
                choices => wxTheApp->privacy_level_choices,
            },
            $main::PHOTO_PROPERTIES_NB => {
                texts => [
                    gettext("Properties"),
                    gettext("Tags")
                ], 
            },
            $main::PHOTO_PROPERTIES_UPLOAD => { label=>gettext("Upload to Piwigo") },
        }
    );    

    $self->global_settings(
        {
            $main::DEFAULT_PHOTO_CAPTION => { label => gettext("Default caption pattern") },
            $main::CPANE_RESIZE_ADVANCED => { label => gettext("Advanced") },
            $main::CPANE_HD_ADVANCED => { label => gettext("Advanced") },
            $main::CPANE_TRANSFERT_ADVANCED => { label => gettext("Advanced") },
            $main::GS_THUMBNAIL => { label => gettext("Thumbnail") },
            $main::GS_SITE_IMG => { label => gettext("Web sized") },
            $main::GS_HD => { label => gettext("High definition") },
            $main::GS_CLOSE => { label => gettext("Close")},
            $main::GS_THUMBNAIL_SHAPE => {
                selection => sub { $self->imagelist->thumbnail_shape_square(@_) },
                choices =>
                [
                    map { gettext $_ } ( "Rectangular", "Square" ) 
                ],
            },
            $main::GS_DEFAULT_PHOTO_CAPTION => {
                string_selection => sub { $self->imagelist->default_caption_pattern(@_) },
                choices =>
                [
                    map { gettext $_ } @{wxTheApp->caption_patterns}
                ],
                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_caption_patterns->{$value} },
                frame_callback => sub { 
                    my( $self, $ctrl, $event ) = @_; 
                    $self->OnDefaultPhotoCaption($event);
                },
            },
            $main::PHOTO_CAPTION_PREFIX => { label => gettext("Default caption") },
            $main::GS_PHOTO_CAPTION_PREFIX => {
                value => sub { $self->imagelist->default_caption(@_) },
            },
            $main::GS_AUTO_ROTATE => {
                label => gettext("Auto rotate image"),
                value => sub { $self->imagelist->auto_rotate(@_) }
           },
            $main::DEFAULT_AUTHOR => { label => gettext("Default author")},
            $main::GS_DEFAULT_AUTHOR => { value => sub { $self->imagelist->author(@_) } },
            $main::THUMBNAIL_SIZE => { label => gettext("Site thumbnail size") },
            $main::GS_THUMBNAIL_SIZE => {
                value => sub { $self->imagelist->thumb_size(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::THUMBNAIL_JPEG_QUALITY => { label => gettext("Site thumbnail jpeg quality") },
            $main::GS_THUMBNAIL_JPEG_QUALITY => {
                value => sub { $self->imagelist->th_quality(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::GS_CREATE_RESIZED => {
                selection => sub { $self->imagelist->create_resized(@_) },
                choices =>
                [
                    map { gettext $_ } ( "Use original", "Use resized original" ) 
                ],
                frame_callback => sub { 
                    my( $dlg, $ctrl, $event ) = @_;
                    $dlg->OnCreateResized($event);
                },
            },
            $main::SITE_IMG_WIDTH => { label => gettext("Maximum width") },
            $main::GS_SITE_IMG_WIDTH => {
                value => sub { $self->imagelist->resize_w(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::SITE_IMG_HEIGHT => { label => gettext("Maximum height") },
            $main::GS_SITE_IMG_HEIGHT => {
                value => sub { $self->imagelist->resize_h(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::SITE_IMG_JPEG_QUALITY => { label => gettext("Site image jpeg quality") },
            $main::GS_SITE_IMG_JPEG_QUALITY => {
                value => sub { $self->imagelist->quality(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::SITE_IMG_FILTER => { label => gettext("Site image filter") },
            $main::GS_SITE_IMG_FILTER => {
                string_selection =>  sub { $self->imagelist->filter(@_) },
                choices =>
                [
                    qw/Point Box Triangle Hermite Hanning Hamming Blackman Gaussian Quadratic Cubic Catrom Mitchell Lanczos Bessel Sinc/  
                ],
            },
            $main::SITE_IMG_BLUR => { label => gettext("Site image blur") },
            $main::GS_SITE_IMG_BLUR => {
                value => sub { $self->imagelist->blur(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::SITE_IMG_INTERLACE => { label => gettext("Site image interlace") },
            $main::GS_SITE_IMG_INTERLACE => {
                string_selection => sub { $self->imagelist->interlace(@_) },
                choices =>
                [
                    qw/None Line Plane Partition JPEG GIF PNG/  
                ],
            },
            $main::GS_REMOVE_UPLOADED_FROM_SELECTION => {
                label => gettext("Remove uploaded photo from selection"),
                value => sub { $self->imagelist->remove_uploaded_from_selection(@_) },
            },
            $main::GS_HD_UPLOAD => {
                choices  =>
                [
                    map { gettext $_ } @{wxTheApp->upload_hd}
                ],
                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_upload_hd->{$value} },
                string_selection => sub { $self->imagelist->upload_hd(@_) },
                frame_callback => sub { 
                    my( $self, $ctrl, $event ) = @_; 
                    $self->OnHDUpload($event);
                },
            },
            $main::HD_IMG_WIDTH => { label => gettext("Maximum width") },
            $main::GS_HD_IMG_WIDTH => {
                label => gettext("HD image width"),
                value => sub { $self->imagelist->hd_w(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::HD_IMG_HEIGHT => { label => gettext("Maximum height") },
            $main::GS_HD_IMG_HEIGHT => {
                label => gettext("HD image height"),
                value => sub { $self->imagelist->hd_h(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::HD_IMG_JPEG_QUALITY => { label => gettext("HD image jpeg quality") },
            $main::GS_HD_IMG_JPEG_QUALITY => {
                value => sub { $self->imagelist->hd_quality(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::HD_IMG_FILTER => { label => gettext("HD image filter") },
            $main::GS_HD_IMG_FILTER => {
                string_selection =>  sub { $self->imagelist->hd_filter(@_) },
                choices =>
                [
                    qw/Point Box Triangle Hermite Hanning Hamming Blackman Gaussian Quadratic Cubic Catrom Mitchell Lanczos Bessel Sinc/  
                ],
            },
            $main::HD_IMG_BLUR => { label => gettext("HD image blur") },
            $main::GS_HD_IMG_BLUR => {
                value => sub { $self->imagelist->hd_blur(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::HD_IMG_INTERLACE => { label => gettext("HD image interlace") },
            $main::GS_HD_IMG_INTERLACE => {
                string_selection => sub { $self->imagelist->hd_interlace(@_) },
                choices =>
                [
                    qw/None Line Plane Partition JPEG GIF PNG/  
                ],
            },
            $main::GS_WMARK_ACTIVATE => {
              label  => gettext("Activate watermark"),
              value  => sub { $self->imagelist->watermark_activate(@_) },
              frame_callback => sub { 
                  my( $self, $ctrl, $event ) = @_; 
                  $self->OnWatermark($event);
              },
            },
            $main::GS_WMARK_ACTIVATE_HD => {
              label => gettext("Activate watermark on high definition"),
              value => sub { $self->imagelist->watermark_activate_pwg_high(@_) },
              frame_callback => sub { 
                  my( $self, $ctrl, $event ) = @_; 
                  $self->OnWatermark($event);
              },
            },
            $main::WMARK_TEXT => { label  => gettext("Text") },
            $main::GS_WMARK_TEXT => { 
              value  => sub { $self->imagelist->watermark_text(@_) },
            },
            $main::WMARK_TEXT_SIZE => { label     => gettext("Text size") },
            $main::GS_WMARK_TEXT_SIZE => {
                value   => sub { $self->imagelist->watermark_text_size(@_) },
            },
            $main::WMARK_COLOR => { label     => gettext("Color") },
            $main::GS_WMARK_COLOR => {
                string_selection => sub { $self->imagelist->watermark_color(@_) },
                choices   => [
                               map { gettext $_ } @{wxTheApp->colors}
                             ],
                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_colors->{$value} },
            },
            $main::WMARK_POSITION => { label     => gettext("Position") },
            $main::GS_WMARK_POSITION => {
                string_selection => sub { $self->imagelist->watermark_position(@_) },
                choices  => [
                               map { gettext $_ } @{wxTheApp->positions}
                           ],
                pre_process => sub { my ( $value ) = @_; wxTheApp->eng_positions->{$value} },
            },
            $main::WMARK_MARGIN_TOP => { label => gettext("Top margin") },
            $main::GS_WMARK_MARGIN_TOP => {
                value   => sub { $self->imagelist->watermark_y(@_) },
            },
            $main::WMARK_MARGIN_LEFT => { label => gettext("Left margin") },
            $main::GS_WMARK_MARGIN_LEFT => {
                value   => sub { $self->imagelist->watermark_x(@_) },
            },
            $main::CHUNK_SIZE => { label => gettext("Transfert chunk size") },
            $main::GS_CHUNK_SIZE => {
                value   => sub { wxTheApp->chunk_size(@_) },
                validator => Wx::Perl::TextValidator->new( '\d' ) 
            },
            $main::LANGUAGE => { label => gettext("Choose a language") },
            $main::GS_LANGUAGE => {
                selection => sub { wxTheApp->current_language(@_) },
                choices => [ map { sprintf($_->[0], gettext($_->[2])) } @{wxTheApp->available_languages} ],
                pre_process => sub { my ( $value ) = @_; wxTheApp->available_languages->[$value][1] },
                frame_callback => sub { my ( $self, $ctrl, $event ) = @_;
                    Wx::LogMessage(
                        sprintf(
                            "%s : %s",  
                            gettext("pLoader needs to be restarted to display the new selected language"),
                            gettext(wxTheApp->available_languages->[$event->GetSelection][2])
                        )
                    );
                    wxTheApp->layout_clean(1);
                },
            },
        }    
    );

    $self->piwigo_property_list(
        [
            {
                label => gettext("Photo caption"),
            },
            {
                label => gettext("Comment"),
            },
            {
                label => gettext("Author"),
            },
            {
                label => gettext("File name"),
            },
            {
                label => gettext("Create date"),
            },
        ]    
    );

    $self->exif_properties(
        [
            {
                label    => gettext("Create date"),
                value    => sub { $self->imagelist->current_image->create_date }, 
                readonly => 1,
            },    
            {
                label    => gettext("Model"),
                value    => sub { $self->imagelist->current_image->exif_tag('Model') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Width"),
                value    => sub { $self->imagelist->current_image->exif_tag('ImageWidth') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Height"),
                value    => sub { $self->imagelist->current_image->exif_tag('ImageHeight') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Orientation"),
                value    => sub { $self->imagelist->current_image->exif_tag('Orientation') }, 
                readonly => 1,
            },    
            {
                label    => "ISO",
                value    => sub { $self->imagelist->current_image->exif_tag('ISO') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Shutter speed"),
                value    => sub { $self->imagelist->current_image->exif_tag('ExposureTime') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Aperture"),
                value    => sub { $self->imagelist->current_image->exif_tag('ApertureValue') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Focal length"),
                value    => sub { $self->imagelist->current_image->exif_tag('FocalLength') }, 
                readonly => 1,
            },    
            {
                label    => gettext("Lens"),
                value    => sub { $self->imagelist->current_image->exif_tag('Lens') }, 
                readonly => 1,
            },    
        ]
    );   

    $self->image_tags(
        sub { scalar @{$self->imagelist->image_selection} > 1 ? $self->imagelist->SetImageSelectionTags(@_) : $self->imagelist->current_image->site_tags(@_)||[]  }
    );

    $self->piwigo_tags(
        sub { wxTheApp->pwg->tags }
    );    
}

sub init_image_types {
    my ( $self ) = @_;

    $self->{IMGTYPE} = {
        'jpg' => wxBITMAP_TYPE_JPEG,
        'gif' => wxBITMAP_TYPE_GIF,
        'png' => wxBITMAP_TYPE_PNG,
    };
}


sub init_frame {
    my ( $self ) = @_;
    
    $self->create_toolbar;

    my $sizer_h = Wx::BoxSizer->new( wxHORIZONTAL );
    


    $self->imageviewer(
        Uploader::GUI::wxImageListCtrl->new( 
            { 
                parentwnd => $self,
                imagelist => $self->imagelist,
                image_size => $self->imagelist->wx_thumb_size,
                columns => $self->piwigo_property_list,
            }
        )
    );


    $self->piwigo_photo_properties_dlg (
        Uploader::GUI::wxPhotoProperties->new(
            {
                parentwnd  => $self,
                categories => [ @{$self->pwg->categories}],
                properties => $self->piwigo_photo_properties,
                tags       =>
                {
                    id => $main::PHOTO_PROPERTIES_TAG,
                    choices => $self->piwigo_tags,
                    selection => $self->image_tags,
                    creation_callback => sub { $self->_create_piwigo_tag(@_) },
               },
            }
        )
    );

    $self->piwigo_photo_properties_tags(
        $self->piwigo_photo_properties_dlg->FindWindow($main::PHOTO_PROPERTIES_TAG)
    );

    $self->tree(
        $self->piwigo_photo_properties_dlg->FindWindow($main::PHOTO_PROPERTIES_CATEGORIES)
    );

    $self->init_dnd_targets;
    $self->init_dialogs;
    $self->show_hide_pwg_categories_empty_msg;

    if( $self->imagelist->wx_thumb_imglist->GetImageCount){
        $self->ShowImageViewer;
        
        $self->imageviewer->Refresh(
            $self->imagelist->wx_thumb_imglist
        );
       
        $self->OnUpdateImageviewerNotEmpty;
    }
    else{
        $self->OnUpdateImageviewerEmpty;
    }

    # the imageviewer has a stretch factor of 1 : expands its size on frame resize
    $sizer_h->Add( $self->imageviewer, 1, wxEXPAND|wxALL, 2 );
    $sizer_h->Add( $self->piwigo_photo_properties_dlg, 0, wxEXPAND|wxALL, 2 );


    $self->SetSizer(
        $sizer_h
    );
    my $new_size = $sizer_h->Fit(
        $self
    );
    $self->SetMinSize([600, 660]);
    $self->Center;
}


sub _create_piwigo_tag {
    my ( $self, $name ) = @_;
    
    if(
        Wx::MessageBox( 
            sprintf(
                "%s \"%s\" ?",
                gettext("Do you want to create"), 
                $name,
            ),
            gettext("Piwigo search information"),
            wxYES_NO | wxICON_QUESTION, 
        ) == wxYES 
    ){    
        $self->pwg->AddTags($name);
        $self->pwg->RefreshTags;
    }
}


sub OnUpdateImageviewerEmpty {
    my ( $self ) = @_;

    $self->piwigo_photo_properties_dlg->SetDisabled;
    $self->imageviewer->OnEmpty;
}

sub OnUpdateImageviewerNotEmpty {
    my ( $self ) = @_;

    $self->piwigo_photo_properties_dlg->SetEnabled;
    $self->imageviewer->OnNotEmpty;
}


sub init_dialogs {
    my ( $self ) = @_;    


    $self->exif_dlg(
        Uploader::GUI::wxPropertyListDlg->new( 
            { 
                parentwnd       => $self,
                properties      => $self->exif_properties,
                caption         => sprintf("%s - EXIF", gettext("Properties")),
            }
        )
    );
    $self->exif_dlg->Hide;

    $self->global_settings_dlg(
        Uploader::GUI::wxGlobalSettings->new( 
            { 
                parentwnd       => $self,
                caption         => gettext("Global settings"),
                properties      => $self->global_settings,
            }
        )
    );
    $self->global_settings_dlg->Hide;

    $self->image_preview_dlg(
        Uploader::GUI::wxImagePreview->new(
            { 
                parentwnd    => $self,
                caption      => gettext("Preview"),
            }
        )
    );

    $self->destination_category_dlg(
        Uploader::GUI::wxDestinationCategoryDlg->new(
            { 
                parentwnd    => $self,
                caption      => gettext("Upload to Piwigo"),
                categories   => [@{$self->pwg->categories}],
                properties   => {
                                    $main::CHOOSE_DESTINATION => { label => wxTheApp->branding->{'What is the destination category?'} },
                                    $main::DESTINATION_CATEGORIES_OK => { label=>gettext("Upload to Piwigo")},
                                    $main::DESTINATION_CATEGORIES_CANCEL => { label=>gettext("Cancel")},
                                    $main::DESTINATION_CATEGORIES => {
                                        id_selection => sub { $self->imagelist->categories(@_) },
                                        frame_callback => sub {
                                            my ( $dlg, $ctrl, $evt ) = @_;
                                            $dlg->FindWindow($main::DESTINATION_CATEGORIES_OK)->Enable(scalar @{$self->imagelist->categories});
                                        },
                                    },
                                },
                frame_callback => sub { $self->OnRefreshCategories },
            }
        )
    );

    $self->destination_category_dlg->Hide;

    $self->destination_categories(
        $self->destination_category_dlg->FindWindow($main::DESTINATION_CATEGORIES)
    );

    $self->categories_treectrl(
        [
            $self->destination_categories,
            $self->tree,
        ]
    );

}


sub init_dnd_targets {
    my ( $self ) = @_;    

    $self->imageviewer->SetDropTarget( 
        DNDImageListDropTarget->new(
            $self->imageviewer 
        ) 
    );

    $self->tree->SetDropTarget( 
        DNDCategoryTreeDropTarget->new(
            $self->tree
        )
    );
    
}


sub OnPhotoProperties {
    my ( $self ) = @_;

    $self->exif_dlg->Show(1);
}


sub OnPreview {
    my ( $self ) = @_;

    $self->image_preview_dlg->Show(1);
}


sub OnGlobalSettings {
    my ( $self ) = @_;

    $self->global_settings_dlg->Show(1);
}


sub OnGeneralSettingsClose {
    my ( $self, $event ) = @_;

    $self->global_settings_dlg->Hide;
}


sub OnImageExifPropClose {
    my ( $self, $event ) = @_;

    $self->image_exif_prop->Hide;
}




sub show_hide_pwg_categories_empty_msg {
    my ( $self ) = @_;

    map {
        $_->GetCount > 1 ?
            $_->HideEmptyMsg :
            $_->ShowEmptyMsg;
    }@{$self->categories_treectrl};

}


sub init_menus {
    my ( $self ) = @_ ;

    $self->_tree_mnu;
    $self->_imageviewer_mnu;    
}


sub _tree_mnu {
    my ( $self ) = @_;    

    my $ctx_mnu = Wx::Menu->new;
    
    map {
        $ctx_mnu->Append(
            @$_[0..2], wxITEM_NORMAL
        );
    }
    (
        # workaround : first item does not show bitmap
        [
            0, 
            "",
            "",
            wxTheApp->resource_path('mnu_folder_new.png'),
        ],
        [
            1+$ID_TREE_CTX_MENU, 
            wxTheApp->branding->{'Add new category'},
            sprintf(
                "%s %s %s %s", 
                gettext("Add a new"), 
                wxTheApp->branding->{category},
                gettext("to the currently selected"),
                wxTheApp->branding->{category},
            ),
            wxTheApp->resource_path('mnu_folder_new.png'),
        ],
        [
            2+$ID_TREE_CTX_MENU, 
            gettext("Refresh"),
            sprintf(
                "Refresh %s list.",
                wxTheApp->branding->{category},
            ),
            wxTheApp->resource_path('mnu_refresh.png'),
        ],
        [
            3+$ID_TREE_CTX_MENU, 
            gettext("Expand all"),
            sprintf(
                "Expand %s list.",
                wxTheApp->branding->{category},
            ),
            wxTheApp->resource_path('mnu_expandall.png'),
        ],
        [
            4+$ID_TREE_CTX_MENU, 
            gettext("Collapse all"),
            sprintf(
                "Collapse %s list.",
                wxTheApp->branding->{category},
            ),
            wxTheApp->resource_path('mnu_collapseall.png'),
        ],
    );

    $ctx_mnu->Delete(0);
    $self->tree_mnu(
         $ctx_mnu
    );    
}    

sub _imageviewer_mnu {
    my ( $self ) = @_;    

    my $ctx_mnu = Wx::Menu->new;
    
    map {
        $ctx_mnu->Append(
            @$_[0..2]
        );
    }
    (
        # workaround : first item does not show bitmap
        [
            0, 
            "",
            "",
            wxTheApp->resource_path('mnu_properties.png'),
        ],
        [
            1+$ID_IMAGEVIEWER_CTX_MENU, 
            gettext("Properties"),
            gettext("Modify photo properties"),
            wxTheApp->resource_path('mnu_properties.png'),
        ],
        [
            2+$ID_IMAGEVIEWER_CTX_MENU, 
            gettext("Preview"),
            gettext("Display photo preview"),
            wxTheApp->resource_path('mnu_preview.png'),
        ],
    );
    
    $ctx_mnu->Delete(0);
    $self->imageviewer_mnu(
         $ctx_mnu
    );    
}

sub init_event_handlers {
    my ( $self ) = @_ ;
    
    Wx::Event::EVT_MENU( $self, 101, \&OnAddImages );
    Wx::Event::EVT_MENU( $self, 102, \&OnRemoveImages );
    Wx::Event::EVT_MENU( $self, 103, \&OnUploadImages );
    Wx::Event::EVT_MENU( $self, 104, \&OnGlobalSettings );
    Wx::Event::EVT_CHOICE( $self, 106, \&OnPhotoSelMode );
    Wx::Event::EVT_TREE_SEL_CHANGED( $self, $self->tree, \&OnTreeSelChanged );
    Wx::Event::EVT_TREE_ITEM_RIGHT_CLICK( $self, $self->tree, \&OnTreeItemRightClick );
    Wx::Event::EVT_TREE_END_LABEL_EDIT( $self, $self->tree, \&OnTreeEndLabelEdit );

    Wx::Event::EVT_LIST_END_LABEL_EDIT( $self, $self->imageviewer, \&OnImageViewerEndLabelEdit );
    Wx::Event::EVT_LIST_ITEM_ACTIVATED( $self, $self->imageviewer, \&OnImageViewerItemActivated );
    Wx::Event::EVT_LIST_ITEM_SELECTED($self, $self->imageviewer, \&OnImageViewerItemSelected) ;
    Wx::Event::EVT_LIST_ITEM_DESELECTED($self, $self->imageviewer, \&OnImageViewerItemDeSelected) ;
    Wx::Event::EVT_LIST_ITEM_RIGHT_CLICK($self, $self->imageviewer, \&OnImageViewerItemRightClick) ;

    Wx::Event::EVT_LIST_KEY_DOWN($self, $self->imageviewer, \&OnImageViewerKeyDown) ;

    Wx::Event::EVT_CLOSE( $self, \&OnClose );

    Wx::Event::EVT_MENU( $self, 1+$ID_TREE_CTX_MENU, \&OnAddCategory );
    Wx::Event::EVT_MENU( $self, 2+$ID_TREE_CTX_MENU, \&OnRefreshCategories );
    Wx::Event::EVT_MENU( $self, 3+$ID_TREE_CTX_MENU, \&OnExpandCategories );
    Wx::Event::EVT_MENU( $self, 4+$ID_TREE_CTX_MENU, \&OnCollapseCategories );

    Wx::Event::EVT_MENU( $self, 1+$ID_IMAGEVIEWER_CTX_MENU, \&OnPhotoProperties );
    Wx::Event::EVT_MENU( $self, 2+$ID_IMAGEVIEWER_CTX_MENU, \&OnPreview );

    Wx::Event::EVT_BUTTON( $self, $main::PHOTO_PROPERTIES_UPLOAD, \&OnUploadImages );
    Wx::Event::EVT_BUTTON( $self, $self->imageviewer->add_button->GetId, \&OnAddImages );
    Wx::Event::EVT_KEY_DOWN($self, \&OnKeyDown );

    # only refresh when calling event is finished
    Wx::Event::EVT_IDLE(
        $self,
        sub {
            my ( $self, $event ) = @_;

            if ( $self->image_preview_need_refresh and $self->image_preview_dlg->IsShown ){
                $self->set_preview_image; 
                $self->image_preview_dlg->Refresh;
                $self->image_preview_need_refresh(0);
            }

            if($self->imageviewer_refresh){
                $self->imageviewer->Refresh;
                $self->imageviewer_refresh(0);
            }

            if($self->imageviewer_item_refresh){
                # for batch mode
                map {
                    $self->imageviewer->ItemRefresh(
                        $_
                    )
                } @{$self->imageviewer->GetSelectedItems};
                $self->imageviewer_item_refresh(0);
            }

            if(!$self->selected_images_count and $self->piwigo_photo_properties_dlg->IsEnabled){
                $self->piwigo_photo_properties_dlg->SetDisabled;
            }

            $self->OnUpdateToolbar;
            $event->Skip;
        }
    );

}


sub selected_images_count {
    my ( $self ) = @_;

    scalar @{$self->imageviewer->GetSelectedItems};
}

{
  my $prevfile;
  my $prevdir;

  sub OnAddImages {
    my( $self, $event ) = @_;

    $prevdir = wxTheApp->default_openfile_dir if ( -d wxTheApp->default_openfile_dir);
    my $dialog = Wx::FileDialog->new
      ( $self, gettext("Select photos for upload"), $prevdir, $prevfile,
        sprintf("%s (*.JPG;*.jpg)|*.JPG;*.jpg|%s (*.*)|*.*", gettext("JPEG files"), gettext("All")),
        wxFD_OPEN|wxFD_MULTIPLE );

    my $file_paths = [];
    if( $dialog->ShowModal != wxID_CANCEL ) {
        @$file_paths = $dialog->GetPaths;
        $self->SetNewFiles($file_paths) ;
    }
    wxTheApp->default_openfile_dir(
        $dialog->GetDirectory
    );
    $dialog->Destroy;
  }
}


sub OnUpdateToolbar {
    my( $self ) = @_;
    
    if($self->global_settings_dlg->IsShown){
        $self->toolbar->EnableTool(104, 0);
    }
    else{    
        $self->toolbar->EnableTool(104, 1);
    }

    if($self->global_settings_dlg->IsShown){
        $self->toolbar->EnableTool(104, 0);
    }
    else{    
        $self->toolbar->EnableTool(104, 1);
    }

}


sub OnRemoveImages {
    my( $self, $event ) = @_;

    
    $self->imagelist->RemoveImageSelection;
    $self->imageviewer->Refresh;    

    if (!$self->imageviewer->GetItemCount){
        $self->image_preview_dlg->image(
            0
        ); 
        # have to reset
        $self->piwigo_photo_properties_dlg->ClearProperties;
        $self->piwigo_photo_properties_tags->ClearAllSelection;
        $self->imagelist->SetCurrentImage(-1);
        $self->OnUpdateImageviewerEmpty;
    }
    else{
        $self->OnUpdateImageviewerNotEmpty;
    }

    if(!$self->multi_selection_mode){
        $self->OnUpdateSingleSelectionModeUI;
    }

    $self->image_preview_dlg->Refresh;
    $self->exif_dlg->Refresh;
}

sub SetNewFiles {
    my ( $self, $file_paths ) = @_;

    $self->ShowImageViewer();
    
    $self->progressdlg->Destroy if defined $self->progressdlg;
    $self->progressdlg( 
        Uploader::GUI::wxImageProcessingProgressDlg->new(
            { 
                title => gettext("Image processing progress information"),
                bt_label => gettext("Cancel image processing"), 
                bt_close_label => gettext("Close"),
                stop_processing => sub { $self->imagelist->stop_processing(1); Wx::Yield(); },
             }
        )        
    );
    $self->progressdlg->Show(1);
    Wx::Yield();

    
    my $files = [
        map {
            # to make sure that unicode chars in filenames are supported
            {
                ANSIPathName => $^O =~ /MSWin32/ ? Win32::GetANSIPathName($_) : $_,
                PathName => $_,
            },
        }@$file_paths    
    ];

    @$files = sort { $a->{PathName} cmp $b->{PathName} } @$files;    

    $self->imagelist->SetNewFiles(
        $files
    );

    
}


sub OnTreeSelChanged {
    my( $self, $event ) = @_;

    $self->imagelist->categories(
        $event->GetEventObject->GetSelectionsIds
    );
}

sub OnTreeItemRightClick {
    my( $self, $event ) = @_;


    $self->PopupMenu($self->tree_mnu, wxDefaultPosition);
    
}

sub OnTreeEndLabelEdit {
    my( $self, $event ) = @_;

    my $label = $event->GetLabel;
    
    $label =~ s/^\s+$//;

    if(defined($label) and !( "" eq $label )){
        $self->_SetLabel($event)
    }
    else{
        $event->Veto;
    }
}

sub _SetLabel {
    my( $self, $event ) = @_;
    
    my $category = $self->tree->GetPlData($event->GetItem);
    my $category_id;
    
    $category_id = $category->{id} if 'HASH' eq ref($category) ;
    my $comment;
    my ( $success, $status_msg, $content ) = $self->pwg->SetInfoCategories( 
        $event->GetLabel, 
        $comment, 
        $category_id
    );

    my $ok = 1;
    
    if(!$success){
        $ok = 0;
    }

    if('fail' eq $content->{stat}){
        $ok = 0;
    }

    # method call failed
    if(!$ok){
        $event->Veto;
        Wx::MessageBox( 
            sprintf(
                "%s %s", 
                gettext("Update failed : "),
                $status_msg
            ),
            gettext("Piwigo update error"),
            wxOK | wxICON_EXCLAMATION, 
        );
        Wx::LogMessage("%s\n\n%s", Dumper($content), gettext("This function is not available. A Piwigo upgrade may resolve this issue."));
    }
}

sub OnImageViewerItemRightClick {
    my( $self, $event ) = @_;

    
    $self->PopupMenu($self->imageviewer_mnu, wxDefaultPosition);
    
    
}

sub OnExpandCategories {
    my ( $self, $event ) = @_;

    my $parent_item = $self->tree->GetSelection;
    $self->tree->ExpandAllChildren($parent_item);
    $self->tree->EnsureVisible($parent_item);
}

sub OnCollapseCategories {
    my ( $self, $event ) = @_;

    my $parent_item = $self->tree->GetSelection;
    $self->tree->CollapseAllChildren($parent_item);
    $self->tree->Expand($parent_item) if -1 == $self->tree->GetPlData($parent_item);
}

sub OnAddCategory {
    my ( $self, $event ) = @_;

    $self->tree->AddCategory;

}


sub OnRefreshCategories {
    my ( $self, $event ) = @_;

    $self->_refresh_all_categories_helper;
}


sub _refresh_all_categories_helper {
    my ( $self ) = @_;

    my $busycursor = Wx::BusyCursor->new();
    $self->tree->CollapseAll;
    $self->tree->DeleteAllItems;
    $self->pwg->RefreshCategories();
    $self->tree->categories(
        $self->pwg->categories
    );
    $self->tree->Populate;
    $self->show_hide_pwg_categories_empty_msg;
}


sub OnImageViewerEndLabelEdit {
    my( $self, $event ) = @_;
  
    my $image = $self->imagelist->GetImage($event->GetIndex);
    $image->site_name(
        $event->GetLabel
    );
        
    $self->piwigo_photo_properties_dlg->SetProperties;
}

sub OnImageViewerItemActivated {
    my( $self, $event ) = @_;
    
    $self->current_imageviewer_index(
        $event->GetIndex
    );

    $self->OnPhotoProperties;
}


sub OnImageViewerItemSelected {
    my( $self, $event ) = @_;

    my $bc = Wx::BusyCursor->new;
    my $indx = $event->GetIndex;

    $self->piwigo_photo_properties_dlg->SetEnabled 
        if !$self->piwigo_photo_properties_dlg->IsEnabled;
    $self->_on_imageviewer_item_selected($indx);

    $event->Skip;

}

sub OnImageViewerItemDeSelected {
    my( $self, $event ) = @_;

    my $bc = Wx::BusyCursor->new;
    $self->_on_imageviewer_item_selection_changed;

    $event->Skip;

}

sub _on_imageviewer_item_selected {
    my ( $self, $index ) = @_;    
    $self->current_imageviewer_index($index);
    $self->imagelist->SetCurrentImage($index);
    
    $self->_on_imageviewer_item_selection_changed;
}

sub _on_imageviewer_item_selection_changed {
    my ( $self ) = @_;    

    $self->imagelist->image_selection(
        $self->imageviewer->GetSelectedItems
    );

    # for batch mode : reset the batch buffer if single selection
    if($self->multi_selection_mode){
        $self->OnUpdateMultiSelectionModeUI;
        $self->imagelist->SetImageSelectionTags([]);
        $self->imagelist->image_selection_privacy_level(-1);
        $self->imagelist->image_selection_name("");
        $self->imagelist->image_selection_author("");
        $self->imagelist->image_selection_comment("");
        $self->imagelist->image_selection_create_date(-1);
    }
    else{
        $self->OnUpdateSingleSelectionModeUI;
    }
    # process image_preview in idle time
    # and when current event is processed
    # see call to EVT_IDLE
    $self->image_preview_need_refresh(1);

    $self->piwigo_photo_properties_dlg->SetProperties if defined $self->piwigo_photo_properties_dlg;
    $self->exif_dlg->Refresh;
    $self->piwigo_photo_properties_tags->RefreshChoices;

}

sub multi_selection_mode {
    my ( $self ) = @_;

    scalar @{$self->imagelist->image_selection} > 1;
}

sub OnUpdateMultiSelectionModeUI{
    my( $self ) = @_;


    $self->piwigo_photo_properties_dlg->SetMultiSelectionMode(
        $self->imageviewer->GetSelectectItemsCount
    );
}

sub OnUpdateSingleSelectionModeUI{
    my( $self ) = @_;

    $self->piwigo_photo_properties_dlg->SetSingleSelectionMode;
}


sub set_preview_image {
    my ( $self ) = @_;    

    my $current_image = $self->imagelist->current_image;
    my $image = Wx::Image->new;
    $image->LoadFile(
        $current_image->file, 
        wxBITMAP_TYPE_ANY
    );
  
    if($self->imagelist->auto_rotate){
        # exif from original image
        my $orientation = $current_image->exif_metadata->{Orientation};

        # Valid for Rotate 180, Rotate 90 CW, Rotate 270 CW
        if( $orientation =~ m/Rotate (\d+)/ ){
            for(my $i=0; $i < floor($1/90) ; $i++){
                $image = $image->Rotate90;
            }                
        }
    }

    $self->image_preview_dlg->image_size(
        [$image->GetWidth, $image->GetHeight, ]
    );        

    $self->image_preview_dlg->image(
        $image
    );        
}

sub OnImageViewerKeyDown {
    my( $self, $event ) = @_;

    if(WXK_DELETE == $event->GetKeyCode){
        $self->OnRemoveImages();
        
        my $index = $self->current_imageviewer_index < $self->imageviewer->GetItemCount ?
            $self->current_imageviewer_index : $self->imageviewer->GetItemCount -1 ;
        $self->imageviewer->SelectItem(
            $index
        );
        $self->imageviewer->EnsureVisible(
            $index
        );
    }    

}


sub OnUploadImages {
    my( $self, $event ) = @_;

    my $select_all = 1;
    eval {
        $self->ProcessImageSelection( $select_all );    
    };
}

# remove image from imagelist when uploaded
sub UploadImagesViewerRefresh {
    my ( $self ) = @_;    


    $self->imageviewer->Refresh;

    if(!$self->imageviewer->GetItemCount){
        $self->image_preview_dlg->image(0);
        $self->OnUpdateImageviewerEmpty;
    }
    # reset previous selection
    $self->imagelist->image_selection(
        []
    );

    if(!$self->multi_selection_mode){
        $self->OnUpdateSingleSelectionModeUI;
    }

    $self->image_preview_dlg->Refresh;
    Wx::Yield();
}

sub UploadProgressMessageRefresh {
    my ( $self, $msg ) = @_;    

    Wx::Yield();

    $self->upload_progressdlg->processing(
        $msg   
    );    
    $self->upload_progressdlg->LogProgress();

    Wx::Yield();
}

sub UploadProgressMessageDetailsRefresh {
    my ( $self, $msg ) = @_;    

    Wx::Yield();

    $self->upload_progressdlg->processing_details(
        $msg   
    );    
    $self->upload_progressdlg->LogProgress();

    Wx::Yield();
}


sub UploadProgressThumbnailRefresh {
    my ( $self ) = @_;    

    my $imagelist = $self->imagelist ;

 
    $self->upload_progressdlg->image->SetBitmap(wxNullBitmap);
    $self->upload_progressdlg->image->SetBitmap(
        Wx::Bitmap->new( 
            $self->imagelist->current_image->wx_thumb_file, 
            $self->GetWxBitmapType($self->imagelist->type), 
        )
    );

    Wx::Yield();
}

sub UploadProgressBarRefresh {
    my ( $self, $value ) = @_;    

    eval {
        $self->upload_progressdlg->progress(
            $value
        );
        $self->upload_progressdlg->LogProgress();
    };
    #croak gettext("Upload cancelled") if $@;

    Wx::Yield();
}

sub SetNewFilesDisplayEndInfo {
    my ( $self, $msg, $errors ) = @_;    
    
    if($errors){
        $self->progressdlg->DisplayEndInfo($msg);
    }
    else{
        $self->progressdlg->Show(0);
    }
}

sub UploadDisplayEndInfo {
    my ( $self, $msg ) = @_;    
    
    my $imagelist = $self->imagelist ;
    
    $self->upload_progressdlg->DisplayEndInfo($msg);
}

sub ShowImageViewer {
    my ( $self ) = @_;    

    if(!$self->imageviewer->IsShown){
        $self->imageviewer->Show(1);
    }
}


sub SetNewFilesViewerRefresh {

    my ( $self ) = @_;    

    my $wximagelist = $self->imagelist->wx_thumb_imglist;
    #print Dumper "SetNewFilesViewerRefresh", $self->imagelist->current_image;
    my $indx = $wximagelist->Add(
        Wx::Bitmap->new( 
            $self->imagelist->current_image->wx_thumb_file, 
            $self->GetWxBitmapType($self->imagelist->type), 
        )
    ) if defined $self->imagelist->current_image->wx_thumb_file;
    #print $self->imagelist->current_image->wx_thumb_file, " added with index ", $indx, "\n";    
    
    $self->imageviewer->Refresh(
        $wximagelist
    );

    $self->OnUpdateImageviewerNotEmpty if $self->imageviewer->GetItemCount;

    Wx::Yield();
}


sub GetWxBitmapType {
    my ( $self, $type ) = @_;
    
    $self->{IMGTYPE}->{$type};
}


# prepare and upload image_selection
sub ProcessImageSelection {
    my ( $self, $select_all ) = @_;

    return if wxTheApp->CheckUpload;
    return if !scalar @{$self->imagelist->sums};

    if( $self->destination_categories_are_empty ){
        return unless $self->destination_category_dlg->ShowModal != wxID_CANCEL;
    }

    $self->imagelist->image_selection(
        $self->imageviewer->GetAllItems
    ) if $select_all;
       
    return if( !defined $self->imagelist->image_selection );
    return if( !scalar @{$self->imagelist->image_selection} );
        
    $self->upload_progressdlg->Destroy if defined $self->upload_progressdlg;
    $self->upload_progressdlg(
        Uploader::GUI::wxImageProcessingProgressDlg->new(
            { 
                title    => gettext("Image upload progress information"),
                bt_label => gettext("Cancel upload"),
                bt_close_label => gettext("Close"), 
                stop_processing => sub { $self->imagelist->stop_processing(1); Wx::Yield(); }, 
            }
        )
    );

    # modeless dialog
    $self->upload_progressdlg->Show(1);
    Wx::Yield();
    eval {
        $self->imagelist->UploadSelection;
    };
    if($@){
        Wx::MessageBox( 
            sprintf(
                gettext("Upload cancelled"),
            ),
            gettext("Piwigo upload information"),
            wxOK | wxICON_INFORMATION, 
        );
    }
}


sub destination_categories_are_empty {
    my ( $self ) = @_;

    !scalar @{$self->imagelist->categories};
}


sub SetNewFilesProgress {
    my ( $self ) = @_;

    my $imagelist = $self->imagelist;

    $self->progressdlg->processing(
        sprintf(
            $imagelist->progress_msg, 
            $imagelist->current_image->file,
        )
    );

    eval {
        $self->progressdlg->image->SetSize([ $imagelist->wx_thumb_size, $imagelist->wx_thumb_size]);
        $self->progressdlg->image->SetBitmap(wxNullBitmap);
        $self->progressdlg->image->SetBitmap(
            Wx::Bitmap->new( 
                $imagelist->current_image->wx_thumb_file,
                $self->GetWxBitmapType( $imagelist->type )
            )
        );
        $self->progressdlg->progress(
            $imagelist->count * ( 100/scalar @{$imagelist->new_files} )
        );
        $self->progressdlg->LogProgress();
    };
    Wx::Yield();
}

sub OnClose {
  my $self = shift;


    # Restaure previous log wnd
    Wx::Log::SetActiveTarget( $self->oldlogwnd );

    # allways store
  
    wxTheApp->StoreConnectionProperties;
    
    $self->imagelist->Store;
    wxTheApp->login_dlg->Destroy;    

    
    wxTheApp->imageviewerIndex(
        $self->current_imageviewer_index
    );
    
    my $frameLayout = {};
    
    ( $frameLayout->{pX}, $frameLayout->{pY}, $frameLayout->{W}, $frameLayout->{H} ) = ( $self->GetPositionXY, $self->GetSizeWH ) ; 
    
    wxTheApp->frameLayout(
        $frameLayout
    );

    wxTheApp->StoreLayoutProperties;

    #destroy hidden dialogs
    $self->global_settings_dlg->Destroy;
    $self->image_preview_dlg->Destroy;
    $self->exif_dlg->Destroy;
    $self->destination_category_dlg->Destroy;

    $self->progressdlg->Destroy if defined $self->progressdlg;
    $self->upload_progressdlg->Destroy if defined $self->upload_progressdlg;

    $self->Destroy;
}


sub create_toolbar {
    my( $self ) = @_;

    my $tb = Wx::ToolBar->new( $self, -1, wxDefaultPosition, [600, -1], wxTB_FLAT|wxTB_TEXT );
    $tb->SetToolBitmapSize( wxSIZE( 32, 32 ) );
    map {
        my $icon1 = Wx::Icon->new();
        eval {
            $icon1->LoadFile($_->[2], $_->[3]);
        };
        my $tb_icon1 = Wx::Bitmap->new( $icon1 );

        my $icon2 = Wx::Icon->new();
        eval {
            $icon2->LoadFile($_->[5], $_->[3]);
        };
        my $tb_icon2 = Wx::Bitmap->new( $icon2 );


        $tb->AddTool( $_->[0], $_->[1], $tb_icon1, $tb_icon2, wxITEM_NORMAL, $_->[6] );
        $tb->EnableTool( $_->[0], $_->[4]);
    }
    (
        [
            101, 
            gettext("Add photos"), 
            wxTheApp->resource_path('tb_add.png'), 
            wxBITMAP_TYPE_PNG, 
            1, 
            wxTheApp->resource_path('tb_add.png'), 
            gettext("Add photos for resizing and uploading")
        ],
        [
            102, 
            gettext("Remove selected photos"), 
            wxTheApp->resource_path('tb_remove.png'), 
            wxBITMAP_TYPE_PNG, 
            1, 
            wxTheApp->resource_path('tb_remove.png'),
            gettext("Remove selected photos. Original files are not deleted")
        ],
        [
            104, 
            gettext("Preferences"), 
            wxTheApp->resource_path('tb_settings.png'), 
            wxBITMAP_TYPE_PNG, 
            0, 
            wxTheApp->resource_path('tb_settings.png'),
            gettext("Change global settings")
        ],
    
    );
    
    $tb->AddSeparator;
    
    $tb->AddControl(
        Wx::Choice->new(
        $tb,
            106,
            wxDefaultPosition,
            [300, -1],
            [],
        )
    );
    my $ch = $tb->FindWindow(106);
    $ch->SetToolTip(gettext("How photo selection is displayed"));
    map {
        $ch->Append(gettext($_), $_);
    }(
        "Thumbnail and caption",
        "Thumbnail",
        "Property list"
    );
    
    $ch->SetStringSelection(gettext($self->imagelist->display_mode));
    $tb->Realize;

    $self->toolbar(
        $tb
    );
    $self->SetToolBar($tb);

    return $tb;
}

sub OnPhotoSelMode {
    my ( $self, $event )= @_;
    
    $self->imagelist->display_mode(
        $event->GetClientData
    );

    $self->imageviewer->change_display_mode(1);
}

sub _create_textctrl {
    my( $self, $parent, $text, $size ) = @_;

    return Wx::TextCtrl->new( $parent, -1, $text, [0, 0], $size,
                              wxNO_BORDER | wxTE_MULTILINE | wxTE_READONLY  );
}

sub create_textctrl {
    my( $self, $text, $size ) = @_;

    return $self->_create_textctrl( $self, $text, $size );
}

sub DESTROY {
    my( $self ) = @_;

}



1;





package DNDImageListDropTarget;
use Wx qw/wxTheApp/;
use base qw(Wx::FileDropTarget Class::Accessor::Fast);

__PACKAGE__->mk_accessors( 
    qw/
          imageviewer
      /
);

sub new {
  my $class = shift;
  my $imageviewer = shift;
  my $self = $class->SUPER::new( @_ );

  $self->imageviewer($imageviewer);

  return $self;
}

sub OnDropFiles {
  my( $self, $x, $y, $files ) = @_;

  wxTheApp->frame->SetNewFiles($files) ;
}




1;


package DNDCategoryTreeDropTarget;

use base qw(Wx::TextDropTarget Class::Accessor::Fast);
use Data::Dumper;
use Wx qw/
              wxDragNone
              wxDragCopy
              wxDragMove
              wxTheApp
         /;

__PACKAGE__->mk_accessors( 
    qw/
          tree
      /
);

sub new {
  my ( $class, $tree ) = @_;
  my $self = $class->SUPER::new();

  $self->tree($tree);

  return $self;
}



sub OnDropText {
  my( $self, $x, $y, $textdata ) = @_;

  # must be $VAR1 because $textdata is the result of Data::Dumper
  my $VAR1;
  eval $textdata;
  eval {
      if(scalar @$VAR1){
             my @items;
             if(scalar @items < 2) {
               my ($dropItem, $flag) = $self->tree->HitTest([$x, $y]);
                 push @items, $dropItem;
             }
             else {
                 @items = $self->tree->GetSelections;
             }
             
             # remove root item which is not a valid category
             @items = grep { $self->tree->GetPlData( $_ ) != -1 } @items;
             
             wxTheApp->frame->imagelist->categories(
                 [
                     map {
                         $self->tree->GetPlData( $_ )->{id};
                     }
                     @items
                 ]
             );
           
             wxTheApp->frame->imagelist->image_selection($VAR1);
             wxTheApp->frame->ProcessImageSelection ;
      }    
  };
}


1;
