class urn_perun_user_attribute_def_virt_tcsMails_mu extends UserVirtualAttributesModuleAbstract implements UserVirtualAttributesModuleImplApi {

	@Override
	public Attribute getAttributeValue(PerunSessionImpl sess, User user, AttributeDefinition attributeDefinition) {

		Attribute attribute = new Attribute(attributeDefinition);

		// to keep actual mails in order
		SortedSet<String> tcsMailsValue = new TreeSet<>();
		// to filter out case insensitive duplicates
		Set<String> compareSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);

		List<String> namesOfAttributes = Arrays.asList(A_U_D_preferredMail, A_U_D_ISMail, A_U_D_o365EmailAddressesMU, A_U_D_publicAliasMails, A_U_D_privateAliasMails);

		List<Attribute> sourceAttributes = sess.getPerunBl().getAttributesManagerBl().getAttributes(sess, user, namesOfAttributes);
		Map<String,Attribute> attributesMap = sourceAttributes.stream().collect(Collectors.toMap(Attribute::getName, Function.identity()));

		// ensure attributes order
		for (String attrName : namesOfAttributes) {
			Attribute sourceAttribute = attributesMap.get(attrName);
			if (sourceAttribute != null) {
				// gather values of all attributes
				if (sourceAttribute.getType().equals(String.class.getName())) {
					if (sourceAttribute.getValue() != null) {
						if (!compareSet.contains(sourceAttribute.valueAsString().trim())) {
							// add only case-insensitive unique values
							compareSet.add(sourceAttribute.valueAsString().trim());
							tcsMailsValue.add(sourceAttribute.valueAsString().trim());
						}
					}
				} else if (sourceAttribute.getType().equals(ArrayList.class.getName())) {
					if (sourceAttribute.getValue() != null) {
						sourceAttribute.valueAsList().stream().map(String::trim).collect(Collectors.toList()).forEach(s -> {
							if (!compareSet.contains(s)) {
								// add only case-insensitive unique values
								compareSet.add(s);
								tcsMailsValue.add(s);
							}
						});
					}
				} else {
					//unexpected type of value, log it and skip the attribute
					log.error("Unexpected type of attribute (should be String or ArrayList) {}. It will be skipped.", sourceAttribute);
				}
			} else {
				log.warn("When counting value of attribute {} we are missing source attribute {}. It will be skipped.", this.getAttributeDefinition(), attrName);
			}
		}
		attribute.setValue(new ArrayList<>(tcsMailsValue));

		return attribute;
	}

}