#
# Copyright (c) 2004-2007 - Consultas, PKG.fr
#
# This file is part of A2P.
#
# A2P is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# A2P is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with A2P; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
#
# $Id: Converter.pm 3 2007-10-18 16:20:19Z guillaume $
#

package A2P::Converter;

# Derived class from Thread.pm
use base qw(A2P::Thread AFPDS::afpds2tex);

use strict ;
use integer ;
use Fcntl ':flock';
use A2P::Globals ;
use A2P::Syslog ;
use AFPDS::afpds2tex ;
use A2P::Com qw( IsCom GetCom comJOB comREQ );
use A2P::Tools qw( ShortID ) ;

BEGIN {
    our $VERSION = sprintf "%s", q$Rev: 717 $ =~ /(\d[0-9.]+)\s+/ ;
}
our $VERSION ;

my $LCK ;
my $self ;

################################################################################
##             Converter code                                                 ##
################################################################################
sub Do {
       $self = shift ;
    my $ref  = shift ;

    my $Ret = 0 ;

    my @Job = &IsCom( comJOB , $$ref );

    if ( @Job == 2 ) {
        my ( $Job , $file ) = @Job ;

        # Keep internal stats
        &UPSTAT('CONV_REQ');

    #--------------------------------------
    # It's a file to convert by default
    #--------------------------------------
        my $startpos = 0 ;
        # Check if we were ask to start an AFP file at a given position
        ( $file, $startpos ) = ( $1, $2 ) if ( $file =~ /^(.*):(\d+)$/ );

        &Debug( "Requested to convert '$file' for Job $Job".
            ( $startpos ? ", beginning at pos $startpos" : "" ) );

        # Get folder without trailing '/'
        my ( $jobfolder ) = $SHMDIR =~ m|(.*[^/]+)/?$| ;
        my ( $base ) = $file =~ m|([^/]+)$| ; # Get file basename
        $jobfolder .= "/$Job-$base" ;

        # Found a free folder to compute AFPDS file
        my ( $newfolder , $tries ) = ( $jobfolder , 10 );
        while ( $tries-- ) {
            $! = 0 ;
            # Use standard Perl locking as we are working on our filesystem
            undef $LCK ;
            open($LCK, '>>', $newfolder.".LCK")
                or $self->ThisError("Can't open $newfolder.LCK lock file: $!"),
                   $Ret ++, last ;

            # Try non blocking exclusive lock
            my $locked = flock($LCK, LOCK_EX | LOCK_NB);
            &Debug("Can't lock '$newfolder.LCK': $locked, $!") unless $locked ;

            # Don't use this folder name if folder exists or we don't have lock
            last unless ( ! $locked or -d $newfolder );

            close($LCK);

            $newfolder = $jobfolder . '-' . &ShortID(5) ;
        }
        $jobfolder = $newfolder ;

        if ( ! -d $jobfolder ) {
            &Debug("Starting '$base' conversion in '$jobfolder' for Job $Job");

            # self->{JOB} is necessary to return some informations to JobManager
            # when conversion thread failed abnormally
            # (see A2P/Thread.pm, DESTROY sub)
            $self->{JOB} = $Job ;
            $Ret = $self->ConvertFile( $jobfolder, $file, $Job, $startpos );
            $self->{JOB} = "" ;

            &Debug("Conversion of '$base' returned with value $Ret") if $Ret ;

            # Keep internal stats
            $Ret ? &UPSTAT('BAD_CONV_REQ') : &UPSTAT('GOOD_CONV_REQ') ;

            # Check to handle splitting case
            if ( !$Ret and
            defined($self->{AFPDS}) and $self->{AFPDS}->issplitted() ) {
                # Set splitting event, JobManager handles it as also DONE answer
                $Ret = $self->{AFPDS}->getEnv ;
                # Freeing object
                delete $self->{AFPDS} ;
            }

            # Now return conversion status
            $Ret = DONE unless $Ret ;
            $self->Return( $Job , $Ret );
            $self->AnswerDone( $Job );

            # LCK file will be purge by JobManager during step 12
            # This will release the lock on the folder

        } else {

            # Keep internal stats
            &UPSTAT('BAD_CONV_JOBFOLDER');

            $Ret = 50 ;
            # Return an error status
            $self->Return( $Job , $Ret );
            $self->AnswerDone( $Job );
        }

    } else {

        # Keep internal stats
        &UPSTAT('BAD_CONV_REQFORMAT');

        $self->ThisError("Got bad conversion request '$$ref'");
        $Ret ++ ;

        if (@Job) {
            # Return exec status even for bad format to not break job processing
            $self->Return( $Job[0] , $Ret );
            $self->AnswerDone( $Job[0] );
        }
    }

    return $Ret == DONE ? 1 : 0 ;
}

sub ThreadInit {
    $self = shift ;

    # Initializes stat headers
    $self->{STATHEADERS} = [ qw(
        Date      DayTime   JobID       Jobname     DestId  PageDef
        FormDef   DocName   PageFormats CopyGroups  Logos   NbPages
        Type      LockId
        ) ];

    $self->{HAVE_STATS} = 1 ;
}

sub END {
    return unless (defined($self) and defined($self->{JOB}) and $self->{JOB});

    print $self->getName . ": END step: $self->{JOB}\n";

    # Return an error status
    &Warn("Unexpected abort condition reached on '$self->{JOB}'");
    $self->Return( $self->{JOB} , 254 );
    $self->AnswerDone( $self->{JOB} );
}

&Debug("Module " . __PACKAGE__ . " v$VERSION loaded");

1;
