#!/usr/bin/perl
$ENV{LC_ALL} = "$ENV{LC_LANG}";

$USAGE =<< "EOM";
**I: smart-copy-ingest script
    -f <dir> Smart copy from folder
    -m <dir> Read config file with md5sum
    -t <time inseconds> Last Modified interval from current time
    -d <dest project root> Destination Zoom project root to save under
EOM

# Constants to change:
$SRC_DIR="/home/evolphin/Hot Folder";
$MD5_CFG="/home/evolphin/zoom-deploy/scripts/smart-copy-ingest";
$ZOOM_SRV= "http://zoomo:8880";
$ZOOM_HOME = "/Applications/Evolphin/zoom/Resources/";
$ZOOM_USER="hotfolderuser";
$ZOOM_PASSWD="hotfolderuser";
$lastModThreshold = "30"; #e.g.untouched in 60s, set to 60
$ZOOM_PROJ= "/defproj";
$BULK_MD = "/Users/rahul/zoom-deploy/import-metadata/hf-vprecords.properties";
$PATH2FUID_URL="http://zoomo:8443/util.jsp?op=getfuid&path=";
$WF_TMPL_ID="30"; # Lookup using zm getworkflows  -p VPRecords -t

# ZM cmd line
$ZM = "$ZOOM_HOME/bin/zm --thisCommandOnly -s $ZOOM_SRV --username \"$ZOOM_USER\" --password \"$ZOOM_PASSWD\"";

# Don't change below
open(OF, "> $ENV{HOME}/.zm/logs/smart-copy.log")  or die "F: failed to open logger: $!\n";

use File::Find;

usage() if (!@ARGV);

while(@ARGV) {
    $arg = shift @ARGV;
    usage(1) if $arg =~ /-h/;

    if ($arg =~ /-d/) {
	$ZOOM_PROJDIR =  shift @ARGV;
    } 

    if ($arg =~ /-f/) {
	$SRC_DIR =  shift @ARGV;
	usage() if !-e $SRC_DIR;
    } 
    if ($arg =~ /-m/) {
	$MD5_CFG  =  shift @ARGV;
	my $md = dirname($MD5_CFG);
	usage() if !-e $md;
    } 
    if ($arg =~ /-t/) {
	$lastModThreshold =  shift @ARGV;
	usage() if !$lastModThreshold || !$lastModThreshold =~ /^\d+$/;
	plog("Untouched threshold is ".$lastModThreshold."s\n");
    }
}

@matchedFiles = ();

plog("START Smarty Copy Ingest..\n");

# --- Read existing md5sums
%MD5 = ();
readMD5List();

use Digest::MD5;

searchFiles(\&wanted, $SRC_DIR);

$cnt = @matchedFiles;

plog("$cnt files found for import\n");

chdir $SRC_DIR;

$nIM=0; $nSC=0;

foreach (@matchedFiles) {
    plog("Processing: $_\n");

    $md5 = computeMD5("$SRC_DIR/$_");
    if (! $md5) {
	plog("Skipping $_, no md5sum computed\n");
	next;
    }
    $srcPath = "$ZOOM_PROJDIR/".fwdSlash($_);

    $existingFile = $MD5{$md5};

    if (! $existingFile) {
	$rv = zm("import -m \"Importing file\" -bmd \"$BULK_MD\"  \"$_\" -d \"$ZOOM_PROJDIR\"");
	$nIM++;
	plog("MD5 $md5: $srcPath\n");
	$MD5{$md5} = $srcPath;       
    } else {
	plog("Duplicated file: $existingFile found. Making a smart copy\n");
	# Create smart copies instead of importing
	mkZoomDir($_);
	$rv = zm("fork -m smartcopy -bmd \"$BULK_MD\" \"$existingFile\" \"$srcPath\"");
	$nSC++;
    }
    if ($rv) {
	push @ingestedFiles, $srcPath;
    }
}

 # saving the changes back to file:
plog("Saving md5 configs\n");
writeMD5List();

$nIngested = @ingestedFiles;

plog("Ingestion attempted: $nIM/$cnt imports; $nSC/$cnt smart-copies; ingested: $nIngested \n");

plog("Converting paths to FUIDs..\n");
foreach (@ingestedFiles) {
    $fuid = getFuid($_);
    next if !$fuid;
    push @fuids, $fuid;
}

$nfuids = @fuids;

if ($nfuids <=0) {
    plog("No fuids to kick off a workflow, finishing\n");
    plog("END Smart Copy Script\n");
    exit(0);
}

plog("Kickoff a templated job\n");

$csvFuids = join(',',@fuids);

$rv = zm("createworkflow -c create -s template  --fuids $csvFuids -wp  id=$WF_TMPL_ID");

plog("Succcess: Created workflows with fuids: $csvFuids\n") if $rv;

plog("END Smart Copy Script\n");

close(OF);

exit(0);

#===

use POSIX qw/strftime/;

use Cwd;
use File::Basename;

sub readMD5List {
    if (!-e $MD5_CFG) {
	return;
    } else {
	$rv = open(MC, "< $MD5_CFG");
	if (! $rv) {
	    plog("Failed to read $MD5_CFG: $!\n");
	    exit(1);
	}
	while(<MC>) {
	    next if (m|\s*#|);
	    next if  !(m#\s*(\S+)\s*=\s*"(.+)"\s*#);
	    $MD5{$1} = $2;
	}

	close(MC);
	
    }
}

sub writeMD5List {
    $rv = open(MC, "> $MD5_CFG");
    if (! $rv) {
	plog("Failed to create $MD5_CFG: $!\n");
	exit(1);
    }
    
    print MC "# MD5 Checksum Store\n";
    print MC "# md5sum=val\n\n";

    foreach my $key (keys %MD5) {
	print MC "$key = \"$MD5{$key}\"\n";
    }

    close(MC);	
}


sub mkZoomDir {

    my $cdir = getcwd;

    #Ensure remote destination path exists
    my $ddir = dirname($_);

    #Create an empty dir to add
    plog("mkdir -p \"$ENV{HOME}/tmp/$ddir\"\n");

    $rv = system("mkdir -p \"$ENV{HOME}/tmp/$ddir\"");
    chdir "$ENV{HOME}/tmp";

    zm("import -m \"Add Folder\" \"$ddir\" -d \"$ZOOM_PROJDIR\"");

    rmdir "$ENV{HOME}/tmp/$ddir";

    chdir $cdir;
}

sub zm {
    my $subcmd = $_[0];
    my $cmd = "$ZM $subcmd";

    plog("Executing: $cmd\n");
    
    my $output = `$cmd 2>&1`;
    if ($?!=0) {
	plog($output);
	return 0;
    }
    return 1;    
}

sub computeMD5 {
    my $inf = $_[0];

    $rv = open(FH, "<$inf");
    if (!$rv) {
	plog("computeMD5sum: Failed to open for read: $inf: $!\n");
	return 0;
    }

    my $ctx = Digest::MD5->new;
    $ctx->addfile(FH);
    $digest = $ctx->hexdigest;
    
    close(FH);
    return $digest;
}

sub trim($)  {
  my $string = shift;
  $string =~ s/^\s+//;
  $string =~ s/\s+$//;
  return $string;
}

sub searchFiles {
    my $wanted = $_[0];
    
    #@matchedFiles file names will be relative to inDir
    $inDir =  $_[1];

    find($wanted, ($inDir) );

}

use URI::Escape;

sub getFuid {
    my $inPath = $_[0];
 
    my $encode = uri_escape($inPath);

    my $url = "$PATH2FUID_URL$encode";
    my $response = `curl \"$url\" 2>&1`;
   
#    print "$url -> ".$response."\n";

    $response =~ m|fuid="(.*)"|;
    $outFuid = $1;
    plog($inPath." -> ".$outFuid."\n");
    return $outFuid;
}

sub getPath {
    my $inFuid = basename $_[0];
    my $url = "$fuid2fqpath$inFuid";
#    my $response = get($url); # HTTP GET, if it fails, returns undef
    my $response = `curl \"$url\" 2>&1`;
   
#    print "$url -> ".$response."\n";

    $response =~ m|path="(.*)"|;
    $outPath = $1;
    plog($inFuid." -> ".$outPath."\n");
    return $outPath;
}

sub plog {  
    print OF "[ZM-SC] ".$_[0];
}

use File::Spec;

sub wanted {
    return if (-d); #only interested in files, ignore dirs

    #is this a valid file name?, ignore ~ backup files
    return if (m/~$/ || m/\.DS_Store$/);

    ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)
	= stat($_);
    
    $now = time();

    # Is last modified time older than $lastModThreshold
    return if ($now - $mtime <  $lastModThreshold);

    #candidate for file op
    $fullFile = $File::Find::name;
    
    $relativePath = File::Spec->abs2rel ($fullFile, $inDir);

    push @matchedFiles, $relativePath;

    plog ("Found file to ingest: ".$fullFile."\n");
}


sub usage() {
    my $std = $_[0];
    $std ? print $USAGE : plog ($USAGE);
    exit(2);
}

sub fwdSlash {
    my $f = $_[0];
    $f =~ s#\\#\/#g;
    return $f;
}
