#!/usr/bin/perl
use strict;
use warnings;
use perunServicesInit;
use perunServicesUtils;
use Time::Piece;

sub calculateExpiration;

local $::SERVICE_NAME = "vsup_rav";
local $::PROTOCOL_VERSION = "3.0.0";
my $SCRIPT_VERSION = "3.0.2";

perunServicesInit::init;
my $DIRECTORY = perunServicesInit::getDirectory;
my $fileName = "$DIRECTORY/$::SERVICE_NAME".".csv";
my $data = perunServicesInit::getHashedHierarchicalData;

#Constants
our $A_LOGIN; *A_LOGIN = \'urn:perun:user_facility:attribute-def:virt:login';
our $A_UCO; *A_UCO= \'urn:perun:user:attribute-def:def:ucoVsup';
our $A_TITLE_BEFORE;  *A_TITLE_BEFORE = \'urn:perun:user:attribute-def:core:titleBefore';
our $A_FIRST_NAME;  *A_FIRST_NAME = \'urn:perun:user:attribute-def:core:firstName';
our $A_LAST_NAME;  *A_LAST_NAME = \'urn:perun:user:attribute-def:core:lastName';
our $A_ARTISTIC_FIRST_NAME; *A_ARTISTIC_FIRST_NAME = \'urn:perun:user:attribute-def:def:artisticFirstName';
our $A_ARTISTIC_LAST_NAME; *A_ARTISTIC_LAST_NAME = \'urn:perun:user:attribute-def:def:artisticLastName';
our $A_TITLE_AFTER;  *A_TITLE_AFTER = \'urn:perun:user:attribute-def:core:titleAfter';
our $A_PHONE;  *A_PHONE = \'urn:perun:user:attribute-def:virt:preferredPhone';
our $A_CARD_BARCODES;  *A_CARD_BARCODES = \'urn:perun:user:attribute-def:def:cardBarCodes';
our $A_CARD_CHIP_NUMBERS;  *A_CARD_CHIP_NUMBERS = \'urn:perun:user:attribute-def:def:cardCodes';
our $A_VSUP_MAIL; *A_VSUP_MAIL= \'urn:perun:user:attribute-def:def:vsupMail';
our $A_VSUP_PREF_MAIL; *A_VSUP_PREF_MAIL= \'urn:perun:user:attribute-def:def:vsupPreferredMail';
our $A_EXPIRATION_KOS;  *A_EXPIRATION_KOS = \'urn:perun:user:attribute-def:def:expirationKos';
our $A_EXPIRATION_DC2;  *A_EXPIRATION_DC2 = \'urn:perun:user:attribute-def:def:expirationDc2';
our $A_EXPIRATION_MANUAL;  *A_EXPIRATION_MANUAL = \'urn:perun:user:attribute-def:def:expirationManual';

# GATHER USERS
my $users;  # $users->{$uco}->{ATTR} = $attrValue;

#
# AGGREGATE DATA
#
# FOR EACH USER
foreach my $memberId ($data->getMemberIdsForFacility()) {

	my $uco  = $data->getUserAttributeValue( member => $memberId, attrName => $A_UCO);
	my $login  = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_LOGIN);
	my $prefMail = $data->getUserAttributeValue(member => $memberId, attrName => $A_VSUP_PREF_MAIL);
	my $vsupMail = $data->getUserAttributeValue(member => $memberId, attrName => $A_VSUP_MAIL);
	my $titleBefore = $data->getUserAttributeValue(member => $memberId, attrName => $A_TITLE_BEFORE);
	my $artisticFirstName = $data->getUserAttributeValue(member => $memberId, attrName => $A_ARTISTIC_FIRST_NAME);
	my $firstName = $data->getUserAttributeValue(member => $memberId, attrName => $A_FIRST_NAME);
	my $artisticLastName = $data->getUserAttributeValue(member => $memberId, attrName => $A_ARTISTIC_LAST_NAME);
	my $lastName = $data->getUserAttributeValue(member => $memberId, attrName => $A_LAST_NAME);
	my $titleAfter = $data->getUserAttributeValue(member => $memberId, attrName => $A_TITLE_AFTER);
	my $phone = $data->getUserAttributeValue(member => $memberId, attrName => $A_PHONE);
	my $cardBarCodes = $data->getUserAttributeValue(member => $memberId, attrName => $A_CARD_BARCODES);
	my $cardChipNumbers = $data->getUserAttributeValue(member => $memberId, attrName => $A_CARD_CHIP_NUMBERS);
	my $expirationKOS = $data->getUserAttributeValue(member => $memberId, attrName => $A_EXPIRATION_KOS);
	my $expirationDC2 = $data->getUserAttributeValue(member => $memberId, attrName => $A_EXPIRATION_DC2);
	my $expirationManual = $data->getUserAttributeValue(member => $memberId, attrName => $A_EXPIRATION_MANUAL);

	$users->{$uco}->{$A_LOGIN} = $login;
	$users->{$uco}->{$A_VSUP_MAIL} = ($prefMail || ($vsupMail || $login . '@vsup.cz'));
	$users->{$uco}->{$A_TITLE_BEFORE} = $titleBefore || '';
	$users->{$uco}->{$A_FIRST_NAME} = ($artisticFirstName || ($firstName || ''));
	$users->{$uco}->{$A_LAST_NAME} = ($artisticLastName || ($lastName || ''));
	$users->{$uco}->{$A_TITLE_AFTER} = $titleAfter || '';
	$users->{$uco}->{$A_PHONE} = $phone || '';

	# if multiple, send only first one
	if (defined $cardBarCodes) {
		$users->{$uco}->{$A_CARD_BARCODES} = $cardBarCodes->[0];
	} else {
		$users->{$uco}->{$A_CARD_BARCODES} = '';
	}
	if (defined $cardChipNumbers) {
		$users->{$uco}->{$A_CARD_CHIP_NUMBERS} = $cardChipNumbers->[0];
	} else {
		$users->{$uco}->{$A_CARD_CHIP_NUMBERS} = '';
	}

	# calculate expiration
	$users->{$uco}->{"EXPIRATION"} = calculateExpiration($expirationKOS, $expirationDC2, $expirationManual) || '';

}

#
# PRINT user data LDIF
#
open FILE,">$fileName" or die "Cannot open $fileName: $! \n";
binmode FILE, ":utf8";

# FOR EACH USER ON FACILITY
my @keys = sort keys %{$users};
for my $uco (@keys) {

	# print attributes, which are never empty
	print FILE $uco . "\t" . $users->{$uco}->{$A_LOGIN} . "\t" . $users->{$uco}->{$A_VSUP_MAIL} . "\t" . $users->{$uco}->{$A_FIRST_NAME}
			. "\t" . $users->{$uco}->{$A_LAST_NAME} . "\t" . $users->{$uco}->{$A_TITLE_BEFORE} . "\t" . $users->{$uco}->{$A_TITLE_AFTER}
			. "\t" . $users->{$uco}->{$A_PHONE} . "\t" . $users->{$uco}->{$A_CARD_BARCODES} . "\t" . $users->{$uco}->{$A_CARD_CHIP_NUMBERS}
			. "\t" . $users->{$uco}->{"EXPIRATION"} . "\n";
}

close(FILE);

perunServicesInit::finalize;

#
# Calculate later from three expiration dates on VŠUP.
#
# 1. param - expiration in KOS (studies)
# 2. param - expiration in DC2 (employees)
# 3. param - manually set expiration
#
# - in case of expiration on 1.1.4000 -> undef is returned as "expiration = never".
# - in case of any other exact date, pick the largest (future).
#
sub calculateExpiration() {

	# read input
	my $expirationKos = shift;
	my $expirationDc2 = shift;
	my $expirationMan = shift;
	# parse to time or undef
	my $expirationKosTime = ($expirationKos) ? Time::Piece->strptime($expirationKos,"%Y-%m-%d") : undef;
	my $expirationDc2Time = ($expirationDc2) ? Time::Piece->strptime($expirationDc2,"%Y-%m-%d") : undef;
	my $expirationManTime = ($expirationMan) ? Time::Piece->strptime($expirationMan,"%Y-%m-%d") : undef;

	my @expirations = ();
	if (defined $expirationKosTime) { push(@expirations, $expirationKosTime->epoch); }
	if (defined $expirationDc2Time) { push(@expirations, $expirationDc2Time->epoch); }
	if (defined $expirationManTime) { push(@expirations, $expirationManTime->epoch); }

	# sort all expirations
	my @sorted_expirations = sort { $a <=> $b } @expirations;
	my $latest_expiration = $sorted_expirations[$#sorted_expirations];

	if (!defined $expirationKos and !defined $expirationDc2 and !defined $expirationMan) {
		# if no expiration set in source data - take as "never"
		return undef;
	}

	# case expiration "never" = 1.1.4000
	if ($latest_expiration == Time::Piece->strptime("4000-01-01","%Y-%m-%d")->epoch) {
		# return without specified expiration date
		return undef;
	}

	# add one day, since we want users to be valid during the last day
	$latest_expiration = $latest_expiration + 86400;

	return localtime($latest_expiration)->ymd;

}
