package tests::UICompoundWidgetTest;

use strict;

use base qw/ Lire::Test::TestCase /;

use Lire::Config::TypeSpec;

use Curses::UI;
use Curses::UI::Widget;
use Curses::UI::Container;

use Lire::Test::CursesUIDriver;
use Lire::Test::Mock;
use Lire::Utils qw/deep_copy/;

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

    $self->{'driver'} = new Lire::Test::CursesUIDriver();

    my $spec = new Lire::Config::ConfigSpec();
    my $compound = new Lire::Config::ConfigSpec( 'name' => 'compound' );
    $spec->add( $compound );
    $compound->add( new Lire::Config::IntegerSpec( 'name' => 'integer' ) );
    my $list = new Lire::Config::ListSpec( 'name' => 'list',
                                           'summary' => 'List summary',
                                           'description' => '<para>List description</para>' );
    $compound->add( $list );
    $list->add( new Lire::Config::StringSpec( 'name' => 'string' ) );
    $compound->add( new Lire::Config::StringSpec( 'name' => 'string' ) );
    $compound->add( new Lire::Config::StringSpec( 'name' => 'obsolete',
                                                  'obsolete' => 1 ) );
    my $empty = new Lire::Config::ConfigSpec( 'name' => 'empty' );
    $spec->add( $empty );

    $self->{'compound'} = $compound->instance();
    $self->{'empty'} = $empty->instance();

    return $self;
}

sub set_up {
    my $self = $_[0];

    $self->SUPER::set_up();

    $self->{'driver'}->setup_curses_ui();

    $self->{'ui'} = new Curses::UI();
    $self->{'driver'}->set_curses_ui( $self->{'ui'} );
    $self->{'window'} = $self->{'ui'}->add( 'window', 'Window' );

    return;
}

sub tear_down {
    my $self = $_[0];
    $self->SUPER::tear_down();

    $self->{'driver'}->teardown_curses_ui();

    return;
}

sub test_new {
    my $self = $_[0];

    my $win = $self->{'window'};
    $self->assert_dies( qr{missing 'value' parameter},
                        sub { my $widget = $win->add( 'widget',
                                                      'Lire::UI::CompoundWidget' ) });
    $self->assert_dies( qr{'value' parameter should be a 'Lire::Config::Dictionary' instance, not 'HASH},
                      sub { my $widget = $win->add( 'widget',
                                                    'Lire::UI::CompoundWidget',
                                                    'Value' => {} ) } );

    my $widget = $win->add( 'widget', 'Lire::UI::CompoundWidget',
                            'value' => $self->{'compound'} );
    $self->assert_isa( 'Lire::UI::CompoundWidget', $widget );
    $self->assert_str_equals( $self->{'compound'}, $widget->{'value'} );

    my $help_viewer = $widget->getobj( 'help_viewer' );
    $self->assert_isa('Curses::UI::TextViewer', $help_viewer );
    my $help_summary = $widget->getobj( 'help_summary' );
    $self->assert_isa( 'Curses::UI::Label', $help_summary );

    my $str_widget = $widget->getobj( 'string_widget' );
    $self->assert_isa( 'Lire::UI::StringWidget', $str_widget );
    $self->assert_str_equals( $self->{'compound'}->get( 'string' ),
                              $str_widget->{'value'} );

    my $int_widget = $widget->getobj( 'integer_widget' );
    $self->assert_isa( 'Lire::UI::IntegerWidget', $int_widget );
    my $list_widget = $widget->getobj( 'list_widget' );
    $self->assert_isa( 'Lire::UI::ListWidget',  $list_widget );

    foreach my $w ( ( $str_widget, $int_widget, $list_widget ) ) {
        $self->assert_str_equals( \&Lire::UI::CompoundWidget::_child_focus_cb,
                                  $w->{'-onfocus'},
                                  "wrong focuscb for $w" );
    }

    foreach my $name ( qw/ string integer list / ) {
        my $w = $widget->getobj( "${name}_label" );
        $self->assert_isa(  'Curses::UI::Label', $w, );
        $self->assert_str_equals( $name, $w->text() );
    }

    return;
}

sub test_new_empty {
    my $self = $_[0];

    my $win = $self->{'window'};
    my $widget = $win->add( 'widget', 'Lire::UI::CompoundWidget',
                            'value' => $self->{'empty'} );

    $self->assert_isa( 'Lire::UI::CompoundWidget', $widget );
    $self->assert_str_equals( $self->{'empty'}, $widget->{'value'} );
    my $label = $widget->getobj( 'empty_label' ) || '< undef >';
    $self->assert_isa( 'Curses::UI::Label', $label  );
    $self->assert_str_equals( '-- This option does not have any attributes --',
                              $label->text() );
}

sub test_refresh_view {
    my $self = $_[0];

    my $win = $self->{'window'};
    my $widget = $win->add( 'widget', 'Lire::UI::CompoundWidget',
                            'value' => $self->{'compound'} );

    no warnings 'redefine';

    my ( $strw, $intw, $listw ) = ( 'undef' x 3 );
    local *Lire::UI::StringWidget::refresh_view = sub { $strw = shift };
    local *Lire::UI::IntegerWidget::refresh_view = sub { $intw = shift };
    local *Lire::UI::ListWidget::refresh_view = sub { $listw = shift };

    $widget->refresh_view();

    $self->assert_str_equals( $strw, $widget->getobj( 'string_widget' ) );
    $self->assert_str_equals( $intw, $widget->getobj( 'integer_widget' ) );
    $self->assert_str_equals( $listw, $widget->getobj( 'list_widget' ) );
}

sub test_child_focus_cb {
    my $self = $_[0];

    my $win = $self->{'window'};
    my $widget = $win->add( 'widget', 'Lire::UI::CompoundWidget',
                            'value' => $self->{'compound'} );
    my $help_summary = $widget->getobj( 'help_summary' );
    my $help_viewer = $widget->getobj( 'help_viewer' );

    $self->assert_str_equals( '', $help_summary->text() );
    $self->assert_str_equals( '', $help_viewer->text() );

    Lire::UI::CompoundWidget::_child_focus_cb( $widget->getobj('list_widget'));

    $self->assert_str_equals( 'List summary', $help_summary->text() );
    $self->assert_str_equals( 'List description', $help_viewer->text() );

    Lire::UI::CompoundWidget::_child_focus_cb( $widget->getobj('string_widget'));

    $self->assert_str_equals( 'string', $help_summary->text() );
    $self->assert_str_equals( 'No help available.', $help_viewer->text() );

    my $texteditor = '<undef>';
    my $nothing = '<undef>';
    my $scrollpos = 0;

    no warnings 'redefine';
    local *Curses::UI::TextViewer::cursor_up =
      sub { $texteditor = shift; $nothing = shift; $scrollpos = shift; };

    $help_viewer->{'-yscrpos'} = 1;
    Lire::UI::CompoundWidget::_child_focus_cb( $widget->getobj('list_widget') );

    $self->assert_str_equals( '<undef>', $texteditor );

    $help_viewer->{'-yscrpos'} = 3;
    Lire::UI::CompoundWidget::_child_focus_cb( $widget->getobj('list_widget') );

    $self->assert_str_equals( $help_viewer, $texteditor );
    $self->assert_null( $nothing );
    $self->assert_num_equals( 3, $scrollpos );
}

sub test_layout {
    my $self = $_[0];

    my $widget = $self->{'window'}->add( 'widget', 'Lire::UI::CompoundWidget',
                                         'value' => $self->{'compound'} );

    my $proxy = new_proxy Lire::Test::Mock( $widget );
    $proxy->set_result( 'canvaswidth', 82, 'canvasheight' => 24 );
    $proxy->layout();

    my $integer_label = $widget->getobj( 'integer_label' );
    $self->assert_num_equals( 0, $integer_label->{'-y'}  );

    my $list_label = $widget->getobj( 'list_label' );
    $self->assert_num_equals( 2, $list_label->{'-y'} );

    my $string_label = $widget->getobj( 'string_label' );
    $self->assert_num_equals( 13, $string_label->{'-y'} );
    foreach my $label ( ( $list_label, $integer_label, $string_label ) ) {
        $self->annotate( "Checking $label->{'-text'}\n" );
        $self->assert_str_equals( 'right', $label->{'-textalignment'} );
        $self->assert_num_equals( 0, $label->{'-x'} );
        $self->assert_num_equals( 1, $label->{'-height'} );
        $self->assert_num_equals( 7, $label->{'-width'} );
    }

    my $integer_widget = $widget->getobj( 'integer_widget' );
    $self->assert_num_equals( 0, $integer_widget->{'-y'} );
    $self->assert_num_equals( 1, $integer_widget->{'-height'} );

    my $list_widget = $widget->getobj( 'list_widget' );
    $self->assert_num_equals( 2, $list_widget->{'-y'} );
    $self->assert_num_equals( 10, $list_widget->{'-height'} );

    my $string_widget = $widget->getobj( 'string_widget' );
    $self->assert_num_equals( 13, $string_widget->{'-y'} );
    $self->assert_num_equals( 1, $string_widget->{'-height'});

    foreach my $wid ( ( $list_widget, $integer_widget, $string_widget ) ) {
        $self->assert_num_equals( 8, $wid->{'-x'} );
        $self->assert_num_equals( 41, $wid->{'-width'} );
    }

    my $summary = $widget->getobj( 'help_summary' );
    $self->assert_num_equals( 50, $summary->{'-x'} );
    $self->assert_num_equals( 32, $summary->{'-width'} );
    $self->assert_num_equals( 0, $summary->{'-y'} );
    my $help_viewer = $widget->getobj( 'help_viewer' );
    $self->assert_num_equals( 50, $help_viewer->{'-x'} );
    $self->assert_num_equals( 32, $help_viewer->{'-width'} );
    $self->assert_num_equals( 2, $help_viewer->{'-y'} );

    return;
}

sub test_max_label_size {
    my $self = $_[0];

    my $new_compound = deep_copy( $self->{'compound'}->spec() );
    my $widget = $self->{'window'}->add( 'widget', 'Lire::UI::CompoundWidget',
                                         'value' => $new_compound->instance());
    my $proxy = new_proxy Lire::Test::Mock( $widget );
    $proxy->set_result( 'canvaswidth', 82 );
    $self->assert_num_equals( 7, $proxy->_max_label_size() );

    $new_compound->get( 'string' )->{'name'} = "A very very very very long";
    $self->assert_num_equals( 20, $proxy->_max_label_size() );
}

sub test_onvaluechanged_cb {
    my $self = $_[0];

    my $called = 'onvaluechanged not called';
    my $win = $self->{'window'};
    my $widget = $win->add( 'widget', 'Lire::UI::CompoundWidget',
                            'value' => $self->{'compound'},
                            'onvaluechanged' => sub { $called = 'called' } );

    my $int_widget = $widget->getobj( 'integer_widget' );
    $self->assert_isa( 'CODE', $int_widget->{'onvaluechanged'} );
    $int_widget->run_event( 'onvaluechanged' );

    $self->assert_str_equals( 'called', $called );

    return;
}

1;


syntax highlighted by Code2HTML, v. 0.9.1