#-------------------------------------------------------------------------------
# xMove package
# coded by Sanjit Rath
# For bugs and suggestions mail to sanjit.rath at gmail.com
# September - June 2006
#-------------------------------------------------------------------------------

package xmove; 

require v5.6.0; 
use warnings;
use strict;
use Config qw(%Config);

#version of the script 
my $VERSION = 0.1;

#check if the thread support is available
$Config{useithreads} or die "Recompile Perl with threads to run this program.";

use IO::File;
use File::Copy;
use threads;
use threads::shared;
use Thread::Queue;

sub BEGIN
{
	push( @INC, './tsk' );
}

use tsk::task;
use tsk::bucket;

sub new
{
	my ( $class, $numberOfThreads, $logFile, $errorLog ) = @_;
	my @taskList     = ();
	my @threadIdList = ();
	my $self = {
		_numberOfThreads => $numberOfThreads,
		_logFile         => defined($logFile) ? $logFile : "",
		_errorLog        => defined($errorLog) ? $errorLog : "",    #error log
		_taskListRef     => \@taskList,
		_bServerStarted  => 0,                 #server is yet to be started
		_expandThreadId  => undef,
		_threadIdListRef => \@threadIdList,    #list of worker thread id
	};
	
	bless $self, $class;
	return $self;
}



#logger queue of thread ids 
my $qLog = Thread::Queue->new();
#boolean value to stop logger thread 
my $stopLogger : shared = 0;
#thread object of logger thread 
my $thLog =(); 

#error queue of thread ids 
my $qError = Thread::Queue->new();
#boolean value to stop error thread
my $stopError : shared = 0;
#thread object of error thread 
my $thError = (); 

sub __startLogger
{
	my ($this) = @_;
	my $logOpened = 0;
	if ( $this->{_logFile} eq "" )
	{
		$stopLogger = -1;
		return 0;
	}
	else
	{
		if ( open( LOG, ">" . $this->{_logFile} ) )
		{
			$logOpened = 1;
		}
		else
		{
			print "Error: Couldn't open log file $this->{_logFile}\n";
		}
	}

	sub logger
	{
		while ( $stopLogger == 0 && $qLog->pending() > 0 )
		{
			my $__error_val = qLog->dqueue();
			print LOG $__error_val;
			print $__error_val;
		}	
		close(LOG);
	}

	my $tid = threads->create( \&logger, "" );
	unless ( defined($tid) )
	{
		die("Error: Failed to start logger theread\n");
	}
	
	$thLog = $tid;
	return 1; 
}

sub log
{
	my ( $this, $message ) = @_;
	if ( $stopLogger == -1 )
	{
		return;
	}
	$qLog->enqueue($message);
}

sub __startErrorLogger
{
	my ($this) = @_;
	my $logOpened = 0;
	if ( $this->{_errorLog} eq "" )
	{
		$stopError = -1;
		return 0;
	}
	else
	{
		if ( open( ERROR_LOG, ">" . $this->{_errorLog} ) )
		{
			$logOpened = 1;
		}
		else
		{
			print "Error: Couldn't open log file $this->{_errorLog}\n";
		}
	}

	sub error_logger
	{
		while ( $stopError == 0 && $qError->pending > 0 )
		{
			my $__error_val = qLog->dqueue;
			print ERROR_LOG $__error_val;
			print $__error_val;
		}
		
		close(ERROR_LOG);
	}

	my $tid = threads->create( \&error_logger, "" );
	unless ( defined($tid) )
	{
		die("Error: Failed to create error logger thread\n");
	}
	 
	$thError = $tid; 
	return 1; 
}

sub error
{
	my ( $this, $message ) = @_;
	if ( $stopError == -1 )
	{
		return;
	}
	$qError->enqueue($message);
}

#subroutine to stop both error logger and logger threads
sub __stopLoggers
{
	if ( $stopLogger == 0 )
	{
		$stopLogger = 1;
		if ( $qLog->pending() == 0 )
		{
			$qLog->enqueue("\n\n ** stopping logger **\n");
		}
	}

	if ( $stopError == 0 )
	{
		$stopError = 1;
		if ( $qError->pending() == 0 )
		{
			$qError->enqueue("\n ** ending error logger \n");
		}
	}
}

sub addTask
{
	my ( $this, $strSrcDir, $strDestDir, $strFlags ) = @_;
	unless ( defined($strSrcDir) || defined($strDestDir) || defined($strFlags) )
	{
		die("xmove task Error: undefined add task parameters @_ ");
		return;
	}

	my $tsk = new tsk::task( $strSrcDir, $strDestDir, $strFlags );
	push( @{ $this->{_taskListRef} }, $tsk );
}






1; 








