package tests::AggregatorTest;

use strict;

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

use Lire::ReportSpec;
use Lire::Report::Subreport;
use Lire::Report::TableInfo;

use Lire::Test::Mock;
use tests::MockAggregate;
use tests::MockAggregator;

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

    $self->init();

    return $self;
}

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

    $self->set_up_test_store();

    my $spec = $self->{'spec'} = new Lire::ReportSpec();
    $spec->superservice( 'test' );
    $spec->joined_schemas( [ 'test-extended' ] );

    $self->{'aggregator'} = new tests::MockAggregator( 'report_spec' => $spec );
    $spec->calc_spec( $self->{'aggregator'} );
    my $nested1 = new tests::MockAggregator( 'name' => 'nested1',
                                             'report_spec' => $spec,
                                             'parent' => $self->{'aggregator'} );
    my $nested2 = new tests::MockAggregator( 'name' => 'nested2',
                                             'report_spec' => $spec,
                                             'parent' => $self->{'aggregator'} );
    $self->{'aggregator'}->ops( [ $nested1, $nested2 ] );
    $nested1->ops( [ new tests::MockAggregate( 'name' => 'mock1',
                                               'parent' => $nested1,
                                               'report_spec' => $spec ) ] );
    $nested2->ops( [ new tests::MockAggregate( 'name' => 'mock2',
                                               'parent' => $nested2,
                                               'report_spec' => $spec ) ] );

    return;
}

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

    my $top = new_proxy Lire::Test::Mock( 'tests::MockAggregator',
                                          'report_spec' => $self->{'spec'} );
    $top->set_result( 'create_entry' =>
                      sub {
                          my ($self, $group, $row ) = @_;

                          return undef if ($self->{'count'} || 0) > 3;

                          my $e = $group->create_entry();
                          $e->add_name( $row->{'client_host'} );
                          $e->add_name( $row->{'user'} );
                          $self->{'count'}++;

                          return $e;
                      } );
    my $nested1 =
      new_proxy Lire::Test::Mock( 'tests::MockAggregator',
                                  'report_spec' => $self->{'spec'},
                                  'parent' => $top, 'name' => 'nested1' );
    $nested1->set_result( 'create_entry' => sub {
                              my ($self, $group, $row ) = @_;

                              my $e = $group->create_entry();
                              $e->add_name( $row->{'connection_id'} );
                              return $e;
                          } );
    $top->ops( [ $nested1 ] );
    $nested1->ops( [ new tests::MockAggregate( 'name' => 'mock',
                                               'parent' => $nested1,
                                               'report_spec' => $self->{'spec'}
                                             ) ] );
    $self->{'spec'}->calc_spec( $top );
    $self->{'mock_query_spec'} = $top;
    return;
}

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

    $self->{'mock_query_info'} = new Lire::Report::TableInfo();
    $self->{'mock_query_info'}->create_column_info( 'client_host',
                                                    'categorical', 'string' );
    $self->{'mock_query_info'}->create_column_info( 'user', 'categorical',
                                                    'string' );

    my $n1_info = $self->{'mock_query_info'}->create_group_info( 'nested1' );
    $n1_info->create_column_info( 'connection_id', 'categorical', 'string' );
    $n1_info->create_column_info( 'mock', 'numerical', 'int' );

    $self->{'mock_query'} = new Lire::DlfQuery( 'test' );
    $self->{'mock_query'}->add_group_field( 'client_host' );
    $self->{'mock_query'}->add_group_field( 'user' );
    $self->{'mock_query'}->set_sort_spec( 'client_host user' );
    my $nested1 = $self->{'mock_query'}->create_nested_query();
    $nested1->add_group_field( 'connection_id' );
    $nested1->set_sort_spec( 'connection_id' );
    $nested1->add_aggr_field( '_lr_nrecords', 'count()' );
    $nested1->add_aggr_field( 'mock', 'count()' );

    return;
}

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

    my $stream = $self->{'store'}->open_dlf_stream( 'test', 'r' );
    my $subreport = new Lire::Report::Subreport( 'mock', 'mock-subreport' );
    $subreport->table_info( $self->{'mock_query_info'} );
    $subreport->nrecords( 24 );
    $subreport->set_summary_value( 'mock', 'content' => 24 );

    my %group_cache = ();
    foreach my $c ( [ '127.0.0.1', 'francis', '13', '13' ],
                    [ '192.168.250.1', 'flacoste', '2', '2' ],
                    [ '192.168.250.2', 'joostvb', '5', '5' ],
                    [ '192.168.250.3', 'wdankers', '3', '3' ],
                  )
    {
        my $entry = $subreport->create_entry();
        $entry->add_name( $c->[0] );
        $entry->add_name( $c->[1] );
        my $group = $entry->create_group();
        $group->nrecords( $c->[2] );
        $group->set_summary_value( 'mock', 'content' => $c->[3] );
        $group_cache{$c->[0] . $c->[1]} = $group;
    }


    my %n_group_cache = ();
    foreach my $c ( [ '127.0.0.1', 'francis', 'AABBCCDD', '13', '13' ],
                    [ '192.168.250.1', 'flacoste', 'AABBCCDE', '1', '1' ],
                    [ '192.168.250.1', 'flacoste', 'AABBCCDF', '1', '1' ],
                    [ '192.168.250.2', 'joostvb', 'AABBCCDG', '5', '5' ],
                    [ '192.168.250.3', 'wdankers', 'AABBCCDD', '3', '3' ],
                  )
    {
        my $group = $group_cache{ $c->[0] . $c->[1]};
        my $entry = $group->create_entry();
        $entry->add_name( $c->[2] );
        $entry->add_value( 'content' => $c->[4] );
    }

    $self->{'mock_query_subreport'} = $subreport;

    return;
}

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

    $self->tear_down_test_store();

    return;
}

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

    $self->set_up_mock_query();
    $self->set_up_mock_query_report();

    my $aggr = new_proxy Lire::Test::Mock( 'tests::MockAggregator',
                                           'report_spec' => $self->{'spec'} );
    $aggr->set_result( 'build_table' => '' );

    my $filter = new Lire::Test::Mock( 'Lire::FilterExpr',
                                       'sql_expr' => 'myfilter = ?',
                                       'sql_params' => [ 'myparam' ] );
    $self->{'spec'}->filter_spec( $filter );

    my $subreport = new Lire::Report::Subreport( 'mock', 'mock-subreport' );
    $subreport->table_info( $self->{'mock_query_info'} );

    $aggr->create_entries( $subreport );
    $self->assert_equals( 0, scalar $subreport->entries() );

    $aggr->{'store'} = $self->{'store'};
    $aggr->create_entries( $subreport );

    $self->assert_num_equals( 1, $aggr->invocation_count( 'build_table' ) );
    $self->assert_num_equals( $self->{'store'},
                              $aggr->get_invocation( 'build_table' )->[1] );
    my $query = $aggr->get_invocation( 'build_table' )->[2];
    $self->assert_isa( 'Lire::DlfQuery',  $query );
    $self->assert_str_equals( 'test', $query->stream_name() );
    $self->assert_deep_equals( [ 'test', 'test-extended' ],
                               $query->joined_streams() );
    $self->assert_str_equals( 'myfilter = ?', $query->filter_clause() );
    $self->assert_deep_equals( [ 'myparam' ], $query->sql_params() );
}

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

    my $test_query = new Lire::DlfQuery( "test" );
    my $sub1 = $test_query->create_nested_query();
    $sub1->add_aggr_field( '_lr_nrecords', 'count(*)' );
    $sub1->add_aggr_field( 'mock1', 'count()' );
    my $sub2 = $test_query->create_nested_query();
    $sub2->add_aggr_field( '_lr_nrecords', 'count(*)' );
    $sub2->add_aggr_field( 'mock2', 'count()' );

    my $query = new Lire::DlfQuery( "test" );
    $self->{'aggregator'}->build_query( $query );

    $self->assert_deep_equals( $test_query, $query );
}

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

    my $query = new Lire::DlfQuery( "test" );
    $self->{'aggregator'}->build_query( $query );

    my $subreport = new Lire::Report::Subreport( 'mock', 'mock-subreport' );
    $subreport->table_info( $self->{'spec'}->create_table_info() );
    $self->{'aggregator'}->build_table_summary( $self->{'store'}, $query,
                                                $subreport );

    $self->assert_equals( 24, $subreport->nrecords() );
    $self->assert_equals( 24, $subreport->get_summary_value( 'mock1' )->{'content'} );
    $self->assert_equals( 24, $subreport->get_summary_value( 'mock2' )->{'content'} );
}

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


    my $query = new Lire::DlfQuery( "test" );
    $self->{'aggregator'}->build_query( $query );
    my $stream = $self->{'store'}->open_dlf_stream( 'test', 'r' );
    my $subreport = new Lire::Report::Subreport( 'mock', 'mock-subreport' );
    my $aggr1 = $self->{'aggregator'}->ops()->[0]->ops()->[0];
    $subreport->table_info( $self->{'spec'}->create_table_info() );

    $self->{'aggregator'}->set_group_summary( $subreport, { '_lr_nrecords' => 24,
                                                            'mock1' => 22,
                                                            'mock2' => 23, } );

    $self->assert_equals( 24, $subreport->nrecords() );
    $self->assert_equals( 22, $subreport->get_summary_value( 'mock1' )->{'content'} );
    $self->assert_equals( 23, $subreport->get_summary_value( 'mock2' )->{'content'} );

    $self->assert_equals( 1, scalar @{$aggr1->{'parent_groups'}});
    $self->assert_str_equals( $subreport,
                              $aggr1->{'parent_groups'}[0] );

    my $nested1 = $self->{'aggregator'}->ops()->[0];
    my $entry = $subreport->create_entry();
    $entry->add_name();
    my $group = $entry->create_group();
    $nested1->set_group_summary( $group, { '_lr_nrecords' => 24,
                                           'mock1' => 22,
                                           'mock2' => 23, } );
    $self->assert_equals( 2, scalar @{$aggr1->{'parent_groups'}});
    $self->assert_str_equals( $subreport,
                              $aggr1->{'parent_groups'}[1] );
}

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

    $self->set_up_mock_query_spec();
    $self->set_up_mock_query();
    $self->set_up_mock_query_report();

    my $e_subreport = $self->{'mock_query_subreport'};
    my $subreport = new Lire::Report::Subreport( 'mock', 'mock-subreport' );
    $subreport->table_info( $self->{'mock_query_info'} );
    $self->{'mock_query_spec'}->build_table( $self->{'store'},
                                             $self->{'mock_query'},
                                             $subreport );
    $self->assert_deep_equals( $e_subreport, $subreport );
}

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

    my $aggr = $self->{'aggregator'};
    $aggr->{'name'} = 'topAggr';
    $self->assert( $aggr->is_name_defined( 'topAggr' ),
                   'is_name_defined( "topAggr" ) returned false' );
    $self->assert( $aggr->is_name_defined( 'nested1' ),
                   'is_name_defined( "nested1" ) returned false' );
    $self->assert( !$aggr->is_name_defined( 'newName' ),
                   'is_name_defined( "newName" ) returned true' );
}

1;


syntax highlighted by Code2HTML, v. 0.9.1