# +-----------------------------------------------------------------------+
# | pLoader - a Perl photo uploader for Piwigo                            |
# +-----------------------------------------------------------------------+
# | Copyright(C) 2008      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
         /;

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
        listchoices
        btn_show
        show_method
        is_selected
        creation_callback
        search_result
        previous_autocompleted
      /
);

use Wx::Event qw(EVT_CHECKLISTBOX EVT_LISTBOX EVT_SEARCHCTRL_SEARCH_BTN EVT_SEARCHCTRL_CANCEL_BTN
                 EVT_TEXT EVT_TEXT_ENTER EVT_RADIOBOX);


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}, -1, wxDefaultPosition, wxDefaultSize );
    $self->_init_panel;
    $self->_init_properties($params);

    $self->Refresh;

    EVT_CHECKLISTBOX( $self, $self->listchoices, \&OnCheck );
    EVT_LISTBOX( $self, $self->listchoices, \&OnSelected );
    EVT_SEARCHCTRL_SEARCH_BTN( $self, $self->search, \&OnSearch );
    EVT_SEARCHCTRL_CANCEL_BTN( $self, $self->search, \&OnCancel );
    EVT_TEXT( $self, $self->search, \&OnSearch );
    EVT_TEXT_ENTER( $self, $self->search, \&OnSearchEnter );
    EVT_RADIOBOX( $self, $self->btn_show, \&OnShow );

    $self;
}

sub _init_properties {
    my ( $self, $params ) = @_;	
	
    $self->choices(
        $params->{choices}
    );

    $self->selection(
        $params->{selection}
    );

    my $choices = $self->choices->() ||[];
    $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("Selected") => sub { $self->_show_selected(@_) },
            gettext("Not selected") => sub { $self->_show_notselected(@_) },
        }
    );
}

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

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

    $self->search->ShowCancelButton( 1 );

    $vsizer->AddWindow( $self->search, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 );

    $self->btn_show(
        Wx::RadioBox->new( $self, -1, sprintf("%s :", gettext("Show")), wxDefaultPosition, [320, -1], 
            [gettext("All"),gettext("Selected"),gettext("Not selected")] , 1, wxRA_SPECIFY_ROWS )
    );
    $vsizer->AddWindow( $self->btn_show, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 );


    $self->listchoices(
        Wx::CheckListBox->new( $self, -1, wxDefaultPosition, [320,300], [], 0 )
    );
    $vsizer->AddWindow( $self->listchoices, 0, wxALIGN_CENTER_VERTICAL|wxALL, 2 );

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

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

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

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

}

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

    

    if (!defined $choices){
        $self->btn_show->SetStringSelection(gettext("All"));
        $choices = $self->choices->();
    }

    $self->_init_choices($choices);
    $self->SetSelection($selected);
	
}


sub SetSelection {
    my ( $self, $selected ) = @_;

    my $selection = $self->selection->()||[];

    push @$selection, $self->id_from_name->{$selected} if defined $selected;

    map {
    	$self->listchoices->Check(
    	    $self->row_lookup->{$_},
    	    exists $self->row_lookup->{$_},
    	) if defined $self->row_lookup->{$_};
    	$self->is_selected->{$_} = 1;	
    }
    @{$selection};	
}

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

    my $row = 0;
    my $selection = [];
    
    my $choices = $self->choices->();
    map {
           
        my $id = $self->id_lookup->{$row};
        $self->is_selected->{$id} = $self->listchoices->IsChecked($row) ;	
    	$row++;
    }@$choices;

    [
        grep { $self->is_selected->{$_} } keys %{$self->is_selected}
    ];	
}

sub OnCheck {
    my ( $self ) = @_;
    
    $self->selection->(
        $self->GetSelection
    );	
}

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

    my $row = $event->GetInt;
    $self->listchoices->Check(
        $row,
        !$self->listchoices->IsChecked($row)    
    );

    $self->OnCheck;

    $event->Skip;    
}

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

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

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

    my $searched = $self->search->GetValue;
    $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;
    $self->SetSelection($searched);
    $self->_show_selected;
    $self->btn_show->SetStringSelection(gettext("Selected"));
}

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

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

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

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

    $self->Refresh(
        $self->search_result
    );
    
    # autocompletion
    if(1== scalar @{$self->search_result}){
    	my $value = $self->search_result->[0]->{name};
    	unless(  $value eq $self->previous_autocompleted ){
    	    my $from = $self->search->GetLastPosition;
    	    $self->search->ChangeValue($value);
    	    my $to = $self->search->GetLastPosition;
    	    $self->search->SetSelection($from, $to);
    	    $self->previous_autocompleted($value);
    	}	
    }
    else{
    	$self->previous_autocompleted(undef);
    }
}

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

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


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

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

    $self->Refresh(
        $self->_filter_notselected()
    );
}

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

    $self->Refresh(
        $self->_filter_selected()
    );
}

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

    $self->Refresh(
        $self->choices->()
    );
}

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

    my $choices = $self->choices->()||[];
    [
        grep { $self->is_selected->{$_->{id}} } @$choices
    ]	
}

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

    my $choices = $self->choices->()||[];
    [
        grep { !$self->is_selected->{$_->{id}} } @$choices
    ]	
}


1;
