#############################################################################
#   $Author: markus $
#     $Date: 2008-11-08 03:31:37 +0100 (Sat, 08 Nov 2008) $
# $Revision: 1199 $
#############################################################################

package LaTeX::Table::Types::TypeI;

use Moose::Role;
use Template;

use version;
our ($VERSION) = '$Revision: 1199 $' =~ m{ \$Revision: \s+ (\S+) }xms;
use Readonly;

has '_table_obj' => ( is => 'rw', isa => 'LaTeX::Table', required => 1 );
has '_tabular_environment' => ( is => 'ro', required => 1 );
has '_template' => ( is => 'ro', required => 1 );

has '_RULE_TOP_ID'   => ( is => 'ro', default => 0 );
has '_RULE_MID_ID'   => ( is => 'ro', default => 1 );
has '_RULE_INNER_ID' => ( is => 'ro', default => 2 );
## no critic
has '_RULE_BOTTOM_ID' => ( is => 'ro', default => 3 );
## use critic

1;

###########################################################################
# Usage      : $self->_header(\@header,\@data);
# Purpose    : create the LaTeX header
# Returns    : LaTeX code
# Parameters : header and data columns
# Throws     :
# Comments   : n/a
# See also   : _footer

sub generate_latex_code {
    my ( $self, $header, $data ) = @_;

    my $tbl = $self->_table_obj;

    # if specified, use coldef, otherwise guess a good definition
    my $table_def;
    if ( $tbl->get_coldef ) {
        $table_def = $tbl->get_coldef;
    }
    else {
        $table_def = $tbl->_get_coldef_code($data);
    }

    my $code = $self->_get_header_columns_code($header);

    my $template_vars = {
        'COLORDEF' => $self->_get_colordef_code,
        'ENVIRONMENT' => $tbl->get_environment,
        'POS'   => $self->_get_pos_code(),
        'SIZE' => $self->_get_size_code(),
        'BEGIN_CENTER' => $self->_get_begin_center_code(),
        'CAPTION' => $self->_get_caption_code(0),
        'HEADER_CAPTION' => $self->_get_caption_code(1),
        'SIDEWAYS' => $tbl->get_sideways(),
        'STAR' => $tbl->get_star(),
        'EXTRA_ROW_HEIGHT' => $self->_get_extra_row_height_code(),
        'BEGIN_RESIZEBOX' =>  $self->_get_begin_resizebox_code(),
        'WIDTH' => $self->_get_width_code(),
        'COL_DEF' => $table_def,
        'HEADER_CODE' => $code,
        'TABLEHEAD'  => $self->_get_tablehead_code($code),
        'TABLETAIL' => $self->_get_tabletail_code( $data, 0 ),
        'TABLETAIL_LAST' => $self->_get_tabletail_code( $data, 1 ),
        'XENTRYSTRETCH' =>  $self->_get_xentrystretch_code(),
        'LABEL' => $self->_get_label_code(),
        'BODY' => $self->_body(),
        'END_CENTER' => $self->_get_end_center_code(),
        'END_RESIZEBOX' =>  $self->_get_end_resizebox_code(),
        'TABULAR_ENVIRONMENT' => $self->_get_tabular_environment(),
        'FOOTTABLE' => $tbl->get_foottable(),
    };
    
    my $template_obj = Template->new();
    my $template     = $self->_template;
    my $template_output;

    $template_obj->process(\$template, $template_vars,
        \$template_output);
    return $template_output;
}

sub _body {
    my ($self) = @_;
    my $code   = q{};
    my $tbl    = $self->_table_obj;

    my $theme  = $tbl->get_theme_settings;
    my $i      = 0;
    my $row_id = 0;

    # check the data and apply callback function
    my @data = $tbl->_examine_data;
ROW:
    for my $row (@data) {
        $i++;

        # empty rows produce a horizontal line
        if ( !@{$row} ) {
            $code .= $self->_get_single_hline_code();
            next ROW;
        }
        else {

            # single column rows that start with a backslash are just
            # printed out
            if ( $tbl->_row_is_latex_command($row) ) {
                $code .= $row->[0] . "\n";
                next ROW;
            }

            $row_id++;

            # now print the row LaTeX code
            my $bgcolor = $theme->{'DATA_BG_COLOR_EVEN'};
            if ( ( $row_id % 2 ) == 1 ) {
                $bgcolor = $theme->{'DATA_BG_COLOR_ODD'};
            }
            $code .= $tbl->_get_row_code( $row, $bgcolor, 0 );

            # do we have to draw a horizontal line?
            if ( $i == scalar @data ) {
                $code .= $self->_get_hline_code( $self->_RULE_BOTTOM_ID );
            }
            else {
                $code .= $self->_get_hline_code( $self->_RULE_INNER_ID );
            }
        }
    }
    return $code;
}

sub _get_begin_center_code {
    my ($self) =@_;
    if ( $self->_table_obj->get_center ) {
        return "\\centering\n";
    }
    return q{};
}
sub _get_end_center_code {
    return q{};
}

sub _get_width_code {
    my ($self) =@_;
    my $width               = q{};
    my $tbl = $self->_table_obj;

    if ( $tbl->get_width ) {
        $width = '{' . $tbl->get_width . '}';
        if ($tbl->get_width_environment
            && !(
                   $tbl->get_width_environment eq 'tabularx'
                && $tbl->get_type              eq 'std'
            )
            )
        {
            $tbl->invalid_option_usage( 'width_environment',
                      'Not known: '
                    . $tbl->get_width_environment
                    . '. Valid environments are: 0, tabularx (not for xtab)'
            );
        }
    }
    elsif ( $tbl->get_width_environment eq 'tabularx' ) {
        $tbl->invalid_option_usage( 'width_environment',
            'Is tabularx and width is unset' );
    }
    return $width;
}

sub _get_caption_command_code {
    my ($self, $header) =@_;
    my $tbl = $self->_table_obj;
    my $c_caption;
    if ( $tbl->get_caption_top ) {
        if ( !$header ) {
            return q{};
        }
        $c_caption = $tbl->get_caption_top;
        $c_caption =~ s{ \A \\ }{}xms;
        if ( $c_caption eq '1' ) {
            $c_caption = 'caption';
        }
    }
    else {
        if ($header) {
            return q{};
        }
        $c_caption = 'caption';
    }
    return $c_caption;
}

sub _get_colordef_code {
    my ($self) = @_;
    my $tbl = $self->_table_obj;
    my $colordef = q{};
    if ( defined $tbl->get_theme_settings->{DEFINE_COLORS} ) {
        $colordef = $tbl->get_theme_settings->{DEFINE_COLORS} . "\n";
    }
    return $colordef;
}

sub _get_begin_resizebox_code {
    my ($self) = @_;
    if ( $self->_table_obj->get_resizebox ) {
        my $rb_width  = $self->_table_obj->get_resizebox->[0];
        my $rb_height = q{!};
        if ( defined $self->_table_obj->get_resizebox->[1] ) {
            $rb_height = $self->_table_obj->get_resizebox->[1];
        }
        return "\\resizebox{$rb_width}{$rb_height}{\n";
    }
    return q{};
}

sub _get_end_resizebox_code {
    my ($self) = @_;
    my $end_resizebox       = q{};
    if ( $self->_table_obj->get_resizebox ) {
        $end_resizebox = "}\n";
    }
    return $end_resizebox;
}

###########################################################################
# Usage      : $self->_get_caption_code($header);
# Purpose    : generates the LaTeX code of the caption
# Returns    : LaTeX code
# Parameters : called from _header?
# Comments   : header specifies whether this function has been called in
#              the header or footer. ignored for xtab, because there it
#              is always placed on top

sub _get_caption_code {
    my ( $self, $header ) = @_;
    my $f_caption = q{};
    my $s_caption = q{};
    my $tbl       = $self->_table_obj;
    my $theme     = $tbl->get_theme_settings;

    my $c_caption = $self->_get_caption_command_code($header);
    if ( $c_caption eq q{} ) {
        return q{};
    }
    my $tmp = q{};
    if ( $tbl->get_maincaption ) {
        $f_caption = '[' . $tbl->get_maincaption . ']';
        $tmp       = $tbl->get_maincaption . '. ';
        if ( defined $theme->{CAPTION_FONT_STYLE} ) {
            $tmp = $tbl->_add_font_family( $tmp,
                $theme->{CAPTION_FONT_STYLE} );
        }
    }
    else {
        return q{} if !$tbl->get_caption;
    }

    $s_caption = '{' . $tmp . $tbl->get_caption . '}';

    return q{\\} . $c_caption . $f_caption . $s_caption . "\n";
}

sub _get_extra_row_height_code {
    my ($self) = @_;
    if ( defined $self->_table_obj->get_theme_settings->{EXTRA_ROW_HEIGHT} ) {
        return '\setlength{\extrarowheight}{'
            . $self->_table_obj->get_theme_settings->{EXTRA_ROW_HEIGHT}
            . "}\n";
    }
    return q{};
}

sub _get_hline_code {
    my ( $self, $id ) = @_;
    my $tbl    = $self->_table_obj;
    my $theme  = $tbl->get_theme_settings;
    my $hlines = $theme->{'HORIZONTAL_LINES'};
    my $line   = 'hline';
    if ( defined $theme->{'BOOKTABS'} && $theme->{'BOOKTABS'} ) {
        my @line_type = qw(toprule midrule midrule bottomrule);
        $line = $line_type[$id];
    }
    if ( $id == $self->_RULE_BOTTOM_ID ) {
        $id = 0;
    }
    return "\\$line\n" x $hlines->[$id];
}

sub _get_single_hline_code {
    my ( $self, $id ) = @_;
    my $theme = $self->_table_obj->get_theme_settings;
    my $line  = 'hline';
    if ( defined $theme->{'BOOKTABS'} && $theme->{'BOOKTABS'} ) {
        $line = 'midrule';
    }
    return "\\$line\n";
}

###########################################################################
# Usage      : $self->_get_size_code();
# Purpose    : generates the LaTeX code of the size (e.g. \small, \large)
# Returns    : LaTeX code
# Parameters : none
# Throws     : exception if size is not valid

sub _get_size_code {
    my ($self) = @_;
    my %valid = (
        'tiny'         => 1,
        'scriptsize'   => 1,
        'footnotesize' => 1,
        'small'        => 1,
        'normal'       => 1,
        'large'        => 1,
        'Large'        => 1,
        'LARGE'        => 1,
        'huge'         => 1,
        'Huge'         => 1,
    );
    my $size = $self->_table_obj->get_size;
    return q{} if !$size;

    if ( !defined $valid{$size} ) {
        $self->_table_obj->invalid_option_usage(
            'custom_themes',
            "Size not known: $size. Valid sizes are: " . join ', ',
            sort keys %valid
        );
    }
    return "\\$size\n";
}

###########################################################################
# Usage      : $self->_get_label_code();
# Purpose    : create the LaTeX label
# Parameters : none
# Returns    : LaTeX code

sub _get_label_code {
    my ($self) = @_;
    my $label = $self->_table_obj->get_label;
    if ($label) {
        return "\\label{$label}\n";
    }
    return q{};
}

###########################################################################
# Usage      : $self->_get_pos_code();
# Purpose    : generates the LaTeX code of the table position (e.g. [htb])
# Returns    : LaTeX code
# Parameters : none

sub _get_pos_code {
    my ($self) = @_;
    if ( $self->_table_obj->get_position ) {
        return '[' . $self->_table_obj->get_position . "]\n";
    }
    else {
        return "\n";
    }

}

sub _get_tabular_environment {
    my ($self) = @_;
    my $res;
    my $tbl = $self->_table_obj;

    if ( $tbl->get_custom_tabular_environment ) {
        $res = $tbl->get_custom_tabular_environment;
    }
    else {
        $res = $self->_tabular_environment;
    }
    if ( $tbl->get_width ) {
        if ( !$tbl->get_width_environment ) {
            $res .= q{*};
        }
        else {
            $res = $tbl->get_width_environment;
        }
    }
    return $res;
}

###########################################################################
# Usage      : $self->_get_header_columns_code(\@header);
# Purpose    : generate the header LaTeX code
# Returns    : LaTeX code
# Parameters : header columns
# Throws     :
# Comments   : n/a
# See also   : _get_row_code

sub _get_header_columns_code {
    my ( $self, $header ) = @_;
    my $tbl   = $self->_table_obj;
    my $code  = q{};
    my $theme = $tbl->get_theme_settings;
    $code .= $self->_get_hline_code( $self->_RULE_TOP_ID );

    my $i = 0;

CENTER_ROW:
    for my $row ( @{$header} ) {
        my @cols = @{$row};
        if ( scalar @cols == 0 ) {
            $code .= $self->_get_single_hline_code();
            next CENTER_ROW;
        }
        if ( $tbl->_row_is_latex_command($row) ) {
            $code .= $cols[0] . "\n";
            next CENTER_ROW;
        }

        my $j = 0;

        for my $col (@cols) {

            #next if $col =~ m{\A \\ }xms;
            if ( $tbl->get_callback ) {
                $col = $tbl->_apply_callback( $i, $j, $col, 1 );
            }
            $col = $tbl->_apply_header_formatting( $col, 1 );

            $j += $tbl->_extract_number_columns($col);
        }

        $code
            .= $tbl->_get_row_code( \@cols, $theme->{'HEADER_BG_COLOR'}, 1 );
        $i++;
    }

    # without header, just draw the topline, not this midline
    if ($i) {
        $code .= $self->_get_hline_code( $self->_RULE_MID_ID );
    }
    return $code;
}

sub _get_tabletail_code     { return q{}; }
sub _get_xentrystretch_code { return q{}; }
sub _get_tablehead_code     { return q{}; }

1;
__END__

=head1 NAME

LaTeX::Table::Types::TypeI - Interface for Types

=head1 SYNOPSIS

=head1 DESCRIPTION

This is the type interface (or L<Moose> role), that all type objects must use.
L<LaTeX::Table> delegates the boring work of building the LaTeX code to type
objects.

=head1 INTERFACE

=over

=item C<generate_latex_code>

=back

=head1 SEE ALSO

L<LaTeX::Table>

=head1 AUTHOR

Markus Riester  C<< <mriester@gmx.de> >>

=head1 LICENSE AND COPYRIGHT

Copyright (c) 2006-2008, Markus Riester C<< <mriester@gmx.de> >>. 

This module is free software; you can redistribute it and/or
modify it under the same terms as Perl itself. See L<perlartistic>.

=cut

# vim: ft=perl sw=4 ts=4 expandtab
