#!/usr/bin/perl

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

sub processResourceMember;
sub processGroupMember;
sub processResource;
sub processGroup;
sub processResourceMail;
sub saveResourceMailsToFile;
sub saveFacilityIdToFile;
sub saveUsersToFile;
sub saveGroupsToFile;

our $SERVICE_NAME     = "o365_mu";
our $PROTOCOL_VERSION = "3.1.0";
my $SCRIPT_VERSION = "3.1.1";

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

#-------------------------------------------------------------------------
# CONSTANTS AND DEFINITIONS
#-------------------------------------------------------------------------

our $A_G_AD_NAME;                            *A_G_AD_NAME =                            \'urn:perun:group:attribute-def:def:adName:o365mu';
our $A_F_DOMAIN_NAME;                        *A_F_DOMAIN_NAME =                        \'urn:perun:facility:attribute-def:def:o365DomainName';
our $A_MG_O365_SEND_AS;                      *A_MG_O365_SEND_AS =                      \'urn:perun:member_group:attribute-def:virt:o365SendAs';
our $A_U_O365_MAIL_ADDRS;                    *A_U_O365_MAIL_ADDRS =                    \'urn:perun:user:attribute-def:def:o365EmailAddresses:mu';
our $A_UF_DISABLE_MAIL_FORWARD;              *A_UF_DISABLE_MAIL_FORWARD =              \'urn:perun:user_facility:attribute-def:def:disableO365MailForward';
our $A_UF_LOGIN;                             *A_UF_LOGIN =                             \'urn:perun:user_facility:attribute-def:virt:login';
our $A_UF_O365_MAIL_FORWARD;                 *A_UF_O365_MAIL_FORWARD =                 \'urn:perun:user_facility:attribute-def:def:o365MailForward';
our $A_UF_O365_ARCHIVE;                      *A_UF_O365_ARCHIVE =                      \'urn:perun:user_facility:attribute-def:def:o365MailInPlaceArchive';
our $A_UF_O365_STORE_AND_FORWARD;            *A_UF_O365_STORE_AND_FORWARD =            \'urn:perun:user_facility:attribute-def:def:o365MailStoreAndForward';
our $A_UF_O365_LICENCE;                      *A_UF_O365_LICENCE =                      \'urn:perun:user_facility:attribute-def:def:o365Licence';
our $A_R_IS_FOR_O365_GROUP;                  *A_R_IS_FOR_O365_GROUP =                  \'urn:perun:resource:attribute-def:def:isForO365Group';
our $A_F_ID;                                 *A_F_ID =                                 \'urn:perun:facility:attribute-def:core:id';

our $UPN_TEXT = "UPN";
our $MAIL_FORWARD_TEXT = "mailForward";
our $ARCHIVE_TEXT = "archive";
our $STORE_AND_FORWARD_TEXT = "storeAndForward";
our $EMAIL_ADDRESSES = "emailAddresses";

###------------------------------------------------------------------------------
### RESOURCE MAILBOXES CONFIGURATION
### WARNING: These variables are for purpose of resource mail boxes configuration
###          and we are not using them at this moment! We still want to preserve
###          this for continuing a work on service in the future.
###------------------------------------------------------------------------------
our $A_R_O365_RES_NAME;                      *A_R_O365_RES_NAME =                      \'urn:perun:resource:attribute-def:def:o365ResourceName';
our $A_R_O365_RES_ALIAS;                     *A_R_O365_RES_ALIAS =                     \'urn:perun:resource:attribute-def:def:o365ResourceAlias';
our $A_R_O365_RES_EMAIL_ADDRESES;            *A_R_O365_RES_EMAIL_ADDRESES =            \'urn:perun:resource:attribute-def:def:o365ResourceEmailAddresses';
our $A_R_O365_RES_DISPLAY_NAME;              *A_R_O365_RES_DISPLAY_NAME =              \'urn:perun:resource:attribute-def:def:o365ResourceDisplayName';
our $A_R_O365_RES_TYPE;                      *A_R_O365_RES_TYPE =                      \'urn:perun:resource:attribute-def:def:o365ResourceType';
our $A_R_O365_RES_CAPACITY;                  *A_R_O365_RES_CAPACITY =                  \'urn:perun:resource:attribute-def:def:o365ResourceCapacity';
our $A_R_O365_RES_ADDITIONAL_RESPONSE;       *A_R_O365_RES_ADDITIONAL_RESPONSE =       \'urn:perun:resource:attribute-def:def:o365ResourceAdditionalResponse';
our $A_R_O365_RES_EXT_MEETING_MSG;           *A_R_O365_RES_EXT_MEETING_MSG =           \'urn:perun:resource:attribute-def:def:o365ResourceProcessExternalMeetingMessages';
our $A_R_O365_RES_ALLOW_CONFLICTS;           *A_R_O365_RES_ALLOW_CONFLICTS =           \'urn:perun:resource:attribute-def:def:o365ResourceAllowConflicts';
our $A_R_O365_RES_BOOKING_WINDOW;            *A_R_O365_RES_BOOKING_WINDOW =            \'urn:perun:resource:attribute-def:def:o365ResourceBookingWindowInDays';
our $A_R_O365_RES_PERCENTAGE_ALLOWED;        *A_R_O365_RES_PERCENTAGE_ALLOWED =        \'urn:perun:resource:attribute-def:def:o365ResourceConflictPercentageAllowed';
our $A_R_O365_RES_ENFORCE_SCHED_HORIZON;     *A_R_O365_RES_ENFORCE_SCHED_HORIZON =     \'urn:perun:resource:attribute-def:def:o365ResourceEnforceSchedulingHorizon';
our $A_R_O365_RES_MAX_CONFLICT_INSTANCES;    *A_R_O365_RES_MAX_CONFLICT_INSTANCES =    \'urn:perun:resource:attribute-def:def:o365ResourceMaximumConflictInstances';
our $A_R_O365_RES_MAX_DURATION;              *A_R_O365_RES_MAX_DURATION =              \'urn:perun:resource:attribute-def:def:o365ResourceMaximumDurationInMinutes';
our $A_R_O365_RES_SCHED_DURING_WORK_HOURS;   *A_R_O365_RES_SCHED_DURING_WORK_HOURS =   \'urn:perun:resource:attribute-def:def:o365ResourceScheduleOnlyDuringWorkHours';
our $A_R_O365_RES_ALL_BOOK_IN_POLICY;        *A_R_O365_RES_ALL_BOOK_IN_POLICY =        \'urn:perun:resource:attribute-def:def:o365ResourceAllBookInPolicy';
our $A_R_O365_RES_ALL_REQ_IN_POLICY;         *A_R_O365_RES_ALL_REQ_IN_POLICY =         \'urn:perun:resource:attribute-def:def:o365ResourceAllRequestInPolicy';
our $A_R_O365_RES_ALL_REQ_OUT_OF_POLICY;     *A_R_O365_RES_ALL_REQ_OUT_OF_POLICY =     \'urn:perun:resource:attribute-def:def:o365ResourceAllRequestOutOfPolicy';
our $A_R_O365_RES_WORKDAYS;                  *A_R_O365_RES_WORKDAYS =                  \'urn:perun:resource:attribute-def:def:o365ResourceWorkdays';
our $A_R_O365_RES_WORKING_HOURS_START_TIME;  *A_R_O365_RES_WORKING_HOURS_START_TIME =  \'urn:perun:resource:attribute-def:def:o365ResourceWorkingHoursStartTime';
our $A_R_O365_RES_WORKING_HOURS_END_TIME;    *A_R_O365_RES_WORKING_HOURS_END_TIME =    \'urn:perun:resource:attribute-def:def:o365ResourceWorkingHoursEndTime';
our $A_R_O365_RES_ALLOW_RECURRING_MEETINGS;  *A_R_O365_RES_ALLOW_RECURRING_MEETINGS =  \'urn:perun:resource:attribute-def:def:o365ResourceAllowRecurringMeetings';
our $A_R_O365_RES_ADD_ADDITIONAL_RESPONSE;   *A_R_O365_RES_ADD_ADDITIONAL_RESPONSE =   \'urn:perun:resource:attribute-def:def:o365ResourceAddAdditionalResponse';
our $A_GR_O365_RES_BOOK_IN_POLICY;           *A_GR_O365_RES_BOOK_IN_POLICY =           \'urn:perun:group_resource:attribute-def:def:o365ResourceBookInPolicy';
our $A_GR_O365_RES_REQUEST_IN_POLICY;        *A_GR_O365_RES_REQUEST_IN_POLICY =        \'urn:perun:group_resource:attribute-def:def:o365ResourceRequestInPolicy';
our $A_GR_O365_RES_REQUEST_OUT_OF_POLICY;    *A_GR_O365_RES_REQUEST_OUT_OF_POLICY =    \'urn:perun:group_resource:attribute-def:def:o365ResourceRequestOutOfPolicy';
our $A_GR_O365_RES_DELEGATES;                *A_GR_O365_RES_DELEGATES =                \'urn:perun:group_resource:attribute-def:def:o365ResourceDelegates';
our $RES_NAME_TEXT = "RES_NAME";
our $RES_ALIAS_TEXT = "RES_ALIAS";
our $RES_EMAIL_ADDRESES_TEXT = "RES_EMAIL_ADDRESES";
our $RES_DISPLAY_NAME_TEXT = "RES_DISPLAY_NAME";
our $RES_TYPE_TEXT = "RES_TYPE";
our $RES_CAPACITY_TEXT = "RES_CAPACITY";
our $RES_ADDITIONAL_RESPONSE_TEXT = "RES_ADDITIONAL_RESPONSE";
our $RES_EXT_MEETING_MSG_TEXT = "RES_EXT_MEETING_MSG";
our $RES_ALLOW_CONFLICTS_TEXT = "RES_ALLOW_CONFLICTS";
our $RES_BOOKING_WINDOW_TEXT = "RES_BOOKING_WINDOW";
our $RES_PERCENTAGE_ALLOWED_TEXT = "RES_PERCENTAGE_ALLOWED";
our $RES_ENFORCE_SCHED_HORIZON_TEXT = "RES_ENFORCE_SCHED_HORIZON";
our $RES_MAX_CONFLICT_INSTANCES_TEXT = "RES_MAX_CONFLICT_INSTANCES";
our $RES_MAX_DURATION_TEXT = "RES_MAX_DURATION";
our $RES_SCHED_DURING_WORK_HOURS_TEXT = "RES_SCHED_DURING_WORK_HOURS";
our $RES_ALL_BOOK_IN_POLICY_TEXT = "RES_ALL_BOOK_IN_POLICY";
our $RES_ALL_REQ_IN_POLICY_TEXT = "RES_ALL_REQ_IN_POLICY";
our $RES_ALL_REQ_OUT_OF_POLICY_TEXT = "RES_ALL_REQ_OUT_OF_POLICY";
our $RES_WORKDAYS_TEXT = "RES_WORKDAYS";
our $RES_WORKING_HOURS_START_TIME_TEXT = "RES_WORKING_HOURS_START_TIME";
our $RES_WORKING_HOURS_END_TIME_TEXT = "RES_WORKING_HOURS_END_TIME";
our $RES_ALLOW_RECURRING_MEETINGS_TEXT = "RES_ALLOW_RECURRING_MEETINGS";
our $RES_ADD_ADDITIONAL_RESPONSE_TEXT = "RES_ADD_ADDITIONAL_RESPONSE";
our $RES_DELEGATES_TEXT = "RES_DELEGATES";
our $RES_BOOK_IN_POLICY_TEXT = "RES_BOOK_IN_POLICY";
our $RES_REQUEST_IN_POLICY_TEXT = "RES_REQUEST_IN_POLICY";
our $RES_REQUEST_OUT_OF_POLICY_TEXT = "RES_REQUEST_OUT_OF_POLICY";

our $resourceMails = {};
my $resourceMailsFileName = "$DIRECTORY/$::SERVICE_NAME-resource-mails";
###------------------------------------------------------------------------------
### END of RESOURCE MAILBOXES CONFIGURATION
###------------------------------------------------------------------------------

#Default forwarding domain for MU
our $DEFAULT_FORWARDING_DOMAIN = '@mo.muni.cz';

#-------------------------------------------------------------------------
# GLOBAL DATA STRUCTURES
#-------------------------------------------------------------------------

our $users = {};
our $groups = {};

#-------------------------------------------------------------------------
# PROCESSING FACILITY
#-------------------------------------------------------------------------

my $facilityId = $data->getFacilityId;
my $domainName = $data->getFacilityAttributeValue( attrName => $A_F_DOMAIN_NAME );

unless($facilityId) { die "Facility id can't be empty, it is used to find directory with cache and active users from AD!\n"; }
unless($domainName) { die "Domain name can't be empty for service o365_mu!\n"; }

#-------------------------------------------------------------------------
# PROCESSING RESOURCES
#-------------------------------------------------------------------------

foreach my $resourceId ( $data->getResourceIds() ) {
	processResource $resourceId, $domainName;
}

#-------------------------------------------------------------------------
# SAVE ALL REQUIRED DATA TO FILES
#-------------------------------------------------------------------------

my $usersFileName = "$DIRECTORY/$::SERVICE_NAME-users";
my $groupsFileName = "$DIRECTORY/$::SERVICE_NAME-groups";
my $facilityIdFileName = "$DIRECTORY/$::SERVICE_NAME-facilityId";

saveUsersToFile $usersFileName, $users;
saveGroupsToFile $groupsFileName, $groups;
###we don't want to process resource mailboxes until further change
#saveResourceMailsToFile $resourceMailsFileName, $resourceMails;
saveFacilityIdToFile $facilityIdFileName, $facilityId;

#-------------------------------------------------------------------------
# FINALIZING
#-------------------------------------------------------------------------

perunServicesInit::finalize;

#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
# SUBS
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------

# input: resourceData structure, domain name
# process data about a resource (it also process data about its members and groups)
sub processResource {

	my $resourceId = shift;
	my $domainName = shift;

	#define attributes for processing o365 groups and o365 resource maling lists
	my $isForO365Group = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_IS_FOR_O365_GROUP );
	#my $resName = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_NAME );

	#process all members from resource (users data)
	foreach my $memberId ($data->getMemberIdsForResource( resource => $resourceId )) {
		processResourceMember $memberId;
	}

	### Skip of processing resource mails
	#if resource mail name exists, process it as resource mail (resource-mails data)
	#if($resName) {
	#	#prevent duplicity in resource name
	#	if($resourceMails->{$resName}) { die "There is a duplicity of two Resources with the same resourceMailName: $resName\n"; }
	#
	#	processResourceMail $resourceId;
	#}

	#if resource is set as o365 resource, process it with all it's groups (groups data)
	if($isForO365Group) {
		foreach my $groupId ($data->getGroupIdsForResource( resource => $resourceId )){
			processGroup $groupId, $resourceId;
		}
	}

}

# input: resourceData structure
# process data about resource mailing list
sub processResourceMail {
	my $resourceId = shift;

	my $resName = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_NAME );

	#process all resource mail attributes
	$resourceMails->{$resName}->{$RES_NAME_TEXT} = $resName;
	my $alias = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ALIAS );
	my $emailAddreses = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_EMAIL_ADDRESES );
	my $displayName = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_DISPLAY_NAME );
	my $type = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_TYPE );
	my $capacity = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_CAPACITY );
	my $additionalResponse = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ADDITIONAL_RESPONSE );
	my $extMeetingMsg = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_EXT_MEETING_MSG );
	my $allowConflicts = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ALLOW_CONFLICTS );
	my $bookingWindow = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_BOOKING_WINDOW );
	my $percentageAllowed = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_PERCENTAGE_ALLOWED );
	my $enforceSchedHorizon = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ENFORCE_SCHED_HORIZON );
	my $maxConflictInstances = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_MAX_CONFLICT_INSTANCES );
	my $maxDuration = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_MAX_DURATION );
	my $schedDuringWorkHours = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_SCHED_DURING_WORK_HOURS );
	my $allBookInPolicy = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ALL_BOOK_IN_POLICY );
	my $allReqInPolicy = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ALL_REQ_IN_POLICY );
	my $allReqOutPolicy = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ALL_REQ_OUT_OF_POLICY );
	my $workdays = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_WORKDAYS );
	my $workingHoursStartTime = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_WORKING_HOURS_START_TIME );
	my $workingHoursEndTime = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_WORKING_HOURS_END_TIME );
	my $allowRecurringMeetings = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ALLOW_RECURRING_MEETINGS );
	my $addAdditionalResponse = $data->getResourceAttributeValue( resource => $resourceId, attrName => $A_R_O365_RES_ADD_ADDITIONAL_RESPONSE );

	$resourceMails->{$resName}->{$RES_ALIAS_TEXT}  = $alias ? $alias : "";
	$resourceMails->{$resName}->{$RES_EMAIL_ADDRESES_TEXT} = $emailAddreses ? join(' ', @{$emailAddreses}) : "";
	$resourceMails->{$resName}->{$RES_DISPLAY_NAME_TEXT} = $displayName ? $displayName : "";
	$resourceMails->{$resName}->{$RES_TYPE_TEXT} = $type ? $type : "";
	$resourceMails->{$resName}->{$RES_CAPACITY_TEXT} = $capacity ? $capacity : "";
	$resourceMails->{$resName}->{$RES_ADDITIONAL_RESPONSE_TEXT} = $additionalResponse ? $additionalResponse : "";
	$resourceMails->{$resName}->{$RES_EXT_MEETING_MSG_TEXT} = $extMeetingMsg ? "1" : "0";
	$resourceMails->{$resName}->{$RES_ALLOW_CONFLICTS_TEXT} = $allowConflicts ? "1" : "0";
	$resourceMails->{$resName}->{$RES_BOOKING_WINDOW_TEXT} = $bookingWindow ? $bookingWindow : "";
	$resourceMails->{$resName}->{$RES_PERCENTAGE_ALLOWED_TEXT} = $percentageAllowed ? $percentageAllowed : "";
	$resourceMails->{$resName}->{$RES_ENFORCE_SCHED_HORIZON_TEXT} = $enforceSchedHorizon ? "1" : "0";
	$resourceMails->{$resName}->{$RES_MAX_CONFLICT_INSTANCES_TEXT} = $maxConflictInstances ? $maxConflictInstances : "";
	$resourceMails->{$resName}->{$RES_MAX_DURATION_TEXT} = $maxDuration ? $maxDuration : "";
	$resourceMails->{$resName}->{$RES_SCHED_DURING_WORK_HOURS_TEXT} = $schedDuringWorkHours ? "1" : "0";
	$resourceMails->{$resName}->{$RES_ALL_BOOK_IN_POLICY_TEXT} = $allBookInPolicy ? "1" : "0";
	$resourceMails->{$resName}->{$RES_ALL_REQ_IN_POLICY_TEXT} = $allReqInPolicy ? "1" : "0";
	$resourceMails->{$resName}->{$RES_ALL_REQ_OUT_OF_POLICY_TEXT} = $allReqOutPolicy ? "1" : "0";
	$resourceMails->{$resName}->{$RES_WORKDAYS_TEXT} = $workdays ? join(' ', sort @{$workdays}) : "";
	$resourceMails->{$resName}->{$RES_WORKING_HOURS_START_TIME_TEXT} = $workingHoursStartTime ? $workingHoursStartTime : "";
	$resourceMails->{$resName}->{$RES_WORKING_HOURS_END_TIME_TEXT} = $workingHoursEndTime ? $workingHoursEndTime : "";
	$resourceMails->{$resName}->{$RES_ALLOW_RECURRING_MEETINGS_TEXT} = $allowRecurringMeetings ? "1" : "0";
	$resourceMails->{$resName}->{$RES_ADD_ADDITIONAL_RESPONSE_TEXT} = $addAdditionalResponse ? "1" : "0";

	my @resDelegates = ();
	my @resBookInPolicy = ();
	my @resReqInPolicy = ();
	my @resReqOutOfPolicy = ();

	foreach my $groupId ($data->getGroupIdsForResource( resource => $resourceId )) {

		my $onResourceBookInPolicy = $data->getGroupResourceAttributeValue( group => $groupId, resource => $resourceId, attrName => $A_GR_O365_RES_BOOK_IN_POLICY );
		my $onResourceRequestInPolicy = $data->getGroupResourceAttributeValue( group => $groupId, resource => $resourceId, attrName => $A_GR_O365_RES_REQUEST_IN_POLICY );
		my $onResourceRequestOutOfPolicy = $data->getGroupResourceAttributeValue( group => $groupId, resource => $resourceId, attrName => $A_GR_O365_RES_REQUEST_OUT_OF_POLICY );
		my $onResourceDelegates = $data->getGroupResourceAttributeValue( group => $groupId, resource => $resourceId, attrName => $A_GR_O365_RES_DELEGATES );

		foreach my $memberId($data->getMemberIdsForResourceAndGroup( resource => $resourceId, group => $groupId )) {
			my $UCO = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_LOGIN );

			#Skip all users without licenses (they can't be inside o365)
			next unless( $users->{$UCO} );
			my $UPN = $users->{$UCO}->{$UPN_TEXT};

			if($onResourceBookInPolicy) { push @resBookInPolicy, $UPN; }
			if($onResourceRequestInPolicy) { push @resReqInPolicy, $UPN; }
			if($onResourceRequestOutOfPolicy) { push @resReqOutOfPolicy, $UPN; }
			if($onResourceDelegates) { push @resDelegates, $UPN; }
		}
	}

  $resourceMails->{$resName}->{$RES_DELEGATES_TEXT} =  join(' ', sort @resDelegates);
	$resourceMails->{$resName}->{$RES_BOOK_IN_POLICY_TEXT} = join(' ', sort @resBookInPolicy);
	$resourceMails->{$resName}->{$RES_REQUEST_IN_POLICY_TEXT} = join(' ', sort @resReqInPolicy);
	$resourceMails->{$resName}->{$RES_REQUEST_OUT_OF_POLICY_TEXT} = join(' ', sort @resReqOutOfPolicy);
}

# input: memberData structure from resource
# process data for member on resource (it is used for users data in o365)
sub processResourceMember {
		my $memberId = shift;

		my $UCO = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_LOGIN );
		#skip user's with not UCO login
		return unless ( $UCO =~ /^[0-9]+$/ );

		my $licence = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_O365_LICENCE );

		#skip user's without proper licence
		return if ( ! defined $licence || $licence eq "0");

		my $disableForward = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_DISABLE_MAIL_FORWARD );
		#if mail forward is not set use the default value unless forwarding is disabled for that user
		my $mailForward = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_O365_MAIL_FORWARD ) || $UCO . $DEFAULT_FORWARDING_DOMAIN unless $disableForward;

		my $archive = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_O365_ARCHIVE );
		my $storeAndForward = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_O365_STORE_AND_FORWARD );
		my @emailsArray = ();
		if(defined($data->getUserAttributeValue( member => $memberId, attrName => $A_U_O365_MAIL_ADDRS))) {
			@emailsArray = @{$data->getUserAttributeValue( member => $memberId, attrName => $A_U_O365_MAIL_ADDRS)};
		} else {
			warn "Can't find emails for user with UCO: $UCO \n";
		}
		#do not use sorting because of cache in send script (cache does not have sorted emails and such records would need to be updated even if there is no really change)
		#my $emailsString = join(',', sort @emailsArray);
		my $emailsString = join(',', @emailsArray);

		unless($users->{$UCO}) {
			$users->{$UCO}->{$UPN_TEXT} = $UCO . "@" . $domainName;
			$users->{$UCO}->{$MAIL_FORWARD_TEXT} = $mailForward ? $mailForward : "";
			$users->{$UCO}->{$ARCHIVE_TEXT} = $archive ? "1" : "0";
			$users->{$UCO}->{$STORE_AND_FORWARD_TEXT} = $storeAndForward ? "1" : "0";
			$users->{$UCO}->{$EMAIL_ADDRESSES} = $emailsString;
		}
}

# input: groupData from resource (defined as o365 group)
# process group from resource defined as o365
sub processGroup {
	my $groupId = shift;
	my $resourceId = shift;

	my $groupADName = $data->getGroupAttributeValue( group => $groupId, attrName => $A_G_AD_NAME );

	if($groupADName) {
		#all groups for mu should have specific part of name
		$groupADName = $groupADName . '_group.muni.cz';
		$groups->{$groupADName} = undef;

		foreach my $memberId($data->getMemberIdsForResourceAndGroup( resource => $resourceId, group => $groupId )) {
			processGroupMember $memberId, $groupId, $resourceId, $groupADName;
		}
	}
}

# input: memberData from group assigned to resource, group ad name
# process member of the group
sub processGroupMember {
	my $memberId = shift;
	my $groupId = shift;
	my $resourceId = shift;
	my $groupADName = shift;

	my $UCO = $data->getUserFacilityAttributeValue( member => $memberId, attrName => $A_UF_LOGIN );
	#skipped user which has no licence
	return unless( $users->{$UCO} );

	my $UPN = $users->{$UCO}->{$UPN_TEXT};
	my $sendAsGroup = $data->getMemberGroupAttributeValue( member => $memberId, group => $groupId, attrName => $A_MG_O365_SEND_AS );

	if($sendAsGroup) { $groups->{$groupADName}->{$UPN} = 1; }
}

# input: file name for users data, usersData structure
# save data about users to file
sub saveUsersToFile {
	my $fileName = shift;
	my $usersData = shift;

	open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";
	binmode FILE, ":utf8";

	foreach my $UCO (sort keys %$usersData) {
		print FILE $usersData->{$UCO}->{$UPN_TEXT} . "\t";
		print FILE $usersData->{$UCO}->{$MAIL_FORWARD_TEXT} . "\t";
		print FILE $usersData->{$UCO}->{$ARCHIVE_TEXT} . "\t";
		print FILE $usersData->{$UCO}->{$STORE_AND_FORWARD_TEXT} . "\t";
		print FILE $usersData->{$UCO}->{$EMAIL_ADDRESSES} .  "\n";
	}

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

# input:  file name for groups data, groupsData structure
# save data about groups to the file
sub saveGroupsToFile {
	my $fileName = shift;
	my $groupsData = shift;

	open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";
	binmode FILE, ":utf8";

	foreach my $adName (sort keys %$groupsData) {
		my $contacts = join " ", sort keys %{$groupsData->{$adName}};
		unless($contacts) { $contacts = ""; }
		print FILE $adName . "\t" . $contacts . "\n";
	}

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

# input: file name for facility id data, facilityId
# save data about facility id to the file
sub saveFacilityIdToFile {
	my $fileName = shift;
	my $facilityId = shift;

	open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";
	print FILE $facilityId . "\n";

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

# input: file name for resource mailing lists data, resourceMailsData structure
# save data about resource mailing lists to the file
sub saveResourceMailsToFile {
	my $fileName = shift;
	my $resourceMailsData = shift;

	open FILE, ">$fileName" or die "Cannot open $fileName: $! \n";
	binmode FILE, ":utf8";

	foreach my $resourceMailName (sort keys %$resourceMailsData) {
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_NAME_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ALIAS_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_EMAIL_ADDRESES_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_DISPLAY_NAME_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_TYPE_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_CAPACITY_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ADDITIONAL_RESPONSE_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_EXT_MEETING_MSG_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ALLOW_CONFLICTS_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_BOOKING_WINDOW_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_PERCENTAGE_ALLOWED_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ENFORCE_SCHED_HORIZON_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_MAX_CONFLICT_INSTANCES_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_MAX_DURATION_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_SCHED_DURING_WORK_HOURS_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ALL_BOOK_IN_POLICY_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ALL_REQ_IN_POLICY_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ALL_REQ_OUT_OF_POLICY_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_WORKDAYS_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_WORKING_HOURS_START_TIME_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_WORKING_HOURS_END_TIME_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ALLOW_RECURRING_MEETINGS_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_ADD_ADDITIONAL_RESPONSE_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_DELEGATES_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_BOOK_IN_POLICY_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_REQUEST_IN_POLICY_TEXT} . "\t";
		print FILE $resourceMailsData->{$resourceMailName}->{$RES_REQUEST_OUT_OF_POLICY_TEXT} . "\n";
	}

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