#!/usr/local/bin/perl
#
#Does monthly or quarterly reset of auto-replenishing accounts

use strict;
use warnings;
use lib '/cell_root/software/HPCC/lib/site_perl';
#For testing, use RW replica
#use lib '/afs/.glue.umd.edu/software/HPCC/1.1/lib/site_perl';

use Glue::HPCC::Cluster;
use Glue::HPCC::ClusterUtil;
use Glue::HPCC::Project::Project;
use Glue::HPCC::Project::Person;
use Glue::HPCC::Project::ProjectType;
use Glue::HPCC::Utils::MailUtils qw(send_template_email);

use Getopt::Long;
use Time::ParseDate;

#These users will get emails of resets for ALL accounts
#my @email_all = qw( floprest payerle kevin jtl);
my @email_all = qw( payerle kevin jtl);

my $mailutil = 'Glue::HPCC::Utils::MailUtils';
my %templates =
(	monthly => "hpcc_monthly_replenishment.tmplate",
	quarterly => "hpcc_quarterly_replenishment.tmplate",
	prorate => "hpcc_prorated_replenishment.tmplate",
);

sub usage()
{	print STDERR <<EOF;
$0: Does monthly/quarterly reset of auto-replenishing accounts

Usage:
$0 [ -cluster CLUSTER ] -mode MODE [ -date DATE ] \
	[ -project PROJNAME ]  [ -reason REASON ]  \
	[ -dryrun ] [ -verbose ] [ -[no]email ] 

Autoreplenishes accounts.  If PROJNAME specified, it will auto-replenish
any accounts for PROJNAME in CLUSTER which have autoreplenishing enabled.
If PROJNAME is not specified, all accounts in cluster CLUSTER with 
autoreplenishing enabled will be replenished.

CLUSTER will be defaulted from the host running on.  REASON defaults to
'monthly autoreplenish' or 'quarterly autoreplenish' for monthly or 
quarterly modes, and is required for prorate mode.

MODE must be one of quarterly, monthly, or prorate
Currently only can replenish 'coop' type accounts:
Quarterly:	normal priority limit set to 2/3 after tax allocation amount
		high priority limit set to 1/3  after tax allocation amount
		usage on both set to 0
Monthly: 	Normal priority limit reduced by high priority limit, if can be.
		High priority usage is zeroed.  If we were unable to reduce
		normal priority limit be the full amount, reduce high-priority
		limit by the amount that was left over.
Prorate:	if DATE (defaults to now) is in the first month of the quarter,
		normal priority limit set to 2/3 of base after tax amount.  If
		in the second month, 1/3, and 0 in final month.  The high
		priority amount is 1/3 the base amount times the fraction of
		the month remaining.
DATE is only relevant with MODE=prorate, and is date to prorate relative to.
Default is current time.

Unless -nomail is set, the Points of Contact for the project will receive
email informing then of the replenishment.

EOF
}

#------------------------------------------------------
#		Main
#------------------------------------------------------

my ($help, $dryrun, $verbose);
my ($cluster, $project, $mode, $reason, $date);
my $do_email=1;
my $tmp;

my $res = GetOptions(
	'help!' => \$help,
	'dryrun!' => \$dryrun,
	'verbose!' => \$verbose,
	'email|mail!' => \$do_email,

	'mode=s' => \$mode,
	'cluster=s' => \$cluster,
	'project=s' => \$project,
	'reason=s' => \$reason,
	'date=s' => \$date,
);

unless ( $res )
{	usage;
	die "\nError processing arguments\n";
}

if ( $help )
{	usage;
	exit 0;
}

if (scalar(@ARGV) )
{	usage;
	$tmp = join ', ', @ARGV;
	die "\nUnrecognized arguments: [ $tmp ], aborting\n";
}

#Default cluster if needed
my $hpc = Glue::HPCC::Cluster->new_from_clustername($cluster);
die "\nInvalid cluster $cluster at " if $cluster && ! $hpc && ! ref($hpc);
die "\nError instantiating cluster $hpc " unless $hpc && ref($hpc);
$cluster = $hpc->db_clustername;
my $full_clustername = $hpc->clustername;

$hpc->verbose($verbose);
$hpc->dryrun($dryrun);
Glue::HPCC::Utils::MailUtils::verbose($verbose);
Glue::HPCC::Utils::MailUtils::dryrun($dryrun);

unless ( $mode )
{	usage;
	die "\nMissing required argument 'mode'\n";
}
$mode = lc $mode;
$mode = 'quarterly' if $mode eq 'q' || $mode eq 'quarter';
$mode = 'monthly' if $mode eq 'm' || $mode eq 'month';
$mode = 'prorate' if $mode eq 'p' || $mode eq 'prorated';
unless ( $mode eq 'quarterly' || $mode eq 'monthly' || $mode eq 'prorate' )
{	usage;
	die "\nInvalid mode '$mode', expecting one of [ quarterly, monthly, prorate ]\n";
}
my $template_file = $templates{$mode};
unless ( $template_file )
{	usage;
	die "\nInvalid mode '$mode', no template found.\n";
}

unless ( $reason )
{	if ( $mode eq 'prorate' )
	{	usage;
		die "\nReason is required for mode prorate\n";
	}
	$reason = "$mode autoreplenishment";
}

my $tstamp;
if ( $date )
{	unless ( $mode eq 'prorate' )
	{	usage;
		die "\nParameter -date only allowed for mode prorate\n";
	}
	$tstamp = parsedate($date, FUZZY=>0, WHOLE=>1, VALIDATE=>1);
	unless ( defined $tstamp )
	{	usage;
		die "\nInvalid value '$date' for date\n";
	}
}

my $hpcUtil = $hpc->get_hpcUtil;
my $userUtil = $hpcUtil->user;
my $projUtil = $hpcUtil->project;

my $projects = [ $project ];
unless ( $project )
{	if ( $mode eq 'prorate' )
	{	usage;
		die "\nYou must specify a project with mode=prorate.\n";
	}

	$projects = $projUtil->get_autoreplenish_projects(hpc=>$hpc);
}
	
my %msgs_by_user = ();
my $user;

PROJECT: foreach my $project (sort @$projects)
{	print STDERR "Autoreplenishing project $project in $cluster ...\n";
	my $pocs = Glue::HPCC::Project::PersonProject->get_pocs_for_project(
		$hpc, $project);
	my ($err, $msgs, $ptname,  $usage1, $usage2) = 
		$projUtil->autoreplenish_project(
			hpc => $hpc,
			project => $project,
			mode => $mode,
			tstamp => $tstamp,
			reason => $reason,
		);
	#Commit after each project
	$hpc->db_commit;
	if ( $err )
	{	warn "Error autoreplenishing project $project: $err\n";
		my $txt = join "\n", @$msgs;
		warn "$txt\n";
		#next PROJECT;
	}
	#print STDERR "err=$err\nmsgs=\n", (join "\n", @$msgs), "\n\n";

	my @users = (@email_all, @$pocs);
	@users = @email_all if $err; #Don't send errors to real PoCs
	#Remove duplicates
	my %temp = map { $_ => undef } @users;
	@users = keys %temp;

	foreach $user (@users)
	{	$tmp = $msgs_by_user{$user};
		unless ( $tmp && ref($tmp) eq 'ARRAY' )
		{	$tmp = $msgs_by_user{$user} = [];
		}
		push @$tmp, { 
			project => $project, 
			messages => $msgs, 
			ptname => $ptname, 
			usage1 => $usage1, 
			usage2 => $usage2 
		};
	}
}

exit unless $do_email;

#Send emails to all the PoCs
my ($full, $email);
USER: foreach $user (keys %msgs_by_user)
{	my $msgs = $msgs_by_user{$user};
	my $userobj = Glue::HPCC::Project::Person->person_by_username(
			$hpc, $user);
	if ( $userobj )
	{	if ( ref($userobj) )
		{	$full = $userobj->fullname;
			$email = $userobj->email;
		} else
		{	warn "Error looking up PoC $user: $userobj at";
			next USER;
		}
	} else
	{	#Handle if not in PDB, mainly for @email_all people
		$full = $user;
		$email = "${user}\@umd.edu";
	}

	my $macros = {
		EMAIL => $email,
		FULLNAME => $full,
		CLUSTER => $full_clustername,
		MSGLIST => $msgs,
	};

	send_template_email($template_file, $macros);
}

