#-------------------------------------------------------------------------------
# Generic task storage container
# Coded by Sanjit Rath
# For bugs and suggestions mailto:sanjit.rath@gmail.com
#-------------------------------------------------------------------------------

package tsk::task;

use strict;
use warnings;
use File::stat;
use Time::localtime;

#create new task object
sub new
{
	my ( $class, $src_dir, $dest_dir, $flags ) = @_;

	if ( substr( $src_dir, -1 ) eq '\\' )
	{
		chop($src_dir);
	}

	if ( substr( $dest_dir, -1 ) eq '\\' )
	{
		chop($dest_dir);
	}

	#set the flags
	# -d:d/m/y copies files with modification time after the said date
	# -s copies directories and subdirectoriesand files
	# -e copies directories and subdirectories including empty ones
	# -c continue copying even if error occures, default behaviour is to stop
	#    the script execution
	# -i copyies files from directoriy tree to a destination directory. Here
	#    destination directory structure is not created
	# -h copies system and hidden files
	# -r overwrites read only files
	# -t creates directory structure only
	# -u copies files only if destination file exists
	# -rx: simple wild card expression, possible values *, *.*, *<some>*  
	# -prx: complex perl regular expression 

	my $self = {
				 _source_dir                      => $src_dir,
				 _destitnation_dir                => $dest_dir,
				 _source_dir_length 			  => length($src_dir),
				 _date                            => "",
				 _dir_sub_dir                     => 0,
				 _dir_sub_dir_empty               => 0,
				 _continue_on_error               => 0,
				 _copy_files_to_dir               => 0,
				 _copy_system_hidden_files        => 0,
				 _overwrite_readonly_files        => 0,
				 _create_directory_structure_only => 0,
				 _copy_only_if_destination        => 0,
				 _regEx                           => "", 
				 
				 #internal flags 
				 __if_regEx => -1 #false if regular expression is used 
	};

	bless( $self, $class );

	#set the flags
	my @flags = split( /\s/, $flags );
	foreach my $flg (@flags)
	{
		if ( $flg =~ /-d:(.+)/ )
		{
			$self->{_date} = $1;
		}
		elsif ( $flg eq "-s" )
		{
			$self->{_dir_sub_dir} = 1;
		}
		elsif ( $flg eq "-e" )
		{
			$self->{_dir_sub_dir_empty} = 1;
		}
		elsif ( $flg eq "-c" )
		{
			$self->{_continue_on_error} = 1;
		}
		elsif ( $flg eq "-i" )
		{
			$self->{_copy_files_to_dir} = 1;
		}
		elsif ( $flg eq "-h" )
		{
			$self->{_copy_system_hidden_files} = 1;
		}
		elsif ( $flg eq "-r" )
		{
			$self->{_overwrite_readonly_files} = 1;
		}
		elsif ( $flg eq "-t" )
		{
			$self->{_create_directory_structure_only} = 1;
		}
		elsif ( $flg eq "-u" )
		{
			$self->{_copy_only_if_destination} = 1;
		}
		elsif( $flg =~ /-rx:(.+)/)
		{
			$self->{_regEx} = $self->__compileRegEx($1); 
		}
		elsif( $flg =~ /-prx:(.+)/)
		{
			$self->{_regEx} = $1; 
		}
		else
		{
			#condition for unknown flag 
			die("Error: Unknown flag $flg"); 
		}
	}
	
	#compile the regular expression 
	

	return $self;
}

#subroutine to return source dir 
#arguments: 
#returns: source directory 
sub __taskSourceDir
{
	my ($this) = @_; 
	return $this->{_source_dir}; 
}

#subroutine to return destination dir 
#arguments: 
#returns: destination directory 
sub __taskDestinationDir
{
	my ($this) = @_; 
	return $this->{_destitnation_dir}; 
}


#subroutine to perform task as per the
#arguments:
# source_file, destination file
# return value 1 if ok else 0
# TODO check task as per the flags 
sub __taskAsPerFlags
{
	my ( $this, $srcFile, $destFile ) = @_;

	if ( $this->{_copy_system_hidden_files} == 0 )
	{
		if ( -h $srcFile )
		{
			return 0;
		}
	}

	if ( $this->{_overwrite_readonly_files} == 0 )
	{
		if ( -f $destFile )
		{
			if ( -r $destFile )
			{
				return 0;
			}
		}
	}

	if ( $this->{_copy_only_if_destination} == 1 )
	{
		unless ( -f $destFile )
		{
			return 0;
		}
	}
	
	unless( $this->{_date} eq "")
	{
		return $this->__checkFileDate($srcFile);
	}
	
	unless($this->{_regEx} eq "")
	{
		return $this->__matchFile($srcFile); 
	}

	return 1;
}

# checks if the file modification date is 
# more or less than a given date 
# the given date format should be yyyy/mm/dd 
sub __checkFileDate
{
	my ($this, $file) = @_; 
	my $date = $this->{'_date'}; 
	#get file date
	my $fmDate = (stat($file))[9]; 
	my ($day, $month, $year) = (localtime($fmDate))[3,4,5]; 
	$year = 1900 + $year; 
	my $fileModDate = '$year/$month/$day'; 
	if($fileModDate le $date)
	{
		return 1; 
	}
	else
	{
		return 0; 
	}
}

#takes regex pattern 
# gets file from the srcFilePath 
# trys to match the file with regex pattern 
sub __matchFile
{
	my ( $this, $srcFilePath ) = @_;
	$srcFilePath =~ s/\\/\//g;
	my $sbPath = $srcFilePath; 
	
	my @comps         = split( /\//, $sbPath );
	my $lastComponent = $comps[$#comps];
	if ( $lastComponent =~ /$this->{_regEx}/ )
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

#matches a directory with a regex pattern 
sub __matchDir
{
	my ($this, $directory) = @_; 
	$directory =~ s/\\/\//g; 
	if($directory =~ /$this->{_regEx}/)
	{
		return 1; 
	}
	else
	{
		return 0; 
	}
}

# takes file regex and
# returns perl regex
sub __compileRegEx
{
	#TODO: check/test compile regEx for wild card expressions 
	my ($this, $strExpr) = @_;
	
	unless(defined($strExpr))
	{
		return; 
	}
	 
	if($strExpr eq "")
	{
		return; 
	}
	
	#strategy for compiling regular expressions 
	#replace . with \. 
	#replace * with (.+)?
	
	$strExpr =~ s/\./\\\./g;
	$strExpr =~ s/\*/\(\.\+\)\?/g;   
	
	$this->{_regEx} = $strExpr; 
}

#public method 
# takes source file 
# returns file path if the flag parameters are met 
# else returns 0 
sub destPath
{
	my ($this, $srcFilePath) = @_; 
	#strip off source dir length
	my $fileSubPath = substr($srcFilePath, $this->{_source_dir_length}); 
	my $destFilePath = $this->{_destitnation_dir}.$fileSubPath; 
	
	#currently directories are passed unconditionally
	if(-d $srcFilePath)
	{
		return $destFilePath; 
	}
	
	
	#TODO: check file attributes as per the flags
	#check for validity of operation
	if($this->__taskAsPerFlags($srcFilePath, $destFilePath))
	{
		return $destFilePath; 
	}
	else
	{
		return "";
	}
}

1;
