The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Business::ReportWriter::Pdf;

use strict;
use POSIX qw(setlocale LC_NUMERIC);
use utf8;

use base 'Business::ReportWriter';

sub init_fields {
    my ( $self, $parms ) = @_;

    $self->SUPER::fields($parms);
    my @fields = @$parms if $parms;

    # Find maximum line height
    $self->{font}{maxheight} = 8;
    for ( 0 .. $#{ $self->{report}{fields} } ) {
        $self->{fields}{ $fields[$_]{name} } = $_;
        if ( defined( $fields[$_]{font}{size} )
            && $fields[$_]{font}{size} > $self->{font}{_maxheight} )
        {
            $self->{font}{_maxheight} = $fields[$_]{font}{size};
        }
    }
}

sub init_breaks {
    my ( $self, $parms ) = @_;

    $self->SUPER::breaks($parms);

    # Find total break height
    $| = 1;

    for ( keys %$parms ) {
        next if /^_/;
        my $brk  = $parms->{$_};
        my $hbs  = $brk->{beforespace} || 0;
        my $hts  = 10;
        my $hfhs = 10;
        my $ts   = 10;

        #    $self->{fields}{$fields[$_]{name}} = $_;
        #    if (defined($fields[$_]{font}{size}) &&
        #      $fields[$_]{font}{size} > $self->{font}{_maxheight}) {
        #      $self->{font}{_maxheight} = $fields[$_]{font}{size};
        #    }
        $brk->{breakheight} = $hbs + $hts + $hfhs + $ts;
    }
}

# Routines for report writing
sub calc_yoffset {
    my ( $self, $fontsize ) = @_;

    $self->{ypos} -= $fontsize + 2;
    $self->check_page;

    return $self->{ypos};
}

sub page_footer {
    my ( $self, $fontsize ) = @_;

    my $break = '_page';
    $self->{breaks}{$break} = '_break';
    my $text = $self->make_text( 0, $self->{report}{breaks}{$break}{text} );
    $self->{breaktext}{$break} = $text;

    #$self->print_break();
    $self->{breaks}{$break} = "";
}

sub header_text {
    my $self = shift;

    my $page = $self->{pageData};

    for my $th ( @{ $self->{report}{page}{text} } ) {
        $self->process_field( $th, $page );
    }
}

sub print_pagenumber {
    my $self = shift;

    my $page = $self->{report}{page};

    my $text = $page->{number}{text} . $self->{pageData}{pagenr};
    $self->out_field( $text, $page->{number} );
    $self->calc_yoffset( $self->{font}{size} )
        unless $page->{number}{sameline};
}

sub print_pageheader {
    my $self = shift;

    my $page = $self->{pageData};
    $self->{ypos} = $self->{paper}{topmargen};

    $self->{ypos} -= mm_to_pt( $self->{report}{page}{number}{ypos} )
        if $page->{number}{ypos};

    $self->header_text();
    $self->print_pagenumber;
}

sub start_body {
    my $self = shift;

    my $body = $self->{report}{body};

    $self->set_font( $body->{font} );
    $self->{ypos} = $self->{paper}{topmargen} - mm_to_pt( $body->{ypos} )
        if $body->{ypos};
    my $heigth = mm_to_pt( $body->{heigth} ) if $body->{heigth};
    $heigth += mm_to_pt( $body->{ypos} ) if $body->{ypos};
    $self->{paper}{heigth} = $heigth if $heigth;

    $self->make_field_headers( $body->{FieldHeaders} );

    $self->{inHeader} = 0;
}

sub draw_graphics {
    my $self = shift;

    my $p        = $self->{pdf};
    my $graphics = $self->{report}{graphics};
    $p->set_gfxlinewidth( $graphics->{width} + 0 )
        if defined( $graphics->{width} );
    for ( @{ $graphics->{boxes} } ) {
        my $bottomy = $self->{paper}{topmargen} - mm_to_pt( $_->{bottomy} );
        my $topy    = $self->{paper}{topmargen} - mm_to_pt( $_->{topy} );
        $p->draw_rect(
            mm_to_pt( $_->{topx} ),    $bottomy,
            mm_to_pt( $_->{bottomx} ), $topy
        );
    }
}

sub draw_logos {
    my $self = shift;

    my $p     = $self->{pdf};
    my $logos = $self->{report}{logo};
    for ( @{ $logos->{logo} } ) {
        my $x = mm_to_pt( $_->{x} );
        my $y = $self->{paper}{topmargen} - mm_to_pt( $_->{y} );
        $p->add_img_scaled( $_->{name}, $x, $y, $_->{scale} );
    }
}

sub new_page {
    my $self = shift;

    $self->{inHeader} = 1;
    my $p = $self->{pdf};
    $self->{pageData}{pagenr}++;
    $self->{breaks}{'_page'} = "";
    $self->page_footer() if $self->{pageData}{pagenr} > 1;
    $self->{ypos} = $self->{paper}{topmargen};
    $p->new_page;
    $self->set_font( $self->{report}{page}{font} );
    $self->print_pageheader() if defined( $self->{report}{page} );
    $self->start_body();
    $self->draw_graphics();
    $self->draw_logos();
}

sub text_color {
    my ( $self, $color ) = @_;

    my $p = $self->{pdf};
    $p->set_textcolor($color);
}

sub set_linecolor {
    my ( $self, $fld_fgcolor ) = @_;

    my $fgcolor =
          $fld_fgcolor
        ? $fld_fgcolor
        : $self->{report}{textcolor} || 'black';
    $self->text_color($fgcolor);
}

sub draw_topline {
    my ($self) = @_;

    my $p = $self->{pdf};
    my $width = $self->{paper}{width} - 20;
    my $ypos  = $self->{ypos} - 3;
    $p->draw_line( 10, $ypos, $width, $ypos );
}

sub draw_underline {
    my ($self) = @_;

    my $p = $self->{pdf};
    my $width = $self->{paper}{width} - 20;
    my $ypos  = $self->{ypos} - $self->{font}{size} - 3;
    $p->draw_line( 10, $ypos, $width, $ypos );
}

sub draw_linebox {
    my ( $self, $shade ) = @_;

    my $p = $self->{pdf};
    my $width    = $self->{paper}{width} - 20;
    my $ypos     = $self->{ypos} - 3;
    my $fontsize = $self->{font}{size} + 2;
    $p->shade_rect( 10, $ypos, $width, $ypos - $fontsize, $shade );
}

sub begin_break {
    my ( $self, $rec, $fld ) = @_;

    $self->check_page( $fld->{breakheight} );
}

sub begin_line {
    my ( $self, $rec, $fld ) = @_;

    $self->set_font( $rec->{font} );
    $self->calc_yoffset( $fld->{beforespace} ) if $fld->{beforespace};
    $self->set_linecolor( $fld->{fgcolor} );
    $self->draw_linebox( $fld->{shade} ) if $fld->{shade};
    $self->draw_topline                  if $rec->{topline};
    $self->draw_underline                if $rec->{underline};
    $self->calc_yoffset( $self->{font}{size} );
}

sub begin_field {
    my ( $self, $field ) = @_;

    $self->set_font( $field->{font} );
    my $fontsize = $self->{font}{size};
}

sub out_field {
    my ( $self, $text, $field, $alt ) = @_;

    my $font = $alt->{font} || $field->{font};
    $self->set_font($font);
    $self->{ypos} = $self->{paper}{topmargen} - mm_to_pt( $field->{ypos} )
        if $field->{ypos};
    $self->calc_yoffset( $self->{font}{size} )
        if defined( $field->{nl} ) && $text;
    my $width = mm_to_pt( $field->{width} );
    $self->out_text( $text, $field->{xpos}, $self->{ypos}, $field->{align},
        $width );

}

sub set_font {
    my ( $self, $font ) = @_;

    my $p = $self->{pdf};
    if ( defined($font) ) {
        if ( $font->{size} ) {
            my $font_size = $font->{size} + 0;
            $p->set_size( $font->{size} ) if $self->{font}{size} != $font_size;
            $self->{font}{size} = $font_size;
        }
        if ( $font->{face} ) {
            $p->set_font( $font->{face} )
                if $self->{font}{face} ne $font->{face};
            $self->{font}{face} = $font->{face};
        }
    }
}

sub begin_list {
    my ($self) = @_;

    my $papersize   = $self->{report}{papersize}   || 'A4';
    my $orientation = $self->{report}{orientation} || 'Portrait';
    my $p           = new Business::ReportWriter::Pdf::Report(
        PageSize        => $papersize,
        PageOrientation => $orientation
    );

    $self->{pdf}  = $p;
    $self->{ypos} = -1;
    $self->set_papersize();
}

sub check_page {
    my ( $self, $yplus ) = @_;

    return if $self->{inHeader};
    my $bottommargen = $self->{paper}{topmargen} - $self->{paper}{heigth};
    $self->new_page() if $self->{ypos} - $yplus < $bottommargen;
}

sub get_doc {
    my ($self) = @_;

    my $p = $self->{pdf};
    $p->finish_report("none");
}

sub print_doc {
    my ( $self, $filename ) = @_;

    my $p = $self->{pdf};
    if ($filename) {
        open OUT, ">$filename";
        print OUT $p->finish_report("none");
        close OUT;
    }
}

sub set_papersize {
    my $self = shift;

    my $p    = $self->{pdf};
    my ( $pagewidth, $pageheigth ) = $p->get_pagedimensions();
    $self->{paper} = {
        width     => $pagewidth,
        topmargen => $pageheigth - 20,
        heigth    => $self->{paper}{topmargen}
    };
}

sub out_text {
    my ( $self, $text, $x, $y, $align, $width ) = @_;

    my $p = $self->{pdf};
    $x = mm_to_pt($x);
##
##print "$text er utf8\n" if utf8::is_utf8($text);
##print "$text er ikke utf8\n" unless utf8::is_utf8($text);
    utf8::decode($text);
    utf8::decode($text) if utf8::is_utf8($text);
    my $sw = 0;
    $sw = int( $p->get_stringwidth($text) + .5 ) if lc($align) eq 'right';
    $x -= $sw;
    my $margen    = 20;
    $width ||= $self->{paper}{width} - $x - 20;
    my $linespace = $self->{font}{size} + 2;

    $p->add_paragraph(
        $text, $x, $y,
        $self->{paper}{width} - $x - 20,
        $self->{paper}{topmargen} - $y,
        0, $linespace
    );
    my ( $hPos, $vPos ) = $p->get_add_textpos();
    $self->{ypos} = $vPos + $linespace if $self->{ypos} - $linespace > $vPos;
}

sub mm_to_pt {
    my $mm = shift;

    return int( $mm / .3527777 );
}

1;
__END__

=head1 NAME

Business::ReportWriter::Pdf - A Business Oriented ReportWriter.

=head1 SYNOPSIS

  use Business::ReportWriter::Pdf;

  my $rw = new Business::ReportWriter::Pdf();
  $rw->process_report($outfile, $report, $head, $list);

=head1 DESCRIPTION

Business::ReportWriter is a tool to make a Business Report from an array of
data.  The report output is generated based on a XML description of the report.

The report is written to a PDF file.

=head2 Method calls

=over 4

=item $obj->get_doc()

Deprecated (?)

=back

=head1 SEE ALSO

 Business::ReportWriter

=head1 COPYRIGHT

Copyright (C) 2003-2006 Kaare Rasmussen. All rights reserved.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=head1 AUTHOR

Kaare Rasmussen <kar at jasonic.dk>