package Lire::ReportParser::ReportBuilder;

use strict;

use base qw/ Lire::ReportParser /;

use Lire::Report;
use Lire::Report::Section;
use Lire::Report::Subreport;
use Lire::Utils qw/ check_param /;
use Lire::ReportSpec;

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

    $self->{'curr_section'} = undef;
    $self->{'curr_subreport'} = undef;

    return;
}

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

    return $self->{'report'};
}

sub parse_with_images {
    my ( $self, $fh, $images_dir ) = @_;

    check_param( $fh, 'fh' );
    check_param( $images_dir, 'images_dir' );

    return $self->parse( $fh );
}

sub parsefile_with_images {
    my ( $self, $file, $images_dir ) = @_;

    check_param( $file, 'file' );
    check_param( $images_dir, 'images_dir' );

    return $self->parsefile( $file );
}

sub report_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::report_start( $name, $attr );

    $self->{'report'} = new Lire::Report();
    $self->{'report'}->generator( __PACKAGE__ . "(3pm)" );

    return;
}

sub handle_title {
    my ( $self, $title ) = @_;

    if ( $self->{'curr_subreport'} ) {
        $self->{'curr_subreport'}->title( $title );
    } elsif ( $self->{'curr_section'} ) {
        $self->{'curr_section'}->title( $title );
    } else {
        $self->{'report'}->title( $title );
    }

    return;
}

sub handle_date {
    my ( $self, $date, $date_epoch ) = @_;

    $self->{'report'}->date( $date_epoch );

    return;
}

sub handle_timespan {
    my ( $self, $timespan, $start, $end, $period ) = @_;

    $self->{'report'}->timespan_period( $period )
      if defined $period;
    $self->{'report'}->timespan_start( $start );
    $self->{'report'}->timespan_end( $end );

    return;
}

sub handle_description {
    my ( $self, $desc )= @_;

    my $o;
    if ( $self->{'curr_subreport'} ) {
        $o = $self->{'curr_subreport'};
    } elsif ( $self->{'curr_section'} ) {
        $o = $self->{'curr_section'};
    } else {
        $o = $self->{'report'};
    }
    $o->description( $desc );

    return;
}

sub section_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::section_start( $name, $attr );

    $self->{'curr_section'} = new Lire::Report::Section();
    $self->{'report'}->add_section( $self->{'curr_section'} );

    return;
}

sub section_end {
    my ( $self, $name ) = @_;

    $self->SUPER::section_end( $name );
    $self->{'curr_section'} = undef;

    return;
}

sub subreport_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::subreport_start( $name, $attr );

    my $subreport = new Lire::Report::Subreport( $attr->{'superservice'},
                                                 $attr->{'type'} );

    $attr->{'id'} = $self->{'report'}->create_subreport_id( $attr->{'type'} )
      unless defined $attr->{'id'};

    $subreport->id( $attr->{'id'} );
    $subreport->schemas( split /\s+/, $attr->{'schemas'} )
      if $attr->{'schemas'};

    $self->{'curr_subreport'} = $subreport;
    $self->{'curr_section'}->add_subreport( $self->{'curr_subreport'} );

    $self->init_stack( 'group' );
    $self->init_stack( 'entry' );
    $self->stack_push( 'group', $subreport );

    return;
}

sub subreport_end {
    my ( $self, $name ) = @_;

    $self->SUPER::subreport_end( $name );
    $self->{'curr_subreport'} = undef;
    $self->stack_pop( 'group' );
    $self->error(  "subreport_end(): assertion failed: stack 'group' should be empty" )
      unless $self->is_stack_empty( 'group' );
    $self->error( "subreport_end(): assertion failed: stack 'entry' should be empty" )
      unless  $self->is_stack_empty( 'entry' );

    return;
}

sub missing_subreport_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::missing_subreport_start( $name, $attr );
    my $subreport = new_missing Lire::Report::Subreport( $attr->{'superservice'},
                                                         $attr->{'type'},
                                                         $attr->{'reason'} );
    $attr->{'id'} = $self->{'report'}->create_subreport_id( $attr->{'type'} )
      unless defined $attr->{'id'};
    $subreport->id( $attr->{'id'} );

    $subreport->schemas( split /\s+/, $attr->{'schemas'} )
      if $attr->{'schemas'};

    $self->{'curr_section'}->add_subreport( $subreport );

    return;
}

sub table_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::table_start( $name, $attr );
    $self->{'curr_charttype'} = $attr->{'charttype'};
    $self->{'curr_subreport'}->show( $attr->{'show'} );

    return;
}

sub group_summary_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::group_summary_start( $name, $attr );

    my $curr_group = $self->stack_peek( 'group' );
    $curr_group->nrecords( $attr->{'nrecords'} );
    $curr_group->missing_cases( $attr->{'missing-cases'} );
    $curr_group->row_idx( $attr->{'row-idx'} )
      if defined $attr->{'row-idx'};

    return;
}

sub group_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::group_start( $name, $attr );
    my $curr_entry = $self->stack_peek( 'entry' );
    my $group = $curr_entry->create_group();
    $group->show( $attr->{'show'} )
      if defined $attr->{'show'};

    $self->stack_push( 'group', $group );

    return;
}

sub group_end {
    my ( $self, $name ) = @_;

    $self->SUPER::group_end( $name );

    $self->stack_pop( 'group' );

    return;
}

sub table_info_end {
    my ( $self, $name ) = @_;

    $self->SUPER::table_info_end( $name );
    $self->{'curr_subreport'}->table_info( $self->current_table_info() );

    if ( $self->{'curr_charttype'} ) {
        my $cfg =
          Lire::ReportSpec::charttype2chart_config( $self->{'curr_charttype'},
                                                    $self->{'curr_subreport'}->id(),
                                                    $self->current_table_info() );
        $self->{'curr_subreport'}->add_chart_config( $cfg );
        delete $self->{'curr_charttype'};
    }
    return;
}

sub entry_start {
    my ( $self, $name, $attr ) = @_;

    $self->SUPER::entry_start( $name, $attr );

    my $entry = $self->stack_peek( 'group' )->create_entry();
    $entry->row_idx( $attr->{'row-idx'} )
      if defined $attr->{'row-idx'};

    $self->stack_push( 'entry', $entry );

    return;
}

sub entry_end {
    my ( $self, $name ) = @_;

    $self->SUPER::entry_end( $name );
    $self->stack_pop( 'entry' );

    return;
}

sub handle_name {
    my ( $self, $name ) = @_;

    $self->stack_peek( 'entry' )->add_name( $name->{'content'},
                                            $name->{'value'},
                                            $name->{'range'} );

    return;
}

sub handle_value {
    my ( $self, $value ) = @_;

    $self->stack_peek( 'entry' )->add_value( 'content' => $value->{'content'},
                                             'value' => $value->{'value'},
                                             'total' => $value->{'total'},
                                             'n' => $value->{'n'},
                                             'missing_cases' => $value->{'missing-cases'} );

    return;
}

sub handle_summary_value {
    my ( $self, $value ) = @_;

    $self->stack_peek( 'group' )->set_summary_value( $value->{'col_info'}->name(),
                                                     'content' => $value->{'content'},
                                                     'value' => $value->{'value'},
                                                     'total' =>$value->{'total'},
                                                     'n' => $value->{'n'},
                                                     'missing_cases' => $value->{'missing-cases'} );

    return;
}

sub handle_chart_configs {
    my ( $self, $configs ) = @_;

    foreach my $cfg ( @$configs ) {
        $self->{'curr_subreport'}->add_chart_config( $cfg );
    }

    return;
}

1;

__END__

=pod

=head1 NAME

Lire::ReportParser::ReportBuilder - Creates Lire::Report objects from XML files

=head1 SYNOPSIS

    use Lire::ReportParser::ReportBuilder;
    my $parser = new Lire::ReportParser::ReportBuilder;
    my $report = $parser->parsefile( "report.xml" );

=head1 DESCRIPTION

This is a subclass of Lire::ReportParser that creates an object
representation of a Lire report contained in a XML file.

=head1 SEE ALSO

Lire::Report(3pm)

=head1 AUTHOR

 Francis J. Lacoste <flacoste@logreport.org>

=head1 VERSION

$Id: ReportBuilder.pm,v 1.41 2006/07/23 13:16:31 vanbaal Exp $

=head1 COPYRIGHT

Copyright (C) 2001, 2004 Stichting LogReport Foundation LogReport@LogReport.org

This file is part of Lire.

Lire 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; either version 2 of the License, or
(at your option) any later version.

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 (see COPYING); if not, check with
http://www.gnu.org/copyleft/gpl.html. 

=cut
