#!/usr/bin/perl

use strict;
use warnings;

binmode STDOUT, ":utf8";

use lib '/var/app/orchard/collab/jgetter/perllib';

use String::Util;

use Orchard::Session;
use Orchard::ETL::Extract::CSV;

## command line options
my ( $opt, $usage ) = clopt(
    [ 'column|c=s'      => 'Named column to print' ],
    [ 'delimiter|d=s'   => 'Delimiter for records [tab] for \t', { 'default'  => ',' } ],
    [ 'empty|e=s'       => 'What to use for empty fields',       { 'default'  => 'NULL' } ],
    [ 'file|f=s'        => 'CSV file to ingest',                 { 'required' => '1' } ],
    [ 'goto|g=i'        => 'Goto line number to start',          { 'default'  => 0 } ],
    [ 'help|?|h'        => "print usage message and exit" ],
    [ 'line|l=i'        => 'Print this specific line' ],
    [ 'ncols|n'         => 'Print the named columns of the file' ],
    [ 'skip_lines'      => "Don't print record lines" ],
    [ 'skip_header'     => "Don't print header" ],
    [ 'raw|r'           => "Just print column data" ],
    [ 'start|s=i'       => 'Header line to start with in the file', { 'default' => 1 } ],
    [ 'total_lines|t=i' => 'Total lines to print' ],
    [ 'width|w=i'       => 'Width of the columns for print', { 'default' => 20 } ],
);
( $usage->text and exit 1 ) if $opt->help;

## if raw skip and skip lines
if ( defined $opt->raw ) {
    $opt->{'skip_lines'}  = 1;
    $opt->{'skip_header'} = 1;
}

## csv object
my $csv = Orchard::ETL::Extract::CSV->new( $opt->file, $opt->start, undef, $opt->delimiter );

## print out the named_cols hash to see A,B...ZZ colums to assist mapping columns
if ( defined $opt->ncols ) {
    map { printf( "%2s => %s\n", $_, $csv->named_cols->{$_} ) if exists $csv->named_cols->{$_} }
      ( 'A' ... 'Z', 'AA' ... 'ZZ', 'AAA' ... 'ZZZ' );
    exit 1;
}

## only print out a certain amount of lines
$csv->total_lines( $opt->total_lines + $opt->start + $opt->goto ) if defined $opt->total_lines;

## if columns is set then print out the header and set the formatting for printf
my @header;
my $strfmt;
my $strlen = $opt->width;
if ( defined $opt->column ) {
    ## create @header and @colnames arrays
    ## colnames gets trimmed by substr to strlen
    my @colnames;
    foreach my $col ( split ",", $opt->column ) {
        push @header,   $csv->named_cols->{ uc($col) };
        push @colnames, substr( $csv->named_cols->{ uc($col) }, 0, $strlen - 2 );
    }

    ## set the delimiter for the strfmt
    #my $d = $opt->delimiter;
    my $d = ' ';
    map { $strfmt .= "%-${strlen}s${d}" } @header;
    $strfmt = defined $opt->raw ? "$strfmt\n" : "%4s${d}$strfmt\n";

    ## print the header
    unless ( defined $opt->skip_header ) {
        print "\n";
        underline();
        printf( $strfmt, "Line", @colnames );
        underline();
    }

}

## iterate thru the file's lines - CRLF blows this up pretty badly
## best to use *nix newline delimited files
while ( my $row = $csv->getrow ) {
    next if defined $opt->line and $opt->line != $csv->lineno;
    next if $opt->goto         and $csv->lineno < $opt->goto;
    if ( scalar @header ) {
        ## if the columns choosen are all null don't print any
        my $printit = 0;
        my @vals;
        for ( my $i = 0 ; $i < scalar @header ; $i++ ) {
            if ( not defined $row->{ $header[$i] } or $row->{ $header[$i] } eq '' ) {
                $vals[$i] = $opt->empty;
            } else {
                ## found a value print at least this line
                my $value = $row->{ $header[$i] };
                $value =~ s/\n/ \\n /g;
                $value = String::Util::trim($value);
                $vals[$i] = substr( $value, 0, $strlen - 2 );
                $printit++;
            }
        }
        ## print to STDOUT if values for the columns are found
        if ($printit) {
            if ( $opt->raw ) {
                printf( $strfmt, @vals );
            } else {
                printf( $strfmt, $csv->lineno, @vals );
                underline();
            }
        }
    } else {
        ## just dump the whole row hash if opt->columns isn't set
        print Dumper( "line: " . $csv->lineno, $row ) . "\n";
    }
    last if defined $opt->line;
}

## format like mysql output with top/bottom lines per record
sub underline {
    my @line;
    for ( my $i = 0 ; $i < scalar @header ; $i++ ) {
        push @line, "-" x $strlen;
    }
    printf( $strfmt, '-' x 4, @line ) unless $opt->skip_lines;
}
