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

use File::Basename;

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 _process {
    my $self = shift;
    assert($self);

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

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

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

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

    $self->debug("- Starting image asset matching");
    my $matcher = new MediaServe::Image::Matcher();
    my $count   = $matcher->match_files();

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

sub convert_images {
    my $self       = shift;
    my $client_id  = Common::RSApp::GetClientID();
    my $converter  = new MediaServe::Image::Converter();
    my $media_file = new MediaServe::MediaFile();

    assert($self);

    my $dir   = RPS::Catalog::ImageUpload::kImageDirectory . "/$client_id";
    my @files = $self->_get_files("upload");

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

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

        if ( $self->_isAlbumDistributing($file) && !$self->{_force} ) {
            $self->debug("  * Album is distributing. ignoring file: $file");
            next;
        }

        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");

            next;
        }

        # Added new file records if needed.
        foreach my $type ( $converter->getFileTypes() ) {
            $media_file->addAlbumFile(
                type     => $type,
                filename => $converter->outputFilename( $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->write_original("$dir/transfer");
        $converter->write_web_thumbnail("$dir/transfer");
        $converter->write_web_image("$dir/transfer");
        $converter->write_distribution_image("$dir/transfer");

        unlink("$dir/upload/$file");
    }
}

sub image_transfer {
    my $self      = shift;
    my $client_id = Common::RSApp::GetClientID();
    my $dir       = RPS::Catalog::ImageUpload::kImageDirectory . "/$client_id/transfer";
    my @files     = $self->_get_files("transfer");
    my ( $host, $path );
    my $album_file;

    my $sftp = new MediaServe::SFTP(
        user     => kDistributionUser,
        password => kDistributionPasswd,
        identity => kDistributionIdent,
        debug    => $self->{_verbose}
    );

    assert($self);

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

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

        $album_file = MediaServe::DB::Item::AlbumFile->LookupByFilename( filename => $_ );

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

        ( $host, $path ) = MediaServe::Server::GetImagePath(
            clientID    => $client_id,
            mediaFileID => $album_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 _isAlbumDistributing {
    my $self     = shift;
    my $filename = shift;

    assert($self);
    assert($filename);

    my $matcher  = new MediaServe::Image::Matcher;
    my %criteria = $matcher->get_match_criteria($filename);
    my @ids      = MediaServe::DB::Item::AlbumFile->GetMatchIDs(%criteria);

    return undef unless (@ids);

    return 1 if ( RPS::DB::Item::Album->HasQueuedJobs( album_id => \@ids ) );

    return undef;
}

sub _get_files {
    my $self      = shift;
    my $subdir    = shift || "";
    my $client_id = Common::RSApp::GetClientID();
    my $dir       = RPS::Catalog::ImageUpload::kImageDirectory . "/$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;
