#------------------------------------------------------------
# Copyright (C) 2010 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package MediaServe::ImageProcessor;
use strict;
use warnings;

use File::Basename;
use Capture::Tiny(qw/capture/);

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

use lib '/app/tools/mediaserve/lib';
use MediaServe::Server;
use MediaServe::SFTP;
use MediaServe::Image::Converter;
use MediaServe::Image::Matcher;

use lib '/app/tools/rps/lib';
use RPS::Catalog::ImageUpload;

use base 'MediaServe::Processor';

use constant kDistributionUser   => 'web';
use constant kDistributionPasswd => 'getImages';
use constant kDistributionIdent  => undef;

sub _init {
    my $self = shift;
    my %args = @_;

    $self->{_force} = $args{force};

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

sub _errors {
    my $self = shift;
    if (@_) {
        $self->{'_errors'} = shift;
    }
    return $self->{'_errors'};
}

sub _process {
    my $self = shift;
    assert($self);

    my $client_id = Common::RSApp::GetClientID();
    $self->log("client id: $client_id - Begin image processing");

    # Do all image conversion
    $self->convertImages();

    # Match assets in the database
    $self->matchImageAssets();

    # Transfer all images to the media server
    $self->imageTransfer();

    ## remove files in upload directory if no errors
    if ( not defined $self->_errors ) {
        $self->removeUploadFiles();
    }

    $self->log("client id: $client_id - End image processing");
}

sub _importAllowed { 1 }

sub removeUploadFiles {
    my $self = shift;

    my $client_id = Common::RSApp::GetClientID();
    my $dir       = $self->_imageDir . "/$client_id";
    my @files     = $self->_getFiles("upload");

    foreach my $file (@files) {
        my $uploadFile = "$dir/upload/$file";
        $self->log("Unlink : $uploadFile");
        unlink $uploadFile;
    }

}

sub matchImageAssets {
    my $self = shift;
    assert($self);

    $self->debug("- Starting image asset matching");
    my $matcher = $self->_assetMatcherObject();
    my $count   = $matcher->match_files();

    if ($count) {
        my $client_id = Common::RSApp::GetClientID();
        $self->log("client id: $client_id - Matched $count image assets");
    }

}

sub convertImages {
    my $self = shift;

    my $client_id  = Common::RSApp::GetClientID();
    my $converter  = $self->_converterObject();
    my $media_file = new MediaServe::MediaFile();

    assert($self);

    my $dir   = $self->_imageDir . "/$client_id";
    my @files = $self->_getFiles("upload");

    $self->debug("- Starting image conversion");

    my $errors = $self->_errors;

    foreach my $file (@files) {
        $self->debug("  + file to convert: $file");

        next unless ( $self->_importAllowed() );

        unless ( $converter->read("$dir/upload/$file") && $converter->validate() ) {
            print STDERR "Failed to read input file: $dir/upload/$file\n";
            print STDERR "   - " . $converter->{_error} . "\n";

            system("mkdir -p $dir/errors");
            system("mv $dir/upload/$file $dir/errors/$file");

            push @{ $errors->{$file} }, $converter->_error;

            next;
        }

        # Added new file records if needed.
        foreach my $type ( $converter->getFileTypes() ) {
            $self->_addFile( $converter, $media_file, $file, $type );
        }

        # Convert Files and move them to the transfer directory
        system("mkdir -p $dir/transfer");

        assert( -d "$dir/transfer", "Directory doesn't exist" );

        $converter->{'_error'} = undef;
        $self->_writeImages( $converter, "$dir/transfer" );

        push @{ $errors->{$file} }, $converter->_error if $converter->_error;

    }

    $self->_errors($errors);

}

sub imageTransfer {
    my $self      = shift;
    my $client_id = Common::RSApp::GetClientID();
    my $dir       = $self->_imageDir . "/$client_id/transfer";
    my @files     = $self->_getFiles("transfer");

    assert($self);

    $self->debug("- Starting image transfer");

    my $class = $self->_dbClass;
    eval "require $class";
    die $@ if ($@);

    my $errors = $self->_errors;

    foreach (@files) {
        $self->debug("   + Setting up transfer for: $_");

        my $file = $self->_dbClass()->LookupByFilename( filename => $_ );

        unless ($file) {
            print STDERR "Media File not found for '$_'\n";
            next;
        }

        my ( $host, $path ) = MediaServe::Server::GetImagePath( clientID => $client_id, mediaFileID => $file->media_file_id );

        my $source = "$dir/$_";
        my $dest   = "/app/shared" . $path;

        my $destDir = File::Basename::dirname($dest);
        my $dirExists = -e $destDir ? 1 : 0;
        if ( !-e $destDir ) {
            my $cmd = "mkdir -p $destDir";
            $self->debug("   + $cmd");
            my $cli = [ capture { system $cmd } ];
            if ( $cli->[2] ) {
                $self->debug("   + Directory $destDir failed to create");
                push @{ $errors->{$file} }, $cli->[1];
            } else {
                $dirExists = 1;
            }
        }
        next if not $dirExists;

        my $cmd = "cp $source $dest";
        $self->debug("   + $cmd");
        my $cli = [ capture { system $cmd } ];
        if ( not $cli->[2] ) {
            $self->debug("   + Transfer complete.  Unlink: $source");
            unlink($source);
        } else {
            $self->debug( "   + Transfer Failed.  " . $cli->[1] );
            push @{ $errors->{$file} }, $cli->[1];
        }
    }

}

##
## deprecated sftp to colo - jg 20190123
##
#sub imageTransfer {
#    my $self      = shift;
#    my $client_id = Common::RSApp::GetClientID();
#    my $dir       = $self->_imageDir . "/$client_id/transfer";
#    my @files     = $self->_getFiles("transfer");
#    my ( $host, $path );
#    my $file;
#
#    my $sftp = new MediaServe::SFTP(
#        user     => kDistributionUser,
#        password => kDistributionPasswd,
#        identity => kDistributionIdent,
#        debug    => $self->{_verbose}
#    );
#
#    assert($self);
#
#    $self->debug("- Starting image transfer");
#
#    my $class = $self->_dbClass;
#    eval "require $class";
#    die $@ if ($@);
#
#    foreach (@files) {
#        $self->debug("   + Setting up transfer for: $_");
#
#        $file = $self->_dbClass()->LookupByFilename( filename => $_ );
#
#        unless ($file) {
#            print STDERR "Media File not found for '$_'\n";
#            next;
#        }
#
#        ( $host, $path ) = MediaServe::Server::GetImagePath(
#            clientID    => $client_id,
#            mediaFileID => $file->media_file_id
#        );
#
#        $sftp->connect($host);
#        assert( -e "$dir/$_" );
#
#        $self->debug("   -> Copy $_ to $host:$path");
#        $sftp->mkdir( dirname($path) );
#        if ( $sftp->put( "$dir/$_", "$path" ) ) {
#            $self->debug("   + Transfer complete.  Unlink: $_");
#            unlink("$dir/$_");
#        } else {
#
#            # for some reason, the quotemeta or destination that's
#            # done in the standard sftp->put fails in our ec2/amilinux
#            # environment. We'll try brute forcing for now, skipping
#            # that bit and doing the SCP directly.
#            #
#            # and in case folks think this is hacky, it is, but we
#            # should be going the s3 route shortly, so this FTP business
#            # will go by the wayside anyway.
#            $self->debug("   + First put failed. Retrying...");
#            if ( $sftp->{_sftp}->ssh()->scp_put( "$dir/$_", "$path" ) ) {
#                $self->debug("   + Transfer complete.  Unlink: $_");
#                unlink("$dir/$_");
#            } else {
#
#                # if it's still failing make sure we've logged
#                # into the media server at least one time in order
#                # to save host keys. If it's still failing, you're
#                # on your own
#                $self->debug("   + Transfer Failed.  $@");
#            }
#        }
#    }
#}

sub _getFiles {
    my $self      = shift;
    my $subdir    = shift || "";
    my $client_id = Common::RSApp::GetClientID();
    my $dir       = $self->_imageDir . "/$client_id/$subdir";

    no warnings;

    $self->debug("- Getting files from $dir");

    opendir( DIR, $dir ) || return;

    # Match all files that are not . or ..
    my @files = grep( !/^(\.\.?)$/, readdir(DIR) );
    closedir(DIR);

    $self->debug("   + Files: @files");

    return @files;
}

1;
