#!/usr/bin/perl

use strict;
use warnings;
use perunServicesInit;
use perunServicesUtils;

#Forward Declaration
sub processResourceData;
sub processGroupData;
sub processMemberData;

our $SERVICE_NAME     = "samba_du";
our $PROTOCOL_VERSION = "3.0.0";
my $SCRIPT_VERSION = "3.0.1";

perunServicesInit::init;
my $DIRECTORY = perunServicesInit::getDirectory;
my $data      = perunServicesInit::getHashedDataWithGroups;

#Constants
our $A_RESOURCE_UNIX_GROUP_NAME;   *A_RESOURCE_UNIX_GROUP_NAME =  \'urn:perun:resource:attribute-def:virt:unixGroupName';
our $A_RESOURCE_UNIX_GID;          *A_RESOURCE_UNIX_GID =         \'urn:perun:resource:attribute-def:virt:unixGID';
our $A_GROUP_UNIX_GROUP_NAME;      *A_GROUP_UNIX_GROUP_NAME =     \'urn:perun:group_resource:attribute-def:virt:unixGroupName';
our $A_GROUP_UNIX_GID;             *A_GROUP_UNIX_GID =            \'urn:perun:group_resource:attribute-def:virt:unixGID';
our $A_MEMBER_LOGIN;               *A_MEMBER_LOGIN =              \'urn:perun:user_facility:attribute-def:virt:login';
our $A_MEMBER_ID;                  *A_MEMBER_ID =                 \'urn:perun:user_facility:attribute-def:virt:UID';

#Global data structure
our $STRUC_UID;      *STRUC_UID = \0;
our $STRUC_GROUPS;   *STRUC_GROUPS = \1;
our $memberStruc = {};

foreach my $resourceId ($data->getResourceIds()) {
	processResourceData $resourceId;

	foreach my $groupId ( $data->getGroupIdsForResource( resource => $resourceId ) ) {
		processGroupData $groupId, $resourceId;
	}
}

my $fileName = "$DIRECTORY/$::SERVICE_NAME";
open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";

foreach my $login (sort keys %$memberStruc) {
	print FILE $login, " ", $memberStruc->{$login}->{$STRUC_UID}, " ", join(',', map { $_ . ":" . $memberStruc->{$login}->{$STRUC_GROUPS}->{$_} } sort keys %{$memberStruc->{$login}->{$STRUC_GROUPS}}), "\n";
}

close(FILE) or die "Cannot close $fileName: $! \n";
perunServicesInit::finalize;

##############################################################################
#   Only subs definitions down there
##############################################################################

# INPUT: group's name, group's ID, member's id
# stores user's login and user's ID into $memberStruc structure
# assigns group's name and group's ID to the member in $memberStruc structure
sub processMemberData {
	my $groupName = shift;
	my $gid = shift;
	my $memberId = shift;

	my $login = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_MEMBER_LOGIN );
	my $uid = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_MEMBER_ID );

	unless(exists $memberStruc->{$login}) {
		$memberStruc->{$login} = {};
		$memberStruc->{$login}->{$STRUC_UID} = $uid;
	} else {
		if($memberStruc->{$login}->{$STRUC_UID} != $uid) {
		die "Consistency error! Two different members have the same user name. Name=" . $login;
		}
	}

	unless(exists $memberStruc->{$login}->{$STRUC_GROUPS}->{$groupName}) {
		$memberStruc->{$login}->{$STRUC_GROUPS}->{$groupName} = $gid;
	} else {
		if($memberStruc->{$login}->{$STRUC_GROUPS}->{$groupName} != $gid) {
			die "Two resources or groups with the same name and different GIDs. Name=" . $groupName . " GID=" . $memberStruc->{$login}->{$STRUC_GROUPS}->{$groupName} . ", " . $gid;
		}
	}
}

# INPUT: resource id
# calls processMemberData to assign RESOURCE_UNIX_GROUP to the member in $memberStruc structure
sub processResourceData {
	my $resourceId = shift;

	my $resourceUnixGroupName = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_RESOURCE_UNIX_GROUP_NAME );
	my $resourceUnixGID = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_RESOURCE_UNIX_GID );

	if (defined $resourceUnixGroupName) {
		foreach my $memberId ($data->getMemberIdsForResource(resource => $resourceId)) {
			processMemberData $resourceUnixGroupName, $resourceUnixGID, $memberId;
		}
	}
}

# INPUT: group id, resource id
# calls processMemberData to assign GROUP_UNIX_GROUP to the member in $memberStruc structure
sub processGroupData {
	my $groupId = shift;
	my $resourceId = shift;

	my $unixGroupName = $data->getGroupResourceAttributeValue( group => $groupId, resource => $resourceId, attrName => $A_GROUP_UNIX_GROUP_NAME);
	if(defined $unixGroupName) {
		my $gid = $data->getGroupResourceAttributeValue( group => $groupId, resource => $resourceId, attrName => $A_GROUP_UNIX_GID );

		foreach my $memberId ($data->getMemberIdsForResourceAndGroup( group => $groupId, resource => $resourceId )) {
			processMemberData $unixGroupName, $gid, $memberId;
		}
	}
}
