package Common::Parser::CSV::File;

use strict;
use warnings;

use base 'Class::Accessor';

__PACKAGE__->mk_accessors(qw/csv data fh header named_cols col_names total_lines lineno/);

use Text::CSV;
use FileHandle;

use lib '/app/tools/common/lib';

use Common::Parser::CSV::NamedColumns;

sub new {
    my $class = shift;
    my $file  = shift;
    my $line  = shift;
    my $head  = shift;
    my $self  = {
        'fh' => FileHandle->new( $file, 'r' ),
        'csv' => Text::CSV->new( { 'binary' => 1, 'eol' => $/ } ),
    };
    bless $self, $class;
    if ( defined $head ) {
        if ( defined $line ) {
            my $i = 0;
            while ( $self->csv->getline( $self->fh ) ) {
                next unless ++$i eq $line;
                $self->{'lineno'} = $i;
                last;
            }
        }
        $self->header($head);
    }
    $self->__init__( defined $line ? $line : 1 );
    $self;
}

sub __init__ {
    my $self  = shift;
    my $start = shift;
    unless ( defined $self->header and ref $self->header eq 'ARRAY' ) {
        if ( $start == 0 ) {
            my $line;
            for my $i ( 'a' ... 'z' ) {
                push @{$line}, 'col_' . $i;
            }
            $self->{'lineno'} = 0;
            $self->header($line);
        } else {
            my $i = 0;
            while ( my $line = $self->csv->getline( $self->fh ) ) {
                next unless ++$i eq $start;
                map { $_ =~ s/\n/ /g } @{$line};
                $self->{'lineno'} = $i;
                $self->header($line);
                last;
            }
        }
    }
    $self->named_cols( Common::Parser::CSV::NamedColumns::letter_cols( $self->header ) );
    $self->col_names( Common::Parser::CSV::NamedColumns::col_letters( $self->header ) );
}

sub extract {
    my $self = shift;
    my $data;
    while ( my $row = $self->getrow ) {
        push @{$data}, $row;
    }
    $self->data($data);
    $data;
}

sub getrow {
    my $self = shift;

    my $row = $self->csv->getline( $self->fh );
    return undef unless defined $row;

    ## stop at the limit of lines requested
    return undef if defined $self->total_lines and ( $self->lineno == $self->total_lines );

    my $header = $self->header;

    my $href;
    for ( my $j = 0 ; $j < scalar @{$header} ; $j++ ) {
        $href->{ $header->[$j] } = $row->[$j];
    }
    $self->{'lineno'}++;
    $href->{'lineno'} = $self->lineno;

    $href;

}

sub getcol {
    my $self = shift;
    my $row  = shift;
    my $col  = shift;
    my $key  = $self->named_cols->{ uc($col) };
    ( defined $row->{$key} and $row->{$key} ne '' ) ? $row->{$key} : undef;
}

sub getkey {
    my $self = shift;
    my $row  = shift;
    my $col  = shift;
    $self->named_cols->{ uc($col) };
}

sub getletter {
    my $self = shift;
    my $text = shift;
    my ($col) = map { $self->col_names->{$_} } grep { $_ =~ m/$text/i } keys %{ $self->col_names };
    $col;
}

sub getstr {
    my $self = shift;
    my $row  = shift;
    my @cols;
    foreach my $col ( ( 'A' ... 'Z', 'AA' ... 'ZZ' ) ) {
        next unless exists $self->named_cols->{$col};
        my $key = $self->getkey( $row, $col );
        push @cols, defined $row->{$key} ? $row->{$key} : '';
    }
    $self->csv->combine(@cols);
    $self->csv->string;

}

sub getheader {
    my $self = shift;
    $self->csv->combine( @{ $self->header } );
    $self->csv->string;
}

1;
