#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------

package Common::Translator::VersionWithHeader;

use base 'Common::Translator::Version';

#
# Common::Translator::VersionWithHeader
#
# This class provides an interface like Common::TranslatorVersion
# but also does header and column mapping.
#

use strict;

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::Log;

sub _requiredHeaders { }
sub _optionalHeaders { }

sub hasHeader { 1 }

sub _buildIndex {
    my $self = shift;

    assert( $self->{_parser} );
    assert( ( $self->_requiredHeaders() || $self->_optionalHeaders() ) );

    my $header = $self->_getHeader();

    unless ($header) {
        $self->{_error} = "Empty file";
        return;
    }

    Common::Log::Debug( "Building index using: " . ref($self) );
    $self->_createHeaderIndex($header);
}

sub _getHeader {
    my $self = shift;

    $self->{_parser}->rewind();
    return $self->{_parser}->next();
}

sub _createHeaderIndex {
    my $self = shift;
    my $row  = shift;

    assert($row);

    my %mapFromToHeader = $self->_getValidHeaders();

    my @missingRequired;
    my @unknownHeaders;
    my @validHeaders = keys(%mapFromToHeader);
    my @foundHeaders;
    my @requiredHeaders = keys( %{ $self->_requiredHeaders() } )
      if ( $self->_requiredHeaders() );

    my %indexByColumn;
    my %indexByOriginal;

    my $fromKey;
    my $toKey;

    # First read all the headers found in the datafile and try to map them.
    for ( my $i = 0 ; $i < $row->columnCount() ; $i++ ) {
        my $fromKey = $self->_cleanHeader( $row->getColumn($i) );

        if ($fromKey) {
            $toKey = $mapFromToHeader{$fromKey};

            if ($toKey) {
                Common::Log::Debug(" HEADER MAP: FROM: $fromKey TO: $toKey");
                $indexByOriginal{$fromKey}->{column} = $i;
                $indexByOriginal{$fromKey}->{to}     = $toKey;

                $indexByColumn{$i}->{from} = $fromKey;
                $indexByColumn{$i}->{to}   = $toKey;
            } else {
                Common::Log::Debug(" Unknown key: $fromKey");
                push( @unknownHeaders, $fromKey );
            }
        }
    }

    # Now check if all required headers have been mapped
    foreach my $h (@requiredHeaders) {
        unless ( defined( $indexByOriginal{$h} ) ) {
            push( @missingRequired, $h );
        }
    }

    $self->{_missingHeaders} = @missingRequired ? \@missingRequired : undef;
    $self->{_unknownHeaders} = @unknownHeaders  ? \@unknownHeaders  : undef;

    $self->{_mapByColumn}   = \%indexByColumn;
    $self->{_mapByOriginal} = \%indexByColumn;

    return $self->error ? 1 : undef;
}

sub _getValidHeaders {
    my $self = shift;

    my @headers;

    if ( $self->_requiredHeaders() ) {
        push( @headers, %{ $self->_requiredHeaders() } );
    }

    if ( $self->_optionalHeaders() ) {
        push( @headers, %{ $self->_optionalHeaders() } );
    }

    return @headers;
}

sub validate {
    my $self = shift;

    unless ( $self->{_parser}->fileType() eq 'table' ) {
        $self->{_error} = "Input is not tabular";
        return;
    }

    if (   $self->{_missingHeaders}
        || $self->{_unknownHeaders} ) {
        $self->{_error} = "Invalid Header";
        return;
    }

    return $self->error ? undef : 1;
}

sub missingHeaders { shift->{_missingHeaders} }
sub unknownHeaders { shift->{_unknownHeaders} }

sub getMapByColumn {
    my $self   = shift;
    my $column = shift;

    assert( defined($column) );

    return $self->{_mapByColumn}->{$column};
}

sub _cleanHeader {
    my $self = shift;
    my $headerName = shift || return;

    # remove regex metachars
    $headerName =~ s/[\*\?]//g;

    # Trim spaces
    $headerName =~ s/\s//g;
    $headerName =~ s/\x0d//g;
    $headerName = lc($headerName);

    return $headerName;
}

###
1;    # Play nicely.
###
