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

use File::Basename;
use Audio::FLAC;

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 MediaServe::Audio::Converter::Wav;

use constant kDefaultSourceFormat => 'flac';

use base 'MediaServe::Converter';

# ----> How to use this class <----
#
# Convert FLAC audio into something different
#
# my $converter = MediaServe::Audio::Converter->new
# (
#   filename => "myaudio.flac",
# );
#
#

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

    $self->{_start}  = $args{start};
    $self->{_length} = $args{length};

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

sub _sourceFormat { 'flac' }

sub read {
    my $self     = shift;
    my $filename = shift;
    my $error;

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

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

    my $audio = new Audio::FLAC($filename);
    $error = $audio->info();

    unless ($error) {
        $self->{_error} = "Failed to parse flac file '$filename'\n";
        return undef;
    }

    $self->{_audio} = $audio;

    return 1;
}

sub timeAsSeconds {
    my $self = shift;

    assert( $self && $self->{_audio} );

    my $info = $self->{_audio}->info();

    assert( $info, "Unable to read flac info" );

    my $totalSamples = $info->{TOTALSAMPLES};
    my $sampleRate   = $info->{SAMPLERATE};

    assert( $sampleRate, "No sample rate, div / 0" );

    return int( $totalSamples / $sampleRate );
}

sub timeAsISO8601 {
    my $self = shift;

    assert( $self && $self->{_audio} );

    my $info = $self->{_audio}->info();
    my $time = $self->timeAsSeconds();

    my $minutes = int( $time / 60 );
    my $seconds = $time % 60;
    return "PT${minutes}M${seconds}S";
}

sub write {
    die "Must be overloaded";
}

sub _getSourceFile {
    my $self = shift;
    my $filename = shift || die;

    my $extension = $self->_sourceFormat();

    # Return the filename if it has an extension
    return $filename if ( $filename =~ /\./ );

    # Otherwise copy it to a temp file and read from that.
    my $tmpFile = File::Temp->new( UNLINK => 1, SUFFIX => ".$extension" );

    my $resultFile = $self->_sourceToTemp( $filename, $tmpFile );

    return $resultFile ? $resultFile : undef;
}

sub _sourceToTemp {
    my $self      = shift;
    my $source    = shift;
    my $tmpfile   = shift;
    my $extension = $self->_sourceFormat();

    my $clipExtension = 'flac';

    my $sourceCopy = File::Temp->new( UNLINK => 1, SUFFIX => ".flac" );
    die("Failed to create tmp file: $sourceCopy: $!")
      unless ( -e "$sourceCopy" );

    if ( $self->{_start} || $self->{_length} ) {
        Common::Log::Debug( "  - Clipping preview of source $sourceCopy, " . " START: $self->{_start}, LENGTH: $self->{_length}" );

        my $sox = Common::RSApp::GetConfig( 'distribution', 'encoders_windows_sox' );
        my $start = $self->{_start} || 0;
        my $stop = $self->{_length} + $start if ( $self->{_length} );

        my $cmd = sprintf( "%s \"%s\" -t %s \"%s\" trim %d %s", $sox, "$source", $clipExtension, $sourceCopy, $start, $stop ? $stop : "" );

        Common::Log::Debug("EXECUTE: $cmd");
        my $res = system($cmd );
        return if ($res);
    } else {
        File::Copy::copy( $source, $sourceCopy );
    }

    if ( $extension =~ /^wav$/ ) {
        $self->_sourceToTempWav( "$sourceCopy", $tmpfile );
    } elsif ( $extension =~ /^flac$/ ) {
        $self->_sourceToTempFlac( "$sourceCopy", $tmpfile );
    } else {
        die "Unknown source format, $extension";
    }

    return $tmpfile;
}

sub _sourceToTempWav {
    my $self   = shift;
    my $source = shift;
    my $dest   = shift;

    Common::Log::Debug("  - CONVERTING $source to file $dest");
    my $converter = new MediaServe::Audio::Converter::Wav( filename => $source );
    $converter->write($dest);
}

sub _sourceToTempFlac {
    my $self   = shift;
    my $source = shift;
    my $dest   = shift;

    Common::Log::Debug("  - Copy source $source to a temp file $dest");
    File::Copy::syscopy( $source, $dest );
}

1;
