#!/usr/bin/perl

use strict;
use warnings;
use POSIX qw(strftime); 
use File::Path;
use esmith::ConfigDB;
use esmith::AccountsDB;

# Routines taken from powershift of rlbackup
sub stagger;
sub powershift;
sub shadowdir;

my $cdb = esmith::ConfigDB->open_ro;
my $adb = esmith::AccountsDB->open_ro();

my $smb = $cdb->get('smb') or die "No smb db entry found\n";
my $shadowdir = $smb->prop('ShadowDir') || '/home/e-smith/files/.shadow';
my $shadowcopy = $smb->prop('ShadowCopy') || 'disabled';
my $offset = ($smb->prop('ShadowCount') || 2) - 2;
$offset = 0 if $offset < 0;

exit unless -d $shadowdir;
exit if $shadowcopy eq 'disabled';

my $filesdir = '/home/e-smith/files';
my $snapfmt = '@GMT-%Y.%m.%d-%H.%M.%S';

# Create list of ibays and users to shadow
my ($ibays, $users, $link) = ('','','');
my @ibays = grep { ($_->prop('ShadowCopy') || 'enabled') ne 'disabled' } $adb->ibays();
$ibays = "$filesdir/./ibays/{" . join(',', map { $_->key } @ibays) . "}/" if scalar @ibays > 1;
$ibays = "$filesdir/./ibays/" . $ibays[0]->key . "/" if scalar @ibays == 1;
my @users = grep { ($_->prop('ShadowCopy') || 'enabled') ne 'disabled' } $adb->users();
$users = "$filesdir/./users/{" . join(',', map { $_->key } @users) . "}/home/" if scalar @users > 1;
$users = "$filesdir/./users/" . $users[0]->key . "/home/" if scalar @users == 1;
$link = "--link-dest ../1" if -d "$shadowdir/1";

# Sync directories to shadow directory
if ( $ibays || $users) {
    system("rsync -aHmR --partial --exclude '\@GMT-*' $link $ibays $users $shadowdir/0/") == 0
	   or die "Couldn't sync directories";
}

# Shift directories using geometric roll-off (only if different)
if ( -d "$shadowdir/1" ) {
	if (system("diff -qr $shadowdir/0 $shadowdir/1 > /dev/null") == 0) {
		rmtree "$shadowdir/0";
	} else {
		powershift(2) if -d shadowdir(-$offset);
		for (my $i=2; $i >= -$offset; $i--) {
			rename shadowdir($i), shadowdir($i+1) 
		}
	}
} else {
	rename "$shadowdir/0", "$shadowdir/1";
}

opendir(SHADOW, $shadowdir);
my %snaps = map {  my @stat = stat("$shadowdir/$_"); $_ => strftime($snapfmt, gmtime($stat[9])) } 
	    grep { -d "$shadowdir/$_" && ! /^\./ } readdir SHADOW;
closedir(SHADOW);

foreach my $ibay ($adb->ibays()) {
	my $ibaydir = 'ibays/' . $ibay->key . ( $ibay->prop('PublicAccess') eq 'none' ? '/files' : '' );

	opendir(IBAY, "$filesdir/$ibaydir") || next;
	unlink "$filesdir/$ibaydir/$_" foreach (grep /^\@GMT-/, readdir(IBAY));
	closedir(IBAY);

	next if ($ibay->prop('ShadowCopy') || 'enabled') eq 'disabled';

	foreach my $snap (keys %snaps) {
		symlink "$shadowdir/$snap/$ibaydir", "$filesdir/$ibaydir/$snaps{$snap}" if -d "$shadowdir/$snap/$ibaydir";
	}
}

foreach my $user ($adb->users()) {
	my $userdir = 'users/' . $user->key . '/home';

	opendir(USER, "$filesdir/$userdir") || next;
	unlink "$filesdir/$userdir/$_" foreach (grep /^\@GMT-/, readdir(USER));
	closedir(USER);

	next if ($user->prop('ShadowCopy') || 'enabled') eq 'disabled';

	foreach my $snap (keys %snaps) {
		symlink "$shadowdir/$snap/$userdir", "$filesdir/$userdir/$snaps{$snap}" if -d "$shadowdir/$snap/$userdir";
	}
}

sub shadowdir {
	my $i = shift;
	return "$shadowdir/".($i+$offset);
}

sub stagger {
	my $i = shift;
	return $i + ($i >> 1);
}

sub powershift {
	my $i = shift;
	if ( -d shadowdir(stagger($i)) ) {
		my $n = powershift($i << 1);
		$i = $n >> 1;
		rename shadowdir(stagger($i)), shadowdir($n) if -d shadowdir(stagger($i));
		rmtree shadowdir($i) if -d shadowdir($i);
	} else {
		rename shadowdir($i), shadowdir(stagger($i)) if -d shadowdir($i);
	}
	return $i;
}
