package tests::ReportParserLaTeXWriterTest;

use strict;

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

use Lire::ReportParser::LaTeXWriter;
use Lire::ReportParser::ReportBuilder;
use Lire::Utils qw/tempdir create_file file_content/;
use File::Path qw/rmtree/;
use Lire::Config::ConfigSpec;
use Lire::DlfSchema;
use Lire::Field;
use Lire::Report;
use Lire::Report::Section;
use Lire::Report::Subreport;
use Lire::Report::TableInfo;
use Lire::Report::ChartConfig;
use Lire::ChartType;
use Lire::PluginManager;
use Lire::Test::Mock;
use IO::Scalar;
use Time::Local;

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

    $self->{'tmpdir'} = tempdir( $self->name() . "_XXXXXX" );
    $self->{'writer'} =
      new_proxy Lire::Test::Mock( 'Lire::ReportParser::LaTeXWriter' );
    $self->{'writer'}{'_fh'} = new IO::Scalar();
    $self->{'keep_tmpdir'} = 0;

    return;
}

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

    rmtree( $self->{'tmpdir'}, 0 )
      unless $self->{'keep_tmpdir'};

    return;
}

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

    my $report = new Lire::Report();
    $report->add_section( new Lire::Report::Section( 'Section 1' ) );
    $report->add_section( new Lire::Report::Section( 'Section 2' ) );
    create_file( "$self->{'tmpdir'}/font.tex", '' );
    $self->{'writer'}->set_result( 'write_header', '' );
    $self->{'writer'}->set_result( 'write_titlepage', '' );
    $self->{'writer'}->set_result( 'write_section', '' );
    $self->{'writer'}->set_result( 'write_appendix', '' );
    $self->{'writer'}->set_result( 'process_latex', '' );
    $self->{'writer'}{'_fh'} = undef;
    $self->{'writer'}->write_report( $report,
                                     "$self->{'tmpdir'}/report.pdf", 'pdf',
                                     "$self->{'tmpdir'}/font.tex" );
    $self->assert_str_equals( 'pdf', $self->{'writer'}{'_format'} );
    $self->assert_str_equals( "$self->{'tmpdir'}/report.pdf",
                              $self->{'writer'}{'_outputfile'},  );
    $self->assert_str_equals( $self->{'tmpdir'},
                              $self->{'writer'}{'_outputdir'} );
    $self->assert_str_equals( "$self->{'tmpdir'}/report",
                              $self->{'writer'}{'_outputbase'}, );
    $self->assert_str_equals( "$self->{'tmpdir'}/font.tex",
                              $self->{'writer'}{'_preamble'}, );

    $self->assert_not_null( $self->{'writer'}{'_fh'},
                            "missing _fh attribute" );

    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_header' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_titlepage' ) );
    $self->assert_num_equals( 2, $self->{'writer'}->invocation_count( 'write_section' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_appendix' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'process_latex' ) );
}

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

    $self->{'cfg'}{'unicode.tex'} = '/usr/share/lire/tex/unicode.tex';
    $self->{'writer'}{'_preamble'} = 'font.tex';
    $self->{'writer'}{'_format'} = 'pdf';
    $self->{'writer'}->write_header();

    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->assert_str_equals( <<EOF, $$buf );
\\ocp\\MyTexUTF=inutf8
\\InputTranslation currentfile \\MyTexUTF

\\documentclass{report}

\\addtolength{\\textwidth}{2\\oddsidemargin}
\\addtolength{\\textheight}{2\\topmargin}
\\setlength{\\oddsidemargin}{0cm}
\\setlength{\\topmargin}{0cm}

\\input /usr/share/lire/tex/unicode.tex
\\usepackage[dvipdf]{graphics}
\\usepackage{longtable}
\\usepackage[ps2pdf,bookmarks,bookmarksopen,bookmarksnumbered]{hyperref}
\\input font.tex

\\begin{document}
EOF

}

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

    my $report = new Lire::Report();
    $report->title( '{My report}' );
    my $start = timelocal( 0, 0, 0, 1, 0, 2004 );
    my $time = timelocal( 15, 15, 3, 2, 0, 2004 );
    $report->timespan_start( $start );
    $report->timespan_end( $start + 86400);
    $report->date( $time );

    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_titlepage( $report );

    $self->assert_str_equals( <<'EOF', $$buf );
\title{\{My report\}}
\author{}
\date{Report for 2004-01-01 00:00 -- 2004-01-02 00:00\\
Report generated 2004-01-02 03:15}
\maketitle
\tableofcontents

EOF
}

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

    my $section = new Lire::Report::Section( '{Section title}' );
    $section->description( '<para>Section description</para>' );
    my $sub1 = new Lire::Report::Subreport( 'test', 'test1' );
    $sub1->id( 'test-test1' );
    $section->add_subreport( $sub1 );
    my $sub2 = new_missing Lire::Report::Subreport( 'test', 'test2',
                                                    'No good reason' );
    $sub2->id( 'test-test2' );
    $section->add_subreport( $sub2 );

    $self->{'writer'}->set_result( 'write_subreport', '' );
    $self->{'writer'}->set_result( 'write_missing_subreport', '' );
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_section( $section );
    $self->assert_str_equals( <<'EOF', $$buf );
\chapter{\{Section title\}}

Section description

EOF
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_subreport' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_missing_subreport' ) );
}

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

    my $sub = new_missing Lire::Report::Subreport( 'test', 'test1', '{No good reason}' );
    $sub->title( '{My subreport}' );
    $sub->description( '<para>Description</para>' );
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_missing_subreport( $sub );
    $self->assert_str_equals( <<'EOF', $$buf );
\section{\{My subreport\}}

\emph{This report is missing: \{No good reason\}}

EOF

}

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

    $self->{'cfg'}{'_lr_config_spec'} = new Lire::Config::ConfigSpec();
    $self->set_up_plugin_mgr();

    my $type = new_proxy Lire::Test::Mock( 'Lire::ChartType' );
    $type->set_result( 'name' => 'mock_chart',
                       'write_chart' => sub { return '/tmp/chart.eps' } );
    Lire::PluginManager->register_plugin( $type );
    $self->{'mock_chart'} = $type;

    $self->{'cfg'}{'lr_chart_font'} = '';
    $self->{'chart1'} = new Lire::Report::ChartConfig();
    $self->{'chart1'}->type( $type );
    $self->{'chart2'} = new Lire::Report::ChartConfig();
    $self->{'chart2'}->type( $type );

    return;
}

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

    $self->set_up_chart_configs();
    my $subreport = new Lire::Report::Subreport( 'test', 'test1' );
    $subreport->title( "{Subreport's Title}" );
    $subreport->description( "<para>Subreport's description</para>" );
    $subreport->add_chart_config( $self->{'chart1'} );
    $subreport->add_chart_config( $self->{'chart2'} );
    $self->{'writer'}->set_result( 'write_chart', '' );
    $self->{'writer'}->set_result( 'write_table_header', '' );
    $self->{'writer'}->set_result( 'write_table_entries', '' );
    $self->{'writer'}->set_result( 'write_table_footer', '' );

    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_subreport( $subreport );
    $self->assert_str_equals( <<'EOF', $$buf );
\section{\{Subreport's Title\}}

Subreport's description

EOF
    $self->assert_num_equals( 2, $self->{'writer'}->invocation_count( 'write_chart' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_table_header' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_table_entries' ) );
    $self->assert_num_equals( 1, $self->{'writer'}->invocation_count( 'write_table_footer' ) );

}

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

    $self->set_up_chart_configs();

    my $subreport = new Lire::Report::Subreport( 'test', 'test1' );
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}{'_outputdir'} = $self->{'tmpdir'};
    $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} );
    $self->assert_str_equals( <<'EOF', $$buf );
\begin{center}
\includegraphics{chart.eps}
\end{center}

EOF
    $self->assert_deep_equals( [ $self->{'mock_chart'},
                                 $self->{'chart1'}, $subreport,
                                 'outputdir', $self->{'tmpdir'},
                                 'format', 'eps',
                                 'font', '/Helvetica',
                               ],
                               $self->{'mock_chart'}->get_invocation( 'write_chart' ) );
    $self->assert_deep_equals( [ '/tmp/chart.eps' ],
                               $self->{'writer'}{'_chart_files'} );

    $self->{'cfg'}{'lr_chart_font'} = '/Times-New-Roman';
    $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} );
    $self->assert_deep_equals( [ $self->{'mock_chart'},
                                 $self->{'chart1'}, $subreport,
                                 'outputdir', $self->{'tmpdir'},
                                 'format', 'eps',
                                 'font', '/Times-New-Roman',
                               ],
                               $self->{'mock_chart'}->get_invocation( 'write_chart', 1 ) );

    $self->{'mock_chart'}->set_result( 'write_chart',
                                       sub { die "An error occured\n" } );
    $$buf = '';
    $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} );
    $self->assert_str_equals( <<'EOF', $$buf );
\emph{An error occured while generating the chart: An error occured
}

EOF
    $self->{'mock_chart'}->set_result( 'write_chart',
                                       sub { return undef } );
    $$buf = '';
    $self->{'writer'}->write_chart( $subreport, $self->{'chart1'} );
    $self->assert_str_equals( '', $$buf );

    return;
}

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

    my $subreport = new Lire::Report::Subreport( 'test', 'test1' );
    my $table_info = new Lire::Report::TableInfo();
    $table_info->create_column_info( 'user', 'categorical', 'string',
                                     '{User}' );
    my $group = $table_info->create_group_info( 'group1' );
    $group->create_column_info( 'file', 'categorical', 'string', '{File}' );
    $group->create_column_info( 'count', 'numerical', 'int', 'Downloads' );
    $group->create_column_info( 'size', 'numerical', 'bytes', 'Size' );

    $table_info->compute_group_layout();
    $subreport->table_info( $table_info );
    $subreport->schemas( 'test' );
    $self->{'subreport'} = $subreport;

    return;
}

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

    $self->init();
    $self->set_up_test_schema();
    $self->set_up_subreport();
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_table_header( $self->{'subreport'} );
    $self->assert_str_equals( <<'EOF', $$buf );
\begin{longtable}{|llrr|}
\hline
\multicolumn{2}{|l}{\bfseries \hyperlink{test:user}{\{User\}}} & \bfseries Downloads & \bfseries Size\\
 & \bfseries \hyperlink{test:file}{\{File\}} &  & \\
\hline
\endhead

EOF

    return;
}

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

    $self->set_up_subreport();
    $self->{'subreport'}->nrecords( 100 );
    $self->{'subreport'}->set_summary_value( 'count', 'content' => '356' );
    $self->{'subreport'}->set_summary_value( 'size', 'value' => 1024 * 1024,
                                             'content' => '1$' );
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_table_footer( $self->{'subreport'} );
    $self->assert_str_equals( <<'EOF', $$buf );
\hline
\multicolumn{4}{r}{\emph{continued on next page}}
\endfoot
\hline
\multicolumn{2}{|l}{\emph{Total for 100 records}} & 356 & 1\$\\
\hline
\endlastfoot

EOF

}

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

    my $data = [ [ 'flacoste', undef,  9, 53 ],
                 [ undef, 'page1.html',  5, 50 ],
                 [ undef, 'page2.html',  4,  3 ],
                 [ '{wsourdeau}', undef,  5, 10 ],
                 [ undef, 'page3.html$',  3,  6  ],
                 [ undef, 'page2.html',  1,  2  ],
                 [ undef, 'page4.html',  1,  2 ] ];
    my $group;
    foreach my $r ( @$data ) {
        my ( $user, $page, $count, $size ) = @$r;
        if ( $user ) {
            my $entry = $self->{'subreport'}->create_entry();
            $entry->add_name( $user );
            $group = $entry->create_group();
            $group->set_summary_value( 'count', 'content' => $count );
            $group->set_summary_value( 'size', 'content' => $size );
        } else {
            my $entry = $group->create_entry();
            $entry->add_name( $page );
            $entry->add_value( 'content' => $count );
            $entry->add_value( 'content' => $size );
        }
    }
    $self->{'subreport'}->finalize();
}

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

    $self->set_up_subreport();
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_table_entries( $self->{'subreport'} );
    $self->assert_str_equals( <<'EOF', $$buf );
\multicolumn{4}{|l|}{\emph{There is no entries in this table.}}\\
\end{longtable}

EOF

    $self->set_up_subreport_data();
    $$buf = '';
    $self->{'writer'}->write_table_entries( $self->{'subreport'} );
    $self->assert_str_equals( <<'EOF', $$buf );
\multicolumn{2}{|l}{flacoste} & 9 & 53\\
 & page1.html & 5 & 50\\
 & page2.html & 4 & 3\\
\multicolumn{2}{|l}{\{wsourdeau\}} & 5 & 10\\
 & page3.html\$ & 3 & 6\\
 & page2.html & 1 & 2\\
 & page4.html & 1 & 2\\
\end{longtable}

EOF
}

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

    my $report = new Lire::Report();
    my $sect = new Lire::Report::Section( 'Title' );
    $report->add_section( $sect );
    my $sub = new Lire::Report::Subreport( 'test', 'top-dirs' );
    $sub->id( 'top-dirs.0' );
    $sub->schemas( 'test', 'test-extended' );
    $sect->add_subreport( $sub );

    $self->{'writer'}->set_result( 'write_schema', '' );
    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_appendix( $report );
    $self->assert_str_equals( "\\appendix\n", $$buf );
    $self->assert_num_equals( 2, $self->{'writer'}->invocation_count( 'write_schema' ) );
}

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

    my $test_schema = new Lire::DlfSchema( 'superservice' => 'test',
                                           'timestamp' => 'time' );
    $test_schema->title( '{A title}' );
    $test_schema->description( '<para>A description.</para>' );
    $test_schema->add_field( new Lire::Field( 'name' => 'time',
                                              'type' => 'timestamp',
                                              'label' => '{Time}',
                                              'description' => '<para>The time field.</para>' ) );
    $test_schema->add_field( new Lire::Field( 'name' => 'field_1',
                                              'type' => 'string',
                                              'label' => 'Field 1',
                                              'description' => '<para>The first field.</para>' ) );

    local $Lire::DlfSchema::SCHEMA_CACHE{'test'} = $test_schema;

    my $buf = $self->{'writer'}{'_fh'}->sref();
    $self->{'writer'}->write_schema( 'test' );
    $self->assert_str_equals( <<'EOF', $$buf );
\chapter{\{A title\}}

A description.

\begin{description}
\item[\hypertarget{test:time}{\{Time\}}]
The time field.

\item[\hypertarget{test:field_1}{Field 1}]
The first field.

\end{description}

EOF
}

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

    $self->init();
    $self->set_up_test_schema();
    $self->set_up_chart_types();
    $self->{'keep_tmpdir'} = $ENV{'KEEP_LATEX'};

    my $spec = $self->{'cfg'}{'_lr_config_spec'};
    $self->{'cfg'}{'unicode.tex'} =
      "$self->{'testdir'}/../../../extras/unicode.tex";
    $self->{'cfg'}{'lambda_path'} =
      $spec->get( 'lambda_path' )->default()->as_value();
    $self->{'cfg'}{'odvips_path'} =
      $spec->get( 'odvips_path' )->default()->as_value();
    $self->{'cfg'}{'ps2pdf_path'} =
      $spec->get( 'ps2pdf_path' )->default()->as_value();

    my $parser = new Lire::ReportParser::ReportBuilder();
    $self->{'report'} = $parser->parsefile( "$self->{'testdir'}/data/TestReport_daily_jan25_2003.xml" );

    $self->{'writer'} = new Lire::ReportParser::LaTeXWriter();
}

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

    $self->set_up_write_report();
    $self->{'writer'}->write_report( $self->{'report'},
                                     "$self->{'tmpdir'}/report.tex",
                                     'latex' );
    $self->assert( -s "$self->{'tmpdir'}/report.tex",
                   "missing '$self->{'tmpdir'}/report.tex'" );

    print "\nLaTeX report generated in $self->{'tmpdir'}/report.tex\n"
      if $self->{'keep_tmpdir'};
}

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

    $self->set_up_write_report();
    $self->assert( $self->{'cfg'}{'lambda_path'},
                   "Can't test without lambda" );

    $self->{'writer'}->write_report( $self->{'report'},
                                     "$self->{'tmpdir'}/report.dvi",
                                     'dvi' );
    $self->assert( -s "$self->{'tmpdir'}/report.dvi",
                   "missing '$self->{'tmpdir'}/report.dvi'" );
    $self->assert( ! -f "$self->{'tmpdir'}/report.tex",
                   "file $self->{'tmpdir'}/report.tex wasn't removed" );
    $self->assert( ! -f "$self->{'tmpdir'}/report.log",
                   "temporary $self->{'tmpdir'}/report.log wasn't removed" );
    $self->assert( ! -f "$self->{'tmpdir'}/report.aux",
                   "temporary $self->{'tmpdir'}/report.aux  wasn't removed" );

    print "\nDVI report generated in $self->{'tmpdir'}/report.dvi\n"
      if $self->{'keep_tmpdir'};
}

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

    $self->set_up_write_report();
    $self->assert( $self->{'cfg'}{'lambda_path'},
                   "Can't test without lambda" );
    $self->assert( $self->{'cfg'}{'odvips_path'},
                   "Can't test without odvips" );

    $self->{'writer'}->write_report( $self->{'report'},
                                     "$self->{'tmpdir'}/report.ps",
                                     'ps' );
    $self->assert( -s "$self->{'tmpdir'}/report.ps",
                   "missing '$self->{'tmpdir'}/report.ps'" );
    $self->assert( ! -f "$self->{'tmpdir'}/report.dvi",
                   "temporary $self->{'tmpdir'}/report.dvi  wasn't removed" );
    print "\nPS report generated in $self->{'tmpdir'}/report.ps\n"
      if $self->{'keep_tmpdir'};
}

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

    $self->set_up_write_report();
    $self->assert( $self->{'cfg'}{'lambda_path'},
                   "Can't test without lambda" );
    $self->assert( $self->{'cfg'}{'odvips_path'},
                   "Can't test without odvips" );
    $self->assert( $self->{'cfg'}{'ps2pdf_path'},
                   "Can't test without ps2pdf" );

    $self->{'writer'}->write_report( $self->{'report'},
                                     "$self->{'tmpdir'}/report.pdf",
                                     'pdf' );
    $self->assert( -s "$self->{'tmpdir'}/report.pdf",
                   "missing '$self->{'tmpdir'}/report.pdf'" );
    $self->assert( ! -f "$self->{'tmpdir'}/report.ps",
                   "temporary $self->{'tmpdir'}/report.ps  wasn't removed" );
    print "\nPDF report generated in $self->{'tmpdir'}/report.pdf\n"
      if $self->{'keep_tmpdir'};
}

1;


syntax highlighted by Code2HTML, v. 0.9.1