#!/usr/bin/perl

###########################
### Autor: Sebastian Enger / B.Sc. 
### Copyright: Sebastian Enger
### Licence: BSD
### Version: 1.1.b  - 20080716@19.Uhr
### Contact: sebastian.enger@gmail.com | icq: 135846444
### Web: http://www.bitjoe.de - Handy P2P Suchmaschine und Downloads
### Latest Version: PENDRIVE:\Programming\Perl\IncrementalBackup
###########################

use strict;
use File::Find;	# perl -MCPAN -e 'force install "File::Find"'
use File::Copy;	# perl -MCPAN -e 'force install "File::Copy"'
use File::Path;	# perl -MCPAN -e 'force install "File::Path"'

# debug
# use Data::Dumper;

print "$0 initializing\n";

my $SourceFolder		= $ARGV[0] || 'F:\My Business'; # F: - source folder
my $DestFolder			= $ARGV[1] || 'I:\My Business'; # I: - destination folder	| 'N:\USBSTICK\My Business'
my (@tmp)				= split(":", $DestFolder );
my $Destination			= $tmp[0] . ":";				# I: - destination to which is copied

#my $DestFileStructure	= {};	# keeps filestructure of DestFolder
my $ErrorFileStructure	= {};	# keeps files that failed copying
my $CopyErrorMessage	= "";	# keeps error message for final output of files that have not been copied successfully
my $SourceFileCount		= 0;	# keeps count of overall files in source folder
my $CopiedFileCount		= 0;	# keeps count of file that must be copied because source files are newer than dest files
my $FailedCopyFile		= "failed_copy_files.txt";	# textfile with failed copied files 
my $StartExecTime		= time();
my $EndExecTime			= 0;

use constant DEBUG		=> 1;	# 2 or 1 or 0


unless ( defined($SourceFolder) && defined($DestFolder) ) {
	
	print "Usage: perl $0 SourceFolder Destination \n";
	print "Usage: Or do define \$SourceFolder and \$DestFolder on top of File $0!\n";
	exit(0);

}; # unless ( 

# prepare DestinationFolder Structure
# find(\&DestStructure, $DestFolder);

# keeps count of overall files in dest folder -before any copying-
# my $DestFileCount		= keys(%{$DestFileStructure});	

# prepare files from SourceFolder
find(\&SourceStructure, $SourceFolder);

my $FailedFileCount = keys(%{$ErrorFileStructure});	
$EndExecTime		= time();

if ( $FailedFileCount > 0 ) {

	open(LOG,">$FailedCopyFile");
	LOG->autoflush(1);
	while( my ($file,$type) = each(%{$ErrorFileStructure}) ){
		print LOG "[$type] Failed to copy Source File $FailedCopyFile\n";
	}; # while( my ($file,$type) = each(%{$ErrorFileStructure}) ){
	close LOG;

	$CopyErrorMessage = "Failed to copy $FailedFileCount - dumped failed copy list to $FailedCopyFile";

}; # if ( $FailedFileCount > 0 ) {


if ( DEBUG >= 1 ) {

	print "Copy assignment from source $SourceFolder to destination $DestFolder\n";	
	print "Started		@ ".MySQLDateTime($StartExecTime)." o'clock\n";
	print "Ended		@ ".MySQLDateTime($EndExecTime)." o'clock\n";
	print "Working Time @ ".sprintf("%.0f", ( ( $EndExecTime - $StartExecTime ) / 60 ) )." minutes\n";
	print "Copied Files @ $CopiedFileCount Files/Dirs from approximatly $SourceFileCount Files\n";
	print "$CopyErrorMessage\n\a"; # incl alarm
	sleep 200;
	exit(0);

}; # if ( DEBUG >= 1 ) {



sub SourceStructure(){

    # $_ is set to the current file name
    # $File::Find::dir is set to the current directory
    # $File::Find::name is set to "$File::Find::dir/$_"
    # you are chdir()'d to $File::Find::dir 

	my $SourceFilename		= $File::Find::name;
	# my $SourceFirname		= $File::Find::dir;
	
	next if ( $SourceFilename eq $SourceFolder );	# ignore $SourceFolder

	$SourceFileCount++;

	my (undef,$tmpfilename)	= split(':', $SourceFilename);
	my $DestFilename		= $Destination.$tmpfilename;
		

	if ( -e $DestFilename ) {
		
		print "DEBUG: $DestFilename alread exists on device\n" if ( DEBUG > 1 );

		if ( -f $SourceFilename ) {	# is_file
		
			my $LastModifyTimeSource	= (stat($SourceFilename))[9];
			my $LastModifyTimeDest		= (stat($DestFilename))[9];

			my $TimeDiff				= $LastModifyTimeSource - $LastModifyTimeDest;
			my $TimeDiffMin				= sprintf("%.0f", $TimeDiff / 60 );	
			my $TimeDiffHour			= sprintf("%.0f", $TimeDiff / ( 60 * 60 ));	
			my $TimeDiffDays			= sprintf("%.0f", $TimeDiff / ( 60 * 60 * 24) );	

			# $FileSizeSource			= (stat($SourceFilename))[7];
		

			if ( $LastModifyTimeSource > $LastModifyTimeDest ) {
			
				$CopiedFileCount++;
				# print "[$CopiedFileCount/$DestFileCount] - Modified at ".MySQLDateTime($LastModifyTimeSource)." for File '$SourceFilename' \n";
				# print "[$CopiedFileCount/$DestFileCount] - Modified before $TimeDiffMin min |$TimeDiffHour h| $TimeDiffDays d for File '$SourceFilename' \n";
				print "[$CopiedFileCount] - Modified before $TimeDiffHour hours | $TimeDiffMin minutes for File '$SourceFilename' \n"  if ( DEBUG == 1 );

				eval { copy($SourceFilename, $DestFilename) };
				if ($@) {
					
					$ErrorFileStructure->{$DestFilename} = 'FILE';
					print "Couldn't copy $SourceFilename TO $DestFilename: $@\n" if ( DEBUG > 1 );
								
				}; # if ($@) {

			}; # if ( $LastModifyTimeSource > $LastModifyTimeDest ) {


		}; # if ( -f $SourceFilename ) {	# is_file

		### is_dir -> it exists we dont need to do something

	} else {
	
		print "DEBUG: $DestFilename must be created on device\n" if ( DEBUG > 1 );

		if ( -f $SourceFilename ) {	# is_file
		
			print "[$CopiedFileCount] - First Time Copy for '$SourceFilename' \n" if ( DEBUG == 1 );
			eval { copy($SourceFilename, $DestFilename) };
		
			if ($@) {
				
				$ErrorFileStructure->{$DestFilename}  = 'FILE';
				print "Couldn't copy $SourceFilename TO $DestFilename: $@\n" if ( DEBUG > 1 );
		
			}; # if ($@) {
			
			$CopiedFileCount++;

		} elsif ( -d $SourceFilename ) {	# is_dir
		
			print "[$CopiedFileCount] - First Time Dir-Create for '$SourceFilename' \n" if ( DEBUG == 1 );
			eval { mkpath($DestFilename) };		# File::Path

			if ($@) {
				
				$ErrorFileStructure->{$DestFilename} = 'DIR';
				print "Couldn't create $DestFilename: $@\n" if ( DEBUG > 1 );
		
			}; # if ($@) {
			
			$CopiedFileCount++;

		}; # if ( -f $SourceFilename ) {

	}; # if ( exists($DestFileStructure->{$DestFilename}) ) {

}; # sub SourceStructure(){


#sub DestStructure(){
#
#	my $DestFilename = $File::Find::name;
#	$DestFileStructure->{$DestFilename} = 0;
#
#}; # sub DestStructure(){


sub MySQLDateTime(){

	my $timestamp = shift;

	my ( $sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst ) = localtime($timestamp);
	$year	+= 1900;
	$mon	+= 1;

	if ( length($mon) == 1 ) {
		$mon = "0". $mon;
	};
	if ( length($mday) == 1 ) {
		$mday = "0". $mday;
	};
	if ( length($sec) == 1 ) {
		$sec = "0". $sec;
	};
	if ( length($min) == 1 ) {
		$min = "0". $min;
	};
	if ( length($hour) == 1 ) {
		$hour = "0". $hour;
	};
	   
	return $year ."-". $mon ."-". $mday .' '. $hour .':'. $min .':'. $sec;
	
}; # sub MySQLDateTime() {}



