#!/usr/bin/perl
use feature "switch";
use Switch;
use strict;
use warnings;
use perunServicesInit;
use perunServicesUtils;
no if $] >= 5.017011, warnings => 'experimental::smartmatch';

local $::SERVICE_NAME = "ad_admin_group_mu_ucn";
local $::PROTOCOL_VERSION = "3.0.0";
my $SCRIPT_VERSION = "3.0.1";

sub addMemberToGroup;
sub processWorkplaces;
sub processGroup;
sub createGroup;
sub processTree;
sub writeDebug;

perunServicesInit::init;
my $DIRECTORY = perunServicesInit::getDirectory;
my $fileName = "$DIRECTORY/$::SERVICE_NAME".".ldif";

#Get hierarchical data without expired members
my $data = perunServicesInit::getHashedDataWithGroups;
my $DEBUG = 0;

#Constants
our $A_LOGIN; *A_LOGIN = \'urn:perun:user:attribute-def:def:login-namespace:mu-adm';
our $A_R_GROUP_NAME;  *A_R_GROUP_NAME = \'urn:perun:resource:attribute-def:def:adGroupName';
our $A_MR_V_IS_BANNED;  *A_MR_V_IS_BANNED = \'urn:perun:member_resource:attribute-def:virt:isBanned';
our $A_R_DESCRIPTION; *A_R_DESCRIPTION = \'urn:perun:resource:attribute-def:core:description';

# Default description of group in Active Directory
my $defaultDescription = "no-desc in Perun";
# OUs for groups and users
my $adOuNameGroups = "OU=PrivilegedGroups,OU=MU,DC=ucn,DC=muni,DC=cz";
my $adOuNameUsers = "OU=PrivilegedUsers,OU=MU,DC=ucn,DC=muni,DC=cz";

our $groups = {};
our $usersByGroups = {};

# FOR EACH RESOURCE
foreach my $resourceId ($data->getResourceIds()) {
	processGroup($resourceId);
}

#
# Print group data LDIF
#
open FILE,">:encoding(UTF-8)","$fileName" or die "Cannot open $fileName: $! \n";

for my $group (sort keys %$groups) {

	print FILE "dn: CN=" . $group . "," . $adOuNameGroups . "\n";
	print FILE "cn: " . $group . "\n";
	print FILE "samAccountName: " . $group . "\n";
	print FILE "description: " . $groups->{$group}->{"description"} . "\n";
	print FILE "objectClass: group\n";
	print FILE "objectClass: top\n";

	my @groupMembers = sort keys %{$usersByGroups->{$group}};
	for my $member (@groupMembers) {
		print FILE "member: " . $member . "\n";
	}

	# there must be empty line after each entry
	print FILE "\n";

}

close FILE;

perunServicesInit::finalize;

####################
# Helper functions #
####################

sub addMemberToGroup {
	my $memberId = shift;
	my $group = shift;
	my $resourceId = shift;

	my $login = $data->getUserAttributeValue( member => $memberId, attrName => $A_LOGIN );
	my $isBanned = $data->getMemberResourceAttributeValue( member => $memberId, resource => $resourceId, attrName => $A_MR_V_IS_BANNED );

	addMember($login, $group, $isBanned)
}

sub processGroup {
	my $resourceId = shift;

	my $group = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_GROUP_NAME );
	my $description = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_DESCRIPTION );

	writeDebug("Process Standard Group: '$group'", 1);
	createGroup($group, $description);

	writeDebug("Continue to add members", 3);
	foreach my $memberId ($data->getMemberIdsForResource( resource => $resourceId )) {
		addMemberToGroup($memberId, $group, $resourceId);
	}
}

sub createGroup {
	my $name = shift;
	my $description = shift;

	# Ensure that there is one group with specific name
	$groups->{$name}->{"description"} =  $description || $defaultDescription;
	writeDebug("Group created", 3);
}

sub addMember {
	my $login = shift;
	my $group = shift;
	my $isBanned = shift;

	#skip banned members
	return if $isBanned;

	# allow only UČOadm, 9UČOadm logins

	return unless $login;
	if ($login =~ /^9[0-9]{6}adm$/ or $login =~ /^[0-9]{1,6}adm$/) {

		# store UČO and 9UČO users
		$usersByGroups->{$group}->{"CN=" . $login . "," . $adOuNameUsers} = 1

	}
}

sub writeDebug {
	my $message = shift;
	my $indentation = shift;

	return unless $DEBUG;

	print "\t" x $indentation;
	print $message . "\n";
}
