package tests::UIStoreWindowTest;

use strict;

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

use Curses::UI;

use Lire::DlfStore;
use Lire::UI::StoreWindow;
use Lire::Test::Mock;
use Lire::Test::CursesUIDriver;
use Lire::Config::Dictionary;
use Lire::Config::DlfStreamSpec;
use Time::Local;

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

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

    return $self;
}

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

    $self->SUPER::set_up();

    $self->set_up_tz( 'EST' );

    my $spec = $self->lire_default_config_spec();
    $self->{'cfg'}{'_lr_config_spec'} = $spec;
    $self->{'cfg'}{'lr_templates_path'} = [];

    $self->{'mock_stream'} =
      new Lire::Test::Mock( 'Lire::DlfStream',
                            'start_time' => '1072933200',
                            'end_time' => '1104555600',
                            'nrecords' => 1 );
    $self->{'store'} = new Lire::Test::Mock( 'Lire::DlfStore',
                                             'path' => 'mystore',
                                             'config' => $spec->instance() );

    $self->{'driver'}->setup_curses_ui();
    $self->{'ui'} = new Curses::UI();
    $self->{'driver'}->set_curses_ui( $self->{'ui'} );

    return;
}

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

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

    return;
}

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

    my $ui = $self->{'ui'};
    $self->assert_dies( qr/missing 'store' parameter/,
                        sub { $ui->add( 'store_win', 'Lire::UI::StoreWindow') }
                      );
    $self->assert_dies(  qr/'store' parameter should be a 'Lire::DlfStore' instance, not 'HASH/,
                         sub { $ui->add( 'store_win', 'Lire::UI::StoreWindow',
                                         'store' => {} ) } );

    my $win = $ui->add( 'store_win', 'Lire::UI::StoreWindow',
                        'store' => $self->{'store'} );

    my $e_object_names = [ 'import_jobs',
                           'nrecords_label', 'nrecords_value',
                           'report_jobs', 'reports',
                           'stream_end_label', 'stream_end_value',
                           'stream_start_label', 'stream_start_value',
                           'streams', 'streams_buttons' ];
    my @object_names = sort keys %{$win->{'-id2object'}};
    $self->assert_deep_equals( $e_object_names, \@object_names );
    $self->assert_str_equals( "Store: mystore", $win->title() );
#   $self->assert_num_equals( 0, $Curses::UI::screen_too_small );

    $self->_test_new_lists( $win );
    $self->_test_add_stream_widgets( $win );

    $self->assert_isa( 'CODE', $win->getobj( 'import_jobs' )->{'onvaluechanged'} );

    return;
}

sub _test_new_lists {
    my ( $self, $win ) = @_;

    my $cfg = $self->{'store'}->config();
    my $e_import_jobs_value = $cfg->get( 'import_jobs' );
    my $e_report_jobs_value = $cfg->get( 'report_jobs' );
    my $e_reports_value = $cfg->get( 'reports' );

    my $import_jobs = $win->getobj( 'import_jobs' );
    $self->assert_isa( 'Lire::UI::ListWidget', $import_jobs );
    $self->assert_str_equals( 'Import Jobs', $import_jobs->title() );
    $self->assert_str_equals( $e_import_jobs_value, $import_jobs->{'value'} );

    my $report_jobs = $win->getobj( 'report_jobs' );
    $self->assert_isa( 'Lire::UI::ListWidget', $report_jobs );
    $self->assert_str_equals( $e_report_jobs_value, $report_jobs->{'value'} );
    $self->assert_str_equals( 'Report Jobs', $report_jobs->title() );

    my $reports = $win->getobj( 'reports' );
    $self->assert_isa( 'Lire::UI::ReportConfigListWidget', $reports );
    $self->assert_str_equals( $e_reports_value, $reports->{'value'} );
    $self->assert_str_equals( 'Report Configurations', $reports->title() );

    return;
}

sub _test_add_stream_widgets {
    my ( $self, $win ) = @_;

    my $streams = $win->getobj( 'streams' );
    $self->assert_isa( 'Curses::UI::Listbox', $streams );
    $self->assert_str_equals( 'DLF Streams', $streams->title() );

    my $streams_buttons = $win->getobj( 'streams_buttons' );
    $self->assert_isa( 'Curses::UI::Buttonbox', $streams_buttons );
    $self->assert_num_equals( 2, scalar @{$streams_buttons->{'-buttons'}} );
    $self->assert_str_equals( '[Configure]',
                              $streams_buttons->{'-buttons'}[0]{'-label'} );
    $self->assert_str_equals( '[Clean]',
                              $streams_buttons->{'-buttons'}[1]{'-label'} );

    my $stream_start_label = $win->getobj( 'stream_start_label' );
    $self->assert_isa( 'Curses::UI::Label', $stream_start_label );
    $self->assert_str_equals( 'Starts:', $stream_start_label->{'-text'} );
    my $stream_end_label = $win->getobj( 'stream_end_label' );
    $self->assert_isa( 'Curses::UI::Label', $stream_end_label );
    $self->assert_str_equals( 'Ends:', $stream_end_label->{'-text'} );

    my $stream_start_value = $win->getobj( 'stream_start_value' );
    $self->assert_isa( 'Curses::UI::Label', $stream_start_value );
    my $stream_end_value = $win->getobj( 'stream_end_value' );
    $self->assert_isa( 'Curses::UI::Label', $stream_end_value );

    my $nrecords_label = $win->getobj( 'nrecords_label' );
    $self->assert_isa( 'Curses::UI::Label', $nrecords_label );
    my $nrecords_value = $win->getobj( 'nrecords_value' );
    $self->assert_isa( 'Curses::UI::Label', $nrecords_value );

    return;
}

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

    my $win = $self->{'ui'}->add( 'store_win', 'Lire::UI::StoreWindow',
                                  'store' => $self->{'store'} );
    my $streams = $win->getobj( 'streams' );
    my $stream_start_value = $win->getobj( 'stream_start_value' );
    my $stream_end_value = $win->getobj( 'stream_end_value' );
    my $nrecords_value = $win->getobj( 'nrecords_value' );
    $self->assert_null( $streams->{'-selected'} );

    $win->_update_labels();
    $self->assert_str_equals( '', $stream_start_value->{'-text'} );
    $self->assert_str_equals( '', $stream_end_value->{'-text'} );
    $self->assert_str_equals( '', $nrecords_value->{'-text'} );

    $self->{'store'}->set_result( 'has_dlf_stream' => 1,
                                  'open_dlf_stream' => $self->{'mock_stream'});

    $streams->{'-values'} = [ 'mock_stream' ];
    $streams->{'-selected'} = $streams->{'-ypos'} = 0;
    $streams->{'-focusable'} = 1;
    $win->_update_labels();
    $self->assert_str_equals( '2004-01-01 00:00',
                              $stream_start_value->{'-text'} );
    $self->assert_str_equals( '2005-01-01 00:00',
                              $stream_end_value->{'-text'} );
    $self->assert_str_equals( 1, $nrecords_value->{'-text'} );

    $self->{'store'}->set_result( 'has_dlf_stream' => 0 );

    $win->_update_labels();
    $self->assert_str_equals( '',  $stream_start_value->{'-text'} );
    $self->assert_str_equals( '', $stream_end_value->{'-text'} );
    $self->assert_str_equals( 0, $nrecords_value->{'-text'} );

    return;
}

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

    my $win = $self->{'ui'}->add( 'store_win', 'Lire::UI::StoreWindow',
                                  'store' => $self->{'store'} );
    $win->_update_streams();
    my $streams = $win->getobj( 'streams' );
    $self->assert_null( $streams->{'-selected'} );
    $self->assert_num_equals( 0, $streams->{'-ypos'} );
    $self->assert_num_equals( 0,  $streams->{'-focusable'} );
    $self->assert_deep_equals( [ '-- no stream --' ], $streams->{'-values'} );

    $self->{'store'}->set_result( 'configured_dlf_streams' => 'mock_stream' );
    $win->_update_streams();
    $self->assert_num_equals( 0, $streams->{'-selected'} );
    $self->assert_num_equals( 0, $streams->{'-ypos'} );
    $self->assert_num_equals( 1,  $streams->{'-focusable'} );
    $self->assert_deep_equals ( [ 'mock_stream' ], $streams->{'-values'} );

    return;
}

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

    $self->{'store'}->set_result( 'configured_dlf_streams' => 'mock_stream',
                                  'open_dlf_stream' => $self->{'mock_stream'});

    my $win = $self->{'ui'}->add( 'store_win', 'Lire::UI::StoreWindow',
                                  'store' => $self->{'store'} );
    $self->assert_num_equals( 0, $win->getobj( 'streams' )->{'-selected'} );

    my $ok_handler = sub {
        my $dialog = $_[1];

        $self->assert_str_equals( $dialog, $win->getobj( 'clean_stream_win' ));
        $self->assert_isa( 'Curses::UI::Window', $dialog );
        $self->assert_str_equals( "Cleaning stream 'mock_stream'",
                                  $dialog->{'-title'} );

        my $field = $dialog->getobj( 'time_field' );
        $field->text( '2004-03-31' );
        $dialog->getobj( 'buttons' )->{'-buttons'}[1]{'-onpress'}->();
    };

    $self->{'driver'}->add_event_loop_handler( $ok_handler );

    $win->getobj( 'streams_buttons' )->{'-buttons'}[1]{'-onpress'}->();

    $self->assert_num_equals( 1, $self->{'mock_stream'}->invocation_count( 'clean' ) );
    $self->assert_deep_equals( [ $self->{'mock_stream'},
                                 timelocal( 0, 0, 0, 31, 2, 2004 ) ],
                                 $self->{'mock_stream'}->get_invocation( 'clean' ) );

    $self->assert_null( $win->getobj( 'clean_stream_win' ) );

    my $cancel_handler = sub {
        my $dialog = $_[1];
        my $field = $dialog->getobj( 'time_field' );
        $field->text( '2004-01-01' );
        $dialog->getobj( 'buttons' )->{'-buttons'}[0]{'-onpress'}->();
    };
    $self->{'driver'}->add_event_loop_handler( $cancel_handler );
    $win->getobj( 'streams_buttons' )->{'-buttons'}[1]{'-onpress'}->();
    $self->assert_num_equals( 1, $self->{'mock_stream'}->invocation_count( 'clean' ) );

    return;
}

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

    my $config = Lire::Config::DlfStreamSpec->new( 'name' => 'mock_stream' )->instance();
    $self->assert_num_equals( 60, $config->get( 'keep_days' )->as_value() );

    $self->{'store'}->set_result( 'configured_dlf_streams' => 'mock_stream',
                                  'get_stream_config' => $config,
                                  'open_dlf_stream' => $self->{'mock_stream'});

    my $win = $self->{'ui'}->add( 'store_win', 'Lire::UI::StoreWindow',
                                  'store' => $self->{'store'} );
    $self->assert_num_equals( 0, $win->getobj( 'streams' )->{'-selected'} );

    my $called = '_update_streams not called';
    no warnings 'redefine';
    local *Lire::UI::StoreWindow::_update_streams = sub { $called = 'called' };

    my $cancel_handler = sub {
        my $dialog = $_[1];

        $self->assert_str_equals( $dialog,
                                  $self->{'ui'}->getobj( 'configure_stream_win' ) );
        $self->assert_isa( 'Curses::UI::Window', $dialog );
        $self->assert_str_equals( "Configuring stream 'mock_stream'",
                                  $dialog->{'-title'} );

        my $stream_cfg = $dialog->getobj( 'stream_config' );
        $self->assert_isa( 'Lire::UI::CompoundWidget',  $stream_cfg );
        $self->assert_str_not_equals( $config, $stream_cfg->value() );
        $self->assert_deep_equals( $config, $stream_cfg->value() );
        $stream_cfg->value()->get( 'keep_days' )->set( 10 );

        $dialog->getobj( 'buttons' )->{'-buttons'}[0]{'-onpress'}->();
    };
    $self->{'driver'}->add_event_loop_handler( $cancel_handler );
    $win->getobj( 'streams_buttons' )->{'-buttons'}[0]{'-onpress'}->();

    $self->assert_null( $self->{'ui'}->getobj( 'configure_stream_win' ) );
    $self->assert_num_equals( 60, $config->get( 'keep_days' )->as_value() );
    $self->assert_str_equals( '_update_streams not called', $called );

    my $ok_handler = sub {
        $_[1]->getobj( 'stream_config' )->value()->get( 'keep_days' )->set( 10 );
        $_[1]->getobj( 'buttons' )->{'-buttons'}[1]{'-onpress'}->();
    };
    $self->{'driver'}->add_event_loop_handler( $ok_handler );
    $win->getobj( 'streams_buttons' )->{'-buttons'}[0]{'-onpress'}->();

    $self->assert_str_equals( 'called', $called );
    $self->assert_num_equals( 10, $config->get( 'keep_days' )->as_value() );

    return;
}

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

    foreach my $date ( qw/ 2003-10-04 03-10-04 0000-01-13 0000-01-31 / ) {
        $self->assert( Lire::UI::StoreWindow::_test_date( $date ),
                       $date );
    }

    foreach my $date (qw/1988 aaaaa 3-10-4 0000-00-00 0000-13-13 2004-01-53/) {
        $self->assert( !Lire::UI::StoreWindow::_test_date( $date ),
                       $date );
    }

    return;
}

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

    my %dates = ( '2004-01-01' => 1072933200,
                  '04-01-01' => 1072933200,
                  '70-01-01' => 18000 );
    foreach my $date ( keys %dates ) {
        $self->assert_num_equals( $dates{$date},
                                  Lire::UI::StoreWindow::_date_to_epoch( $date ) );
    }
}

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

    my %epochs = ( 1072933200 => '2004-01-01',
                   18000 => '1970-01-01' );
    foreach my $epoch ( keys %epochs ) {
        $self->assert_num_equals( $epochs{$epoch},
                                  Lire::UI::StoreWindow::_epoch_to_date( $epoch ) );
    }

    $self->assert_str_equals( '-- no date --',
                              Lire::UI::StoreWindow::_epoch_to_date() );
    $self->assert_str_equals( '-- no date --',
                              Lire::UI::StoreWindow::_epoch_to_date( '' ) );
}

1;


syntax highlighted by Code2HTML, v. 0.9.1