# +-----------------------------------------------------------------------+
# | 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::wxChoiceFilteredPanel;
use strict;
use Wx qw/
             wxDefaultSize
             wxDefaultPosition
             wxVERTICAL
             wxALIGN_CENTER_VERTICAL
             wxALL
             wxSHAPED
             wxALIGN_CENTER
             wxTE_PROCESS_ENTER
             wxRA_SPECIFY_ROWS
             wxGROW
             wxEXPAND
         /;

use base qw/Wx::Panel Uploader::Object2/;
use Wx::Locale qw/:default/;

use Data::Dumper;
__PACKAGE__->mk_accessors(     
    qw/
        frame_callbacks
        choices
        selection
        id_lookup
        row_lookup
        id_from_name
        search
        choices_list
        btn_show
        show_method
        is_selected
        creation_callback
        search_result
        previous_autocompleted
        autocomplete_from
        autocomplete_to
        autocomplete_set_selection
        current_show_mode
      /
);


sub new {
    my ($this, $params) = @_;
    #on recupere le nom de la classe en fonction du type d'appel de la méthode.
    my $class = ref($this) || $this;

    my $self = $class->SUPER::new( $params->{parentwnd}, $params->{id}||-1, wxDefaultPosition, wxDefaultSize );

    $self->init_panel;
    $self->init_properties($params);
    $self->init_event_handlers;

    $self;
}


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

    my( $vsizer ) = Wx::BoxSizer->new( wxVERTICAL );
    
    $self->search(
        Wx::SearchCtrl->new( $self, -1, "", wxDefaultPosition, [-1,-1],wxTE_PROCESS_ENTER )
    );

    $self->search->ShowCancelButton( 1 );
    $vsizer->Add( $self->search, 0, wxEXPAND|wxALL, 2 );

    $self->choices_list(
        Wx::CheckListBox->new( $self, -1, wxDefaultPosition, [-1,-1], [], 0 )
    );
    $vsizer->Add( $self->choices_list, 1, wxEXPAND|wxALL, 2 );

    $self->btn_show(
        Wx::RadioBox->new( $self, -1, sprintf("%s :", gettext("Show")), wxDefaultPosition, [-1, -1], 
            [gettext("All"),gettext("Selection")] , 1, wxRA_SPECIFY_ROWS )
    );
    $vsizer->Add( $self->btn_show, 0, wxEXPAND|wxALL, 2 );

    $self->SetSizer( $vsizer );
    $vsizer->Fit( $self );
}


sub init_properties {
    my ( $self, $params ) = @_;    
    
    $self->choices(
        $params->{choices}|| sub { [] }
    );

    $self->selection(
        $params->{selection}|| sub{ [] }
    );

    $self->search_result(
        []
    );
    
    $self->is_selected({});
    
    $self->creation_callback(
        $params->{creation_callback}
    ) if 'CODE' eq ref($params->{creation_callback});

    $self->show_method(
        {
            gettext("All") => sub { $self->show_all(@_) },
            gettext("Selection") => sub { $self->show_selected(@_) },
        }
    );
}


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

    $self->refresh_lookups(
        $self->choices->()
    );
    $self->refresh_is_selected;
    my $show_mode = $self->current_show_mode||gettext("All");
    $self->show_method->{$show_mode}->();
}


sub refresh_lookups {
    my ( $self, $choices ) = @_;

    $self->id_lookup({});
    $self->row_lookup({});
    $self->id_from_name({});

    my $row = 0;
    #print Dumper $self->properties;
    map {
        $self->id_lookup->{$row} = $_->{id};
        $self->row_lookup->{$_->{id}} = $row;
        $self->id_from_name->{$_->{name}} = $_->{id};
        $row++;    
    }@{$choices};

}


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

    my $selection = $self->selection->();
    $self->is_selected({});

    map {
        $self->is_selected->{$_} = 1;
    } @$selection;

}


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

    my $choices = $self->choices->();
    $self->current_show_mode(
        gettext("All")
    );
    $self->refresh_choices_list(
        $self->choices->()
    );
}


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

    $self->current_show_mode(
        gettext("Selection")
    );

    $self->refresh_choices_list(
        $self->get_selected_choices()
    );
}


sub refresh_choices_list {
    my ( $self, $choices ) = @_;

    $self->choices_list->Freeze;
    $self->choices_list->Clear;

    #print Dumper $self->properties;
    my $i=0;
    map {
        $self->choices_list->Append(
            $_->{name},
        );
        $self->choices_list->Check(
            $i,
            $self->is_selected->{$_->{id}}
        );
        $i++;
    }@{$choices};
    $self->choices_list->Thaw;
}


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

    my $choices = $self->choices->()||[];
    # each choice item is { id => $id,  name => $name, url_nam => $url_name }
    my $selected = [
        grep { $self->is_selected->{$_->{id}} } @$choices
    ];


    $selected;
}


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

    my $row = 0;
    
    my $choices = $self->choices->();
    $self->choices_list->Freeze;
    map {
        $self->choices_list->Check($row, 0) ;    
        $row++;
    }@$choices;
    $self->choices_list->Thaw;
}


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

    Wx::Event::EVT_CHECKLISTBOX( $self, $self->choices_list, \&OnCheck );
    Wx::Event::EVT_LISTBOX( $self, $self->choices_list, \&OnSelected );
    Wx::Event::EVT_SEARCHCTRL_SEARCH_BTN( $self, $self->search, \&OnSearch );
    Wx::Event::EVT_SEARCHCTRL_CANCEL_BTN( $self, $self->search, \&OnCancel );
    Wx::Event::EVT_TEXT( $self, $self->search, \&OnSearch );
    Wx::Event::EVT_TEXT_ENTER( $self, $self->search, \&OnSearchEnter );
    Wx::Event::EVT_RADIOBOX( $self, $self->btn_show, \&OnShow );
    # fix for linux : can not call SetSelection before the current event is processed.
    # call when idle
    Wx::Event::EVT_IDLE(
        $self,
        sub {
            my ($self, $event)=@_;
            $self->search->SetSelection(
                $self->autocomplete_from,
                $self->autocomplete_to
            ) if $self->autocomplete_set_selection;
            $self->autocomplete_set_selection(0);
        }
    );

}


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

    my $list = $event->GetEventObject;
    my $row = $event->GetInt;

    $list->Check(
        $row,
        !$list->IsChecked($row)    
    );

    $self->OnCheck($event);

}


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

    my $list = $event->GetEventObject;
    my $indx = $event->GetInt;
    my $item = $list->GetString($indx);
    if($list->IsChecked($indx)){
       $self->add_to_selection($item);
    }
    else{
        $self->remove_from_selection($item);
    }
    
}


sub add_to_selection {
    my ( $self, $item ) = @_;

    return if !defined $item;

    my $id = $self->id_from_name->{$item};
    return if !defined $id;

    $self->is_selected->{$id} = 1;
    my $selection = $self->selection->();

    $self->selection->(
        [
            $id,
            @$selection
        ]
    );
}


sub remove_from_selection {
    my ( $self, $item ) = @_;

    my $id = $self->id_from_name->{$item};
    my $selection = $self->selection->();
    $self->selection->(
        [
            grep { $_ ne $id } @$selection
        ]
    );
    $self->refresh_is_selected;
}


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

    my $show_mode = $event->GetString();
    $self->show_method->{$show_mode}->();
}


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

    my $searched = $self->search->GetValue;
    eval { $searched =~ s/\s+$//; };
    $searched = $searched eq "" ? undef : $searched ;

    my $cleanup;
    if(defined($searched)){
    
        my $busy = Wx::BusyCursor->new();
    
        if(!scalar @{$self->search_result}){
            $self->creation_callback->(
                $searched    
            );
    
            $self->refresh_selected_searched($searched);
            $cleanup = 1;
        }
    
        if( 1 == scalar @{$self->search_result}){
            $self->refresh_selected_searched($searched);
            $cleanup = 1;
        }
    
    }
    else{
        $cleanup = 1;
    }

    if($cleanup){    
        $self->search->ChangeValue("");
        $self->search->SetFocus;
    }
}

sub refresh_selected_searched {
    my ( $self, $searched ) = @_;        

    $self->refresh_lookups(
        $self->choices->()
    );
    $self->add_to_selection($searched);
    $self->show_selected;
    $self->btn_show->SetStringSelection(gettext("Selection"));
}

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

    $self->btn_show->SetStringSelection(gettext("All"));

    my $searched = $self->search->GetValue;

    $self->search_result(
        $self->search_in_choices(
            $searched
        )
    );

    $self->refresh_choices_list(
        $self->search_result
    );
    
    # autocompletion
    if(1== scalar @{$self->search_result}){
        my $value = $self->search_result->[0]->{name};
        unless(  $value eq $self->previous_autocompleted ){
            $self->autocomplete_from(
                $self->search->GetLastPosition
            );
            $self->search->ChangeValue($value);
            $self->autocomplete_to(
                $self->search->GetLastPosition
            );
            $self->autocomplete_set_selection(1);
            $self->previous_autocompleted($value);
        }    
    }
    else{
        $self->previous_autocompleted(undef);
    }
    
    $event->Skip;
}


sub search_in_choices {
    my ( $self, $searched ) = @_;
    
    my $choices = $self->choices->()||[];
    
    [
       grep { $_->{name} =~ /\b$searched/i} @$choices
    ];
}


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

    $self->init_choices_list(
        $self->choices->()
    );
    
    $self->btn_show->SetStringSelection(gettext("All"));
}


1;
