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

package MediaServe::BookPub::Converter;
use strict;
use warnings;

use Image::Magick;
use File::Basename;

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

use lib '/app/tools/mediaserve/lib';
use MediaServe::DB::Item::AlbumFile;
use MediaServe::Converter;

use base 'MediaServe::Converter';

# ----> How to use this class <----
#
# Convert images into different RS standard formats.
#
# my $converter = MediaServe::Image::Converter->new
# (
#   filename => "myimage.gif",
#   allow_upscaling => 0
# );
#
# $converter->write_web_thumbnail( "/tmp" );
# $converter->write_web_image( "/tmp", "override.jpg" );
# $converter->write_distribution_image( "/tmp" );
#

use constant kImageFormat => (
    geometry       => '600x600',
    dpi            => '72',
    shape_variance => '10',                # percentage not square
    formats        => [ 'jpeg', 'tiff' ]
);

#
# resize filters: Point, Box, Triangle, Hermite, Hanning, Hamming, Blackman,
#                 Gaussian, Quadratic, Cubic, Catrom, Mitchell, Lanczos,
#                 Bessel, Sinc
#
use constant kResizeSettings => (

    web_thumbnail => {

        #geometry => '45x64',
        width       => 45,
        filter      => undef,
        blur        => undef,
        density     => 72,
        format      => 'jpeg',
        extension   => 'Th',
        compression => undef
    },

    web_image => {

        #geometry => '270x384',
        width       => 210,
        filter      => undef,
        blur        => undef,
        density     => 72,
        extension   => 'L',
        compression => 'None',
        format      => 'jpeg'
    },

);

sub validate { 1 }

sub read {
    my $self     = shift;
    my $filename = shift;
    my $image    = new Image::Magick;
    my $error;

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

    $self->{_image}    = undef;
    $self->{_filename} = $filename;

    $error = $image->Read($filename);

    if (   $error
        && $error !~ /Exception 350/ ) {
        $self->{_error} = $error;
        return undef;
    }

    $self->{_image} = $image;

    return 1;
}

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

sub write_web_thumbnail {
    my $self    = shift;
    my %formats = (kResizeSettings);
    assert( $formats{web_thumbnail} );

    return $self->_write_image( $formats{web_thumbnail}, @_ );
}

sub write_web_image {
    my $self    = shift;
    my %formats = (kResizeSettings);
    assert( $formats{web_image} );

    return $self->_write_image( $formats{web_image}, @_ );
}

sub write_original {
    my $self = shift;
    return $self->_write_image( undef, @_ );
}

sub write {
    my $self = shift;
    my ( $format, $dir, $file ) = @_;

    assert($format);
    assert($dir);
    assert($file);

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

sub _write_image {
    my $self            = shift;
    my $format          = shift || {};
    my $output_dir      = shift;
    my $output_filename = shift || $self->{_filename};
    my $image           = $self->{_image};
    my $output;
    my @resize_args;
    my @write_args;

    assert($self);
    assert($output_dir);
    assert($output_filename);
    assert($image);

    # Don't muck with the original
    $image = $image->Clone();

    unless ( ref($image) ) {
        $self->{_error} = $image;
        return undef;
    }

    # Setup the output file
    $output = basename($output_filename);
    $output = "$output_dir/$output";
    if ( $format->{format} ) {
        $output =~ s/(.*)\..*/$1/;
        $output .= "-$format->{extension}.";
        $output .= $format->{format};
        $output = "$format->{format}:$output";
    }

    my ( $width, $height ) = split( /x/i, $format->{geometry} ) if ( $format->{geometry} );
    ( $width, $height ) = $self->_constrainSize(
        width  => $format->{width},
        height => $format->{height},
        image  => $image
    ) unless ( $format->{geometry} );

    #Common::Log::Debug( "Writing image to $output" );

    #push( @resize_args, geometry => $format->{geometry} ) if( $format->{geometry} );
    push( @resize_args, height => $height )           if ($height);
    push( @resize_args, width  => $width )            if ($width);
    push( @resize_args, filter => $format->{filter} ) if ( $format->{filter} );
    push( @resize_args, blur   => $format->{blur} )   if ( $format->{blur} );

    push( @write_args, compression => $format->{compression} ) if ( $format->{compression} );
    push( @write_args, density     => $format->{density} )     if ( $format->{density} );

    $self->{_error} = $image->Set( Type => "TrueColor" );

    unless ( $self->{_error} ) {
        Common::Log::Debug("  - Resize image: @resize_args");
        $self->{_error} = $image->Resize(@resize_args) if (@resize_args);
    }

    unless ( $self->{_error} ) {
        Common::Log::Debug("Writing $output");
        $self->{_error} = $image->Write( filename => "$output", @write_args );
    }

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

sub outputFilename {
    my $self     = shift;
    my $filename = shift;
    my $type     = shift;
    my %formats  = (kResizeSettings);
    my $format;

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

    Common::Log::Debug("Converting filename: $filename");
    if ( $type eq MediaServe::DB::Item::AlbumFile::kFileTypeOriginal ) {
        return $filename;
    }

    if ( $type eq MediaServe::DB::Item::AlbumFile::kFileTypeThumbnail ) {
        $format = "web_thumbnail";
    } elsif ( $type eq MediaServe::DB::Item::AlbumFile::kFileTypeLarge ) {
        $format = "web_image";
    }

    assert( $format, "Unknown image format" );

    my $base = basename($filename);
    $base =~ s/(.*)\..*/$1/;
    $base = $filename unless ($base);
    my $out = $base . "-" . $formats{$format}->{extension} . "." . $formats{$format}->{format};

    Common::Log::Debug("Converted filename: $out");

    return $out;
}

sub getFileTypes {
    return ( MediaServe::DB::Item::AlbumFile::kFileTypeOriginal,
        MediaServe::DB::Item::AlbumFile::kFileTypeThumbnail,
        MediaServe::DB::Item::AlbumFile::kFileTypeLarge
    );

}

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

    my $width  = $args{width};
    my $height = $args{height};
    my $image  = $self->{_image};

    assert($image);

    return unless ( $width || $height );
    return ( $width, $height ) if ( $width && $height );

    my ($xres) = $image->Get("width");
    my ($yres) = $image->Get("height");

    my $delta = $width ? ( $width / $xres ) : ( $height / $yres );

    $height = int( $yres * $delta ) unless ($height);
    $width  = int( $xres * $delta ) unless ($width);

    return ( $width, $height );
}

1;
