#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2010 RoyaltyShare, Inc.      All Rights Reserved
#---------------------------------------------------------------

package Common::File::Base;
use strict;

use lib '/app/tools/common/lib';
use Common::UTF8;
use Common::Util;
use Common::Log;
use Common::Assert;
use IO::File;

sub _encoding       { die "Must be overloaded" }
sub _getHeaderBytes { die "Must be overloaded" }
sub _isValid        { die "Must be overloaded" }

# JPK - This will become the _preferred_ way to test whether a file at a given path
#       is a valid file of this type.
#
sub IsValid {
    my ( $class, $path ) = @_;
    assert($path);

    my $file = $class->new($path);
    my $flag = $file->isValid();
    $file->close();

    return $flag;
}

sub new {
    my $class = shift;
    my $self = bless {}, $class;

    return $self->_init(@_);
}

# Returns the size, in bytes, of the file byte-order header (if any).
#
sub headerSize {
    my ($self) = @_;

    my @header = $self->_getHeaderBytes();
    return scalar @header;
}

sub _init {
    my $self     = shift;
    my $filename = shift;

    if ( defined $filename ) {
        $self->open($filename);
    }

    return $self;
}

sub error      { shift->{_error} }
sub filename   { shift->{_filename} }
sub filehandle { shift->{_filehandle} }
sub fileheader { shift->{_fileheader} }

sub open {
    my $self = shift;
    my $filename = shift || die "filename required";

    if ( $self->{_filehandle} ) {
        $self->close();
    }

    $self->{_filename} = $filename;
    $self->_openFile();

    return 1;
}

sub close {
    my ($self) = @_;
    if ( $self->{_filehandle} ) {
        CORE::close( $self->{_filehandle} );
        $self->{_filehandle} = undef;
        $self->{_fileheader} = undef;
    }
}

sub _openFile {
    my $self = shift;
    die "No filename specified" unless ( defined $self->filename );

    unless ( $self->filehandle ) {

        #        CORE::open( INFILE, '<:raw', $self->filename) || die "Couldn't open file: $!";
        #        CORE::open( INFILE, $self->filename) || die "Couldn't open file: $!";
        #        $self->{_filehandle} = \*INFILE;
        $self->{_filehandle} = IO::File->new( $self->filename ) || die "Couldn't open file: $!";

        $self->_getHeaderBytes();

        binmode( $self->{_filehandle}, ':encoding(' . $self->_encoding() . ')' ) if $self->_encoding();

        # !!! I think I need to do this...
        #
    }

    return $self->filehandle;
}

sub readLine {
    my ($self) = @_;
    my $fh = $self->filehandle();

    my $line = <$fh>;

    return unless defined $line;

    # provide the newline...  Don't strip that out.
    #
    #    chomp($line);

    # !!! JPK  -  It looks like the encoding mumbo-jumbo obviates the need to call Encode here.
    # !!! At least it does for UTF16 files...
    #
    my $decoded = $line;

    #    my $decoded = Common::UTF8::Encode( $line, $self->_encoding() );
    $decoded =~ s/\cM//g;

    return $decoded;
}

sub read {
    my $self = shift;

    my @lines;
    my $fh = $self->filehandle();

    die "Encoding type required: $self" unless ( $self->_encoding() );

    $self->_getHeaderBytes();

    my $text = do { local $/; <$fh> };

    #    my $decoded = Common::UTF8::Encode( $text, $self->_encoding() );
    my $decoded = $text;

    $decoded =~ s/\cM//g if ( $decoded =~ /\cJ/ );
    @lines = split( /(?:\cM\cJ|\cJ|\cM)/m, $decoded );

    return \@lines;
}

sub DESTROY {
    my ($self) = @_;
    $self->close();
}

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