package Uploader::GUI::App;
use threads;
use threads::shared;
use Thread::Queue;
use strict;
use base qw/Wx::App Class::Accessor::Fast/;
use Wx qw/
    wxBITMAP_TYPE_GIF 
    wxBITMAP_TYPE_ICO 
    wxBITMAP_TYPE_BMP 
    wxBITMAP_TYPE_PNG 
    wxBITMAP_TYPE_JPEG
    wxIMAGE_QUALITY_HIGH
    wxSPLASH_CENTRE_ON_SCREEN 
    wxSPLASH_TIMEOUT
    wxDefaultPosition
    wxDefaultSize
    wxSIMPLE_BORDER
    wxFRAME_TOOL_WINDOW
    wxFRAME_NO_TASKBAR wxSTAY_ON_TOP
    wxWHITE
    wxICON_EXCLAMATION
    wxICON_QUESTION
    wxOK
    wxYES
    wxYES_NO
    wxNO_DEFAULT
    wxICON_ERROR
    wxLANGUAGE_CHINESE_SIMPLIFIED
    wxLANGUAGE_CZECH
    wxLANGUAGE_DANISH
    wxLANGUAGE_DUTCH
    wxLANGUAGE_ENGLISH
    wxLANGUAGE_FRENCH
    wxLANGUAGE_GERMAN
    wxLANGUAGE_HUNGARIAN
    wxLANGUAGE_ITALIAN
    wxLANGUAGE_JAPANESE
    wxLANGUAGE_POLISH
    wxLANGUAGE_PORTUGUESE
    wxLANGUAGE_PORTUGUESE_BRAZILIAN
    wxLANGUAGE_RUSSIAN
    wxLANGUAGE_SLOVAK
    wxLANGUAGE_SPANISH
/;
use Wx::Locale qw/:default/;
use File::HomeDir;
use Uploader::PWG;
use Uploader::Images;
use Uploader::Connection;
use Uploader::Preferences;
use Uploader::ResizeManager;
use Uploader::TransferManager;
use Uploader::GUI::LoginDlg;
use Storable;
use utf8;
use Data::Dumper;
use IO::Socket;
use Wx::Socket;

my $received_filename_event : shared = Wx::NewEventType;
my $transfer_progress_event : shared = Wx::NewEventType;
my $transfer_done_event : shared = Wx::NewEventType;
my $transfer_batch_end_event : shared = Wx::NewEventType;
my $resize_done_event : shared = Wx::NewEventType;
my $resize_progress_event : shared = Wx::NewEventType;
my $resize_batch_end_event : shared = Wx::NewEventType;

my $image_progress_event = Wx::NewEventType;

$|=1;


my @app_properties = qw/
    localized_msg
    version
    frame
    argv
    images
    images_version
    preferences
    preferences_version
    user_def_preferences
    privacy_level
    upload_hd
    resize_manager
    transfer_manager
/;


my @connection_properties = qw/
    connection_version
    connection
    login_dlg
    branding
    use_offline
    use_connected
    pwg
/;


my @file_properties = qw/
    bin_dir
    resource_dir
    thumb_dir
    resized_dir
    wx_thumb_dir
    userdata_dir
    root_dir
    locale_dir
    preferences_file
    connection_file
    images_file
    app_file
    instance_checker_file
/;


my @localized_properties = qw/
    colors
    positions
    upload_hd
    caption_patterns
/;


my @language_properties = qw/
    current_language
    locale
    languages
    available_languages
    eng_colors
    eng_positions
    eng_upload_hd
    eng_caption_patterns
/;


my @custom_events = qw/
    resize_start_event
    batch_end_event
    image_progress_event
    image_done_event
/;

__PACKAGE__->mk_accessors(@app_properties);
__PACKAGE__->mk_accessors(@file_properties);
__PACKAGE__->mk_accessors(@connection_properties);
__PACKAGE__->mk_accessors(@localized_properties);
__PACKAGE__->mk_accessors(@language_properties);
__PACKAGE__->mk_accessors(@custom_events);

my $_params;

sub new {
    my ( $self, $params ) = @_;

    $_params = $params;

    $self->SUPER::new();

}


sub OnInit {
    my( $self ) = @_;

    $self->init_properties_from_params;
    $self->init_application_properties;
    $self->init_single_instance_checker;
    $self->init_file_properties;
    $self->init_locale;
    $self->init_localized_properties;
    $self->init_preferences;
    $self->init_resize_manager;
    $self->init_images;

    return 0 unless $self->is_single_instance_server;

    $self->connect_or_exit;

}


sub OnExit {
    my( $self ) = @_;

    unlink $self->instance_checker_file
        if -e $self->instance_checker_file;
    $self->store_all;

}


sub store_all {
    my( $self ) = @_;

    $self->connection->Store;;
    $self->images->Store;
    $self->preferences->Store;

}


sub reset_add_rank {
    my ( $self ) = @_;

    $self->images->reset_add_rank;
}


sub cancel_all {
    my ( $self ) = @_;

    $self->cancel_transfer if $self->cancel_resize;
}


sub stop_all {
    my( $self ) = @_;

    $self->resize_manager->stop;
    $self->transfer_manager->stop;
    $self->stop_single_instance_server;
    $self->login_dlg->Destroy;    



}


sub init_properties_from_params {
    my ( $self ) = @_;

    map {
        $self->$_(
            $_params->{$_}
        )
    } keys %$_params;

}


sub init_application_properties {
    my ( $self ) = @_;

    $self->version(
        '1.7'
    );
    

    Wx::InitAllImageHandlers();

    $self->{IMGTYPE} = {
        'jpg' => wxBITMAP_TYPE_JPEG,
        'gif' => wxBITMAP_TYPE_GIF,
        'png' => wxBITMAP_TYPE_PNG,
    };

    my $applicationName = "pLoader" ;
    $self->SetAppName( $applicationName );
    $self->SetVendorName( "Piwigo Team" );


}


sub init_single_instance_checker {
    my ( $self ) = @_;


    my $id_user=$ENV{USERNAME} || $ENV{USER} || $ENV{LOGNAME};
    # must save the object
    $self->{_instance_checker} = Wx::SingleInstanceChecker->new;
    my $pid = sprintf(
        "%s-%s",
        $self->GetAppName,
        $id_user,
    );
    $self->{_instance_checker}->Create(
        $pid
    );

    $self->instance_checker_file(
        File::Spec->canonpath(
            File::Spec->catfile(
                File::HomeDir->my_home(),
                $pid
            )
        )
    );

}


sub init_file_properties {
    my ( $self ) = @_;
    
    my $applicationName = $self->GetAppName ;
    my $userdatadir = File::Spec->canonpath(
        File::Spec->catfile(
            File::HomeDir->my_data(), 
            $applicationName
        )
    );

    if(! -d $userdatadir){
        if(! mkdir $userdatadir){
            Wx::MessageBox( 
                sprintf(
                    "%s directory creation failed",
                    $userdatadir,
                ),
                "pLoader working directory creation error",
                wxOK | wxICON_EXCLAMATION, 
            );

            $userdatadir = File::Spec->canonpath(
                File::Spec->catfile(
                    File::Spec->tmpdir(), 
                    $applicationName
                )
            );
            mkdir $userdatadir;
        }    
    }

    $self->userdata_dir($userdatadir);

    $self->app_file(
        $self->userdata_filepath("$applicationName.dat")
    );

    $self->preferences_file(
        $self->userdata_filepath("preferences.dat")
    );

    $self->connection_file(
        $self->userdata_filepath("connection.dat")
    );

    $self->images_file(
        $self->userdata_filepath("images.dat")
    );
    
    my $thumbdir = $self->userdata_filepath('thumbnails');
    mkdir $thumbdir unless -d $thumbdir ;
    $self->thumb_dir($thumbdir);

    my $wxthumbdir = $self->userdata_filepath('wxthumbnails');
    mkdir $wxthumbdir unless -d $wxthumbdir ;
    $self->wx_thumb_dir($wxthumbdir);


    my $resizedir = $self->userdata_filepath('resize');
    mkdir $resizedir unless -d $resizedir ;
    $self->resized_dir($resizedir);
}


sub userdata_filepath {
    my ( $self, $filename ) = @_;

    File::Spec->catfile(
        $self->userdata_dir,
        $filename
    );
}


sub read_params {
    my( $self, $file ) = @_ ;

 
    my $expr_params ;
    eval { $expr_params = read_file( $file ); } ;
    
    my $paramValues = [] ;
    if($expr_params){
        my $expr = '$paramValues = ' ;
        $expr .=  "$expr_params ; " ;
        eval $expr ;
    }
    
    return unless 'ARRAY' eq ref $paramValues ;
    
    if(scalar(@$paramValues )){
        my $params = $paramValues->[0] ;
        $self->set_key_values($params);
    }

}


sub set_key_values {
    my ( $self, $params )= @_;    

    foreach( keys %$params ) {
        $self->{$_} = $params->{$_} ;
    }
}


sub init_connection {
    my ( $self ) = @_;

    $self->connection_version('0.1');

    my $stored = $self->retrieve_from_file(
        $self->connection_file,
        $self->connection_version
    );

    $self->connection(
        $stored ?
        Uploader::Connection->new(
            $stored
        ):
        Uploader::Connection->new(
            $self->default_connection
        )
    );

}


sub default_connection {
    my ( $self ) = @_;

    my $connection = {
        version          => $self->connection_version,
        storable_file    => $self->connection_file,
    };

    return $connection;
}

my $locale;
sub init_locale {
    my ( $self, $language ) = @_;

    $self->languages(
      [
             ["中文 (%s)", wxLANGUAGE_CHINESE_SIMPLIFIED, 'Chinese simplified'],   
             ["Česky (%s)", wxLANGUAGE_CZECH, 'Czech'],   
             ["Dansk (%s)", wxLANGUAGE_DANISH, 'Danish'],   
             ["Deutsch (%s)", wxLANGUAGE_GERMAN, 'German'],   
             ["English (%s)", wxLANGUAGE_ENGLISH, 'English'],   
             ["Español (%s)", wxLANGUAGE_SPANISH, 'Spanish'],   
             ["Français (%s)", wxLANGUAGE_FRENCH, 'French'],   
             ["Italiano (%s)", wxLANGUAGE_ITALIAN, 'Italian'],   
             ["日本語 (にほんご) (%s)", wxLANGUAGE_JAPANESE, 'Japanese'],   
             ["Magyar (%s)", wxLANGUAGE_HUNGARIAN, 'Hungarian'],
             ["Nederlands (%s)", wxLANGUAGE_DUTCH, 'Dutch'],   
             ["Polski (%s)", wxLANGUAGE_POLISH, 'Polish'],   
             ["Português Brasileiro (%s)", wxLANGUAGE_PORTUGUESE_BRAZILIAN, 'Portuguese Brazil'],   
             ["Português Portugal (%s)", wxLANGUAGE_PORTUGUESE, 'Portuguese Portugal'],   
             ["Русский (%s)", wxLANGUAGE_RUSSIAN, 'Russian'],
             ["Slovenčina (%s)", wxLANGUAGE_SLOVAK, 'Slovak'],
      ]
    );
    # some languages may be unavailable due to system configuration.
    $self->filter_available_languages;

    $self->current_language(
        $language||$self->{current_language}||Wx::Locale::GetSystemLanguage()
    );

    undef $locale;
    $locale = Wx::Locale->new(
        $self->current_language
    );

    $locale->AddCatalogLookupPathPrefix(
        File::Spec->catfile($self->root_dir, $self->locale_dir)
    );
    if(!$locale->AddCatalog( 'pLoader.mo' )){
        Wx::LogMessage gettext("Cannot find translation catalog files for %s. Use default language"), $locale->GetCanonicalName();
    }
    $self->locale($locale);    
}


sub filter_available_languages {
    my ( $self ) = @_;

    # check if the locale can be set and the translation catalog available
    $self->available_languages(
        [
            grep {$_} 
            map{
                #  a locale may be unavailable due to system limitations ( ex: chinese, japanese when language pack are not installed )
                if(Wx::Locale::IsAvailable($_->[1])){
                    my $locale = Wx::Locale->new($_->[1]);
                    $locale->AddCatalogLookupPathPrefix(
                        File::Spec->catfile($self->root_dir, $self->locale_dir)
                    );
                    $_ if $locale->AddCatalog('pLoader');
                }
            }
            @{$self->languages}
        ]
    );
}


sub init_localized_properties {
    my ( $self ) = @_;

    $self->colors(
        ['Black', 'White']
    );

    # We need to translate back to english when we store properties
    $self->eng_colors(
        {
            map { gettext($_) => $_ } @{$self->colors} 
        }
    );

    $self->positions(
        [
            'Top',
            'Left',
            'Right',
            'Bottom',
            'Top left',
            'Top right',
            'Bottom left',
            'Bottom right',
            'Center',
        ]
    );

    $self->eng_positions(
        { 
             map { gettext($_) => $_ } @{$self->positions} 
        }
    );

    $self->upload_hd(
        [
            'No',
            'Yes, use HD resized of the original photo',
            'Yes, use a copy of the original photo',
        ]
    );

    $self->eng_upload_hd(
        {
             map { gettext($_) => $_ } @{$self->upload_hd} 
        }
    );
    

    $self->caption_patterns(
        [
             'None',
             'File name',
             'File path and name',
             'Caption',
             'Caption + rank number',
             'Rank number + caption',
             'Caption + create date chrono',
             'Create date chrono + caption',
             'Create date chrono + rank',
             'Rank + create date chrono',
        ]
    );

    $self->eng_caption_patterns(
        {
             map { gettext($_) => $_ } @{$self->caption_patterns} 
        }
    );
    
    # hard coded because the piwigo api to read custom privacy level is not yet available
    $self->privacy_level(
        [
            'everybody',
            'contacts',
            'friends',
            'family',
            'admins'
        ]
    );


    $self->localized_msg(
        {
             map { $_ => gettext($_) } (
                 'cancelled',
                 'sending files',
                 'checking files',
                 'files checked',
                 'transfered',
                 'updating',
                 'updating files',
                 'files updated',
                 'updating properties',
                 'properties updated',
                 'prepared, waiting for transfer',
                 'preparing web size',
                 'web size prepared',
                 'preparing high',
                 'high prepared',
                 'start sending',
                 'sending',
                 
             )
        }
    );

    print Dumper $self->localized_msg;

}


# display privacy level list in a pyramid way :
# ['everybody', 'contacts', friends, family, admins] -> [everybody, 'contacts, friends, family, admins', 'friends, family, admins', 'family, admins', 'admins only' ]
sub privacy_level_choices{
    my ( $self ) = @_;

    my $pl = $self->privacy_level;    
    my $n = scalar @$pl - 1;
    my $list = [ gettext($pl->[0]) ];
    my $i=0;
    while(++$i<$n){    
        push @$list, join(
            ', ', 
            map{ gettext($_) }
            @$pl[$i..$n] 
        );
    }
    push @$list, gettext($pl->[$n]);
    
    $list;
}


sub init_preferences {
    my ( $self ) = @_;    

    $self->preferences_version('0.1');

    my $stored = $self->retrieve_from_file(
        $self->preferences_file,
        $self->preferences_version
    );

    $self->preferences(
        $stored ?
        Uploader::Preferences->new(
            $stored
        ):
        Uploader::Preferences->new(
            $self->default_preferences
        )
    );
}


sub retrieve_from_file {
    my ( $self, $file, $version ) = @_;


    my $stored;
    
    if( -e $file ){
        eval {
            $stored = retrieve $file;
        };
        if($@){
            warn(
                "An error has occured. Can not read %s\n%s",
                $file, 
                $@
            );
            undef $stored;
        }
        # should have a valid images
        else{
            undef $stored unless $version eq $stored->{version};
        }
    }

    $stored;
}


sub default_preferences {
    my ( $self ) = @_ ;

    # must be read in a ini file
    $self->user_def_preferences(
        {}
    );

    my $preferences = {
        version => $self->preferences_version,
        storable_file    => $self->preferences_file,
        hd_filter        => $self->user_def_preferences->{hd_filter}||'Lanczos',
        hd_blur          => $self->user_def_preferences->{hd_blur}||0.9,
        hd_quality       => $self->user_def_preferences->{hd_quality}||95,
        hd_w             => $self->user_def_preferences->{hd_w}||1600,
        hd_h             => $self->user_def_preferences->{hd_h}||1200,
        hd_interlace     => $self->user_def_preferences->{hd_interlace}||'Line',
        thumb_size       => $self->user_def_preferences->{thumbnail_size}||120,
        wx_thumb_size    => $self->user_def_preferences->{wx_thumbnail_size}||100,
        resize_w         => $self->user_def_preferences->{resize_w}||800,
        resize_h         => $self->user_def_preferences->{resize_h}||600,
        type             => 'jpg',
        filter           => $self->user_def_preferences->{resize_filter}||'Lanczos',
        blur             => $self->user_def_preferences->{resize_blur}||0.9,
        quality          => $self->user_def_preferences->{resize_quality}||95,
        wx_quality       => $self->user_def_preferences->{wx_thumbnail_quality}||90,
        th_quality       => $self->user_def_preferences->{thumbnail_quality}||90,
        auto_rotate      => $self->user_def_preferences->{auto_rotate}||1,
        upload_hd        => $self->user_def_preferences->{upload_hd}||'No',
        remove_uploaded_from_selection => $self->user_def_preferences->{remove_uploaded_from_selection}||1,
        interlace        => $self->user_def_preferences->{resize_interlace}||'Line',
        create_resized   => $self->user_def_preferences->{create_resized}||1,
        prefix           => 'TN',
        default_caption_pattern => $self->user_def_preferences->{default_caption_pattern}||'File name',
        default_caption  => $self->user_def_preferences->{default_caption}||gettext('Photo '),
        watermark_text => $self->user_def_preferences->{watermark_text}||gettext("my watermark"),
        watermark_text_size => $self->user_def_preferences->{watermark_text_size}||12,
        watermark_position => $self->user_def_preferences->{watermark_position}||'Center',
        watermark_y => $self->user_def_preferences->{watermark_y}||10,
        watermark_x => $self->user_def_preferences->{watermark_x}||10,
        watermark_color => $self->user_def_preferences->{watermark_color}||'White',
        reupload_action_files => 1,
        reupload_action_properties => 2,
        reupload_action_properties_m => 1,
        display_mode => $self->user_def_preferences->{display_mode}||'Thumbnail and caption',
        chunk_size   => $self->user_def_preferences->{chunk_size}||500000,
    };

    return $preferences;
}


sub init_resize_manager {
    my ( $self ) = @_;

    $self->resize_start_event(
        Wx::NewEventType
    );

    $self->resize_manager(
        Uploader::ResizeManager->new({
            thumb_dir       => $self->thumb_dir,
            wx_thumb_dir    => $self->wx_thumb_dir,
            resized_dir     => $self->resized_dir,
            preferences     => sub { $self->preferences(@_) },
            progress_event  => $resize_progress_event,
            done_event      => $resize_done_event,
            batch_end_event => $resize_batch_end_event,
            event_handler   => $self,
            localized_msg   => $self->localized_msg,
        })
    );

    $self->init_resize_batch_end_event_handler;
    $self->init_resize_done_event_handler;
    $self->init_resize_progress_event_handler;
}


sub init_resize_batch_end_event_handler {
    my ( $self ) = @_;

    Wx::Event::EVT_COMMAND(
        $self,
        -1,
        $resize_batch_end_event,
        sub {
            my ( $handler, $event ) = @_;
            my $msg : shared = shared_clone($event->GetData);
            # add the batch end message to the queue
            $self->transfer_manager->add_images([ $msg ]);
        } 
    );

}


sub init_resize_done_event_handler {
    my ( $self ) = @_;

    Wx::Event::EVT_COMMAND(
        $self,
        -1,
        $resize_done_event,
        sub {
            my ( $handler, $event ) = @_;
            my $image : shared = shared_clone($event->GetData);
            $handler->on_image_progress($image);
            # image is prepared, send to transfer queue
            $self->transfer_manager->add_images([ $image ]);
        } 
    );

}


sub init_resize_progress_event_handler {
    my ( $self ) = @_;

    Wx::Event::EVT_COMMAND(
        $self,
        -1,
        $resize_progress_event,
        sub {
            my ( $handler, $event ) = @_;
            my $data : shared = shared_clone($event->GetData);
            $handler->on_image_progress($data);
        } 
    );

}


sub on_batch_end {
    my ( $self, $image ) = @_;

    Wx::PostEvent(
        $self->frame,
        Wx::PlThreadEvent->new(
            -1,
            $self->batch_end_event,
            $image
        )
    );
}


sub on_image_progress {
    my ( $self, $image ) = @_;

    Wx::PostEvent(
        $self->frame,
        Wx::PlThreadEvent->new(
            -1,
            $self->image_progress_event,
            $image
        )
    );
}


sub on_image_done {
    my ( $self, $image ) = @_;

    Wx::PostEvent(
        $self->frame,
        Wx::PlThreadEvent->new(
            -1,
            $self->image_done_event,
            $image
        )
    );
}

sub init_images {
    my ( $self ) = @_;

    $self->images_version('0.1');

    my $stored = $self->retrieve_from_file(
        $self->images_file,
        $self->images_version,
    );

    $self->images(
        $stored ?
        Uploader::Images->new(
            $stored
        ):
        Uploader::Images->new(
            {
                storable_file => $self->images_file,
                version       => $self->images_version,
            }
        )
    );

    $self->images->eng_caption_patterns(
        $self->eng_caption_patterns
    );

    $self->images->create_wx_thumbnail_cbk(
        sub { $self->resize_manager->create_wx_thumbnail(@_) }
    );

    $self->images->default_caption_cbk(
        sub { $self->preferences->default_caption(@_) }
    );

    $self->images->default_caption_pattern_cbk(
        sub { $self->preferences->default_caption_pattern(@_) }
    );

    $self->images->set_current_image(-1);
}


sub is_single_instance_server {
    my ( $self ) = @_;

    if($self->is_single_instance_running){
        printf("connect_to_single_instance_server\n");
        $self->connect_to_single_instance_server;
        printf("connected to single_instance_server\n");
        return 0;
    }
    else{
        printf("start_single_instance_server\n");
        $self->start_single_instance_server;
        printf("single_instance_server started\n");
        return 1;
    }
}


sub is_single_instance_running {
    my ( $self ) = @_;

    $self->{_instance_checker}->IsAnotherRunning;
} 


my $single_instance_port = 9101;


sub connect_to_single_instance_server {
    my ( $self ) = @_;

    my $socket = IO::Socket::INET->new(
        PeerAddr => '127.0.0.1',
        PeerPort => $single_instance_port,
        Proto    => 'tcp',
        Type     => IO::Socket::SOCK_STREAM(),
    );

    # if connection successful, server sends pid
    if ($socket) {
        my $pid = '';
        my $read = $socket->sysread( $pid, 10 );
        if ( defined $read and $read == 10 ) {
            my $files = join(',', @{$self->argv});
            printf("send to server %s\n", $files);
            $socket->print("open $files\n");
            #$socket->print("focus\n");
            $socket->close;
            return 0;
        }
    }
}


sub start_single_instance_server {
    my ( $self ) =@_;

    $self->{_single_instance_server} = Wx::SocketServer->new(
        '127.0.0.1' => $single_instance_port,
        Wx::wxSOCKET_NOWAIT Wx::wxSOCKET_REUSEADDR,
    );

    if( $self->{_single_instance_server}->Ok ) {
        Wx::Event::EVT_SOCKET_CONNECTION(
            $self,
            $self->{_single_instance_server},
            sub {
                $self->single_instance_connect( $_[0] );
            }
        );
    }
    else {
        delete $self->{_single_instance_server};
        warn( Wx::gettext("Failed to create single instance server") );
    }

    return 1;

}


sub single_instance_connect {
    my $self   = shift;
    my $server = shift;
    my $client = $server->Accept(0);

    # Before we start accepting input,
    # send the client our process ID.
    $client->Write( sprintf( '% 10s', $$ ), 10 );

    # Set up the socket hooks
    Wx::Event::EVT_SOCKET_INPUT(
        $self, $client,
        sub {

            # Accept the data and stream commands
            my $command = '';
            my $buffer  = '';
            while ( $_[0]->Read( $buffer, 128 ) ) {
                $command .= $buffer;
                while ( $command =~ s/^(.*?)[\012\015]+//s ) {
                    $_[1]->single_instance_command( "$1", $_[0] );
                }
            }
            return 1;
        }
    );
    Wx::Event::EVT_SOCKET_LOST(
        $self, $client,
        sub {
            $_[0]->Destroy;
        }
    );

    return 1;
}

sub single_instance_command {
    my( $self, $line, $socket ) = @_;

    return 1 unless defined $line && length $line;

    # ignore the line if command isn't plain ascii
    return 1 unless $line =~ s/^(\S+)\s*//s;

    if ( $1 eq 'open' ) {
        if ( -f $line ) {
            printf("received from incoming connection %s\n", $line);
            $self->images->add_images(
                [
                    grep { -f $_} split(/,/, $line)
                ]
            );
        }
    } 
    else {
        warn("Unsupported command '$1'");
    }

    return 1;
}


sub stop_single_instance_server {
    my ( $self ) =@_;

    if(exists $self->{_single_instance_server}){
        $self->{_single_instance_server}->Destroy;
        delete $self->{_single_instance_server};
    }
}


sub default_app {
    my ( $self ) = @_ ;

    my $app = {
        thumb_dir   => $self->thumb_dir,
        wx_thumb_dir     => $self->wx_thumb_dir,
        resized_dir => $self->resized_dir,
        userdata_dir     => $self->userdata_dir,
        version          => $self->version,
        storable_file    => $self->app_file,

    };

    $app;
}


sub connect_or_exit {
    my ( $self ) = @_;


    my $not_exit = $self->login();
    $self->connection->Store;
    # user pressed OK
    if($not_exit){
        if( $self->use_connected ){
            while( $not_exit and $self->not_connected ){
                $not_exit = $self->login;
                last if $self->use_offline;
            }
            $self->init_transfer_manager;
        }
    }
    else {
        $self->resize_manager->stop;
        $self->stop_single_instance_server;
    }

    $not_exit;
}


sub login {
    my ( $self ) = @_;    

    $self->init_connection;

    $self->login_dlg( 
        Uploader::GUI::LoginDlg->new(
            {
                title         => gettext("Piwigo login"),
                site_url      => sub { $self->connection->site_url(@_) },
                site_username => sub { $self->connection->site_username(@_) },    
                site_password => sub { $self->connection->site_password(@_) },
                use_offline   => sub { $self->connection->use_offline(@_) },    
            }
        )
    ) unless $self->login_dlg;

    my $icon = Wx::Icon->new();
    $icon->LoadFile(
        $self->resource_path('favicon.ico'), 
        wxBITMAP_TYPE_ICO
    );

    $self->login_dlg->SetIcon($icon);

    
    my $rval = $self->login_dlg->ShowModal();
    $self->login_dlg->Show(0);

    $self->init_branding;
    
    if ($self->connection->site_url !~ /^http:/){
        $self->connection->site_url(
            sprintf(
                "http://%s",
                $self->connection->site_url
            )
        );    
    }

    $self->pwg(
        # get these parameters from dialog or from file
        Uploader::PWG->new(
            {
                site_url       => $self->connection->site_url,
                site_username  => $self->connection->site_username,
                site_password  => $self->connection->site_password,
                http_username  => $self->connection->http_username,
                http_password  => $self->connection->http_password,
                branding       => $self->branding,
                use_offline    => $self->use_offline,
                version        => $self->version,
                localized_msg  => $self->localized_msg,
            }
        )
    );

    $rval;
}


# helper method to get the full path for a resource
sub resource_path{
    my ( $self, $file ) = @_;

    File::Spec->catfile($self->root_dir, $self->resource_dir, $file);
}

sub bin_path{
    my ( $self, $file ) = @_;

    File::Spec->catfile($self->root_dir, $self->bin_dir, $file);
}

sub locale_path{
    my ( $self, $file ) = @_;

    File::Spec->catfile($self->root_dir, $self->locale_dir, $file);
}

sub locale_catalog_path{
    my ( $self, $file ) = @_;

    File::Spec->catfile($self->root_dir, $self->locale_dir, $self->locale->GetCanonicalName, $file);
}


# some labels differ with branding ( piwigo.com or piwigo.org )
sub init_branding {
    my ( $self ) =@_;
    
    if( $self->connection->site_url =~ /\.piwigo\.com/ ){
        $self->branding(
            {
                category  => gettext("album"),
                Category  => gettext("Album"),
                categories => gettext("albums"),
                Categories => gettext("Albums"),
                'Add new category' => gettext("Add new album"),
                'Category name' => gettext("Album name :"),
                'New category' => gettext("New album"),
                'What is the destination category?' => gettext("What is the destination album?")
            }
        );
    }
    else{
        $self->branding(
            {
                category  => gettext("categorie"),    
                Category  => gettext("Categorie"),    
                categories => gettext("categories"),    
                Categories => gettext("Categories"),    
                'Add new category' => gettext("Add new category"),
                'Category name' => gettext("Category name :"),
                'New category' => gettext("New category"),
                'What is the destination category?' => gettext("What is the destination category?")
            }
        );
    }    
}


sub use_connected {
    my ( $self ) = @_;

    !$self->use_offline
}


sub not_connected {
    my ( $self ) = @_;

    !$self->is_connected;
}


sub is_connected {
    my ( $self ) = @_;

    my $_is_connected;

    if($self->pwg->login_result->{stat} eq 'ok'){
        $_is_connected = 1;
    }
    else{
        Wx::MessageBox( 
            sprintf(
                "%s\n\n%s %s %s",
                $self->pwg->login_result->{message},
                gettext("Connection to"),
                $self->connection->site_url,
                gettext("failed"),
            ),
            gettext("Piwigo login error"),
            wxOK | wxICON_EXCLAMATION, 
        );
    }
    
    $_is_connected;
}


sub init_transfer_manager {
    my ( $self ) = @_;

    $self->check_upload;

    $self->transfer_manager(
        Uploader::TransferManager->new({
            pwg             => $self->pwg,
            progress_event  => $transfer_progress_event,
            done_event      => $transfer_done_event,
            event_handler   => $self,
            batch_end_event => $transfer_batch_end_event,
            localized_msg   => $self->localized_msg,
        })
    );

    $self->image_progress_event(
        Wx::NewEventType
    );

    $self->image_done_event(
        Wx::NewEventType
    );

    $self->batch_end_event(
        Wx::NewEventType
    );

    $self->init_transfer_batch_end_event_handler;
    $self->init_transfer_done_event_handler;
    $self->init_transfer_progress_event_handler;

}


sub check_upload {
    my ( $self ) = @_;

    my $err_msg = $self->pwg->check_upload;

    $err_msg = gettext("Your user account is not granted to upload photos") if
        'Access denied' eq $err_msg;

    #Wx::LogMessage("%s", $err_msg) if $err_msg;
    Wx::MessageBox($err_msg, "", wxOK | wxICON_ERROR) if $err_msg;

    $err_msg;
}


sub init_transfer_batch_end_event_handler {
    my ( $self ) = @_;

    Wx::Event::EVT_COMMAND(
        $self,
        -1,
        $transfer_batch_end_event,
        sub {
            my ( $handler, $event ) = @_;
            my $data = $event->GetData;
            $handler->on_batch_end($data);
        } 
    );

}


sub init_transfer_done_event_handler {
    my ( $self ) = @_;

    Wx::Event::EVT_COMMAND(
        $self,
        -1,
        $transfer_done_event,
        sub {
            my ( $handler, $event ) = @_;
            my $data = $event->GetData;
            $handler->on_image_done($data);
        } 
    );

}


sub init_transfer_progress_event_handler {
    my ( $self ) = @_;

    Wx::Event::EVT_COMMAND(
        $self,
        -1,
        $transfer_progress_event,
        sub {
            my ( $handler, $event ) = @_;
            my $data : shared = shared_clone($event->GetData);
            $handler->on_image_progress($data);
        } 
    );

}


sub start_resize {
    my( $self, $all_images ) = @_;

    # we need to copy data from object to use another thread
    my $images = $self->images->get_images(
        $self->preferences->get_data,
        $self->transfer_manager->destination_category,
        $all_images
    );

    push @$images, { event => "BATCH_END" };

    $self->resize_manager->add_images($images);

    Wx::PostEvent(
        $self->frame,
        Wx::PlThreadEvent->new(
            -1,
            $self->resize_start_event,
            shared_clone($images)
        )
    );

    $images;
}


sub cancel_resize {
    my( $self ) = @_;

    my $cancelled;

    if( $self->resize_manager->pending and wxYES == Wx::MessageBox( 
        sprintf(
            "Cancel %s resize pending job(s) ?",
            $self->resize_manager->pending,
        ),
        "pLoader job processing",
        wxYES_NO|wxNO_DEFAULT| wxICON_QUESTION, ) 
    ){
        $cancelled = 1;
        $self->resize_manager->cancel;
    }

    $cancelled;
}


sub cancel_transfer {
    my( $self ) = @_;

    my $cancelled = 1;
    if( $self->transfer_manager->pending ){
        if( wxYES == Wx::MessageBox( 
            sprintf(
                "Cancel %s transfer pending job(s) ?",
                $self->transfer_manager->pending,
            ),
            "pLoader job processing",
            wxYES_NO|wxNO_DEFAULT| wxICON_QUESTION, ) 
            )
        {
            $self->transfer_manager->cancel;
        }
        else{
            $cancelled = 0;
        }
    }

    $cancelled;
}


sub SetFrame {
    my ( $self, $frame ) = @_;    

    my $url = $self->connection->site_url;
    
    if($self->use_offline){
        $url = gettext("Work Offline");
    }

    $self->frame($frame);

    my $icon = Wx::Icon->new();
    $icon->LoadFile(
        File::Spec->catfile(
            $self->root_dir, $self->resource_dir, 'favicon.ico'
        ), 
        wxBITMAP_TYPE_ICO
    );
    $self->frame->SetIcon($icon);
}


sub GetWxBitmapType {
    my ( $self, $type ) = @_;
    
    $self->{IMGTYPE}->{$type};
}

1;