class urn_perun_user_attribute_def_virt_eduPersonScopedAffiliations extends UserVirtualAttributeCollectedFromUserExtSource {

	@Override
	public List<AuditEvent> resolveVirtualAttributeValueChange(PerunSessionImpl perunSession, AuditEvent message) throws WrongReferenceAttributeValueException, AttributeNotExistsException, WrongAttributeAssignmentException {

		// generic handling
		List<AuditEvent> resolvingMessages = super.resolveVirtualAttributeValueChange(perunSession, message);

		// handle source user attribute changes

		if (message instanceof AttributeSetForUser &&
				((AttributeSetForUser) message).getAttribute().getFriendlyName().equals(getSecondarySourceAttributeFriendlyName())) {

			AttributeDefinition attributeDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getDestinationAttributeName());
			resolvingMessages.add(new AttributeChangedForUser(new Attribute(attributeDefinition), ((AttributeSetForUser) message).getUser()));

		} else if (message instanceof AttributeRemovedForUser &&
				((AttributeRemovedForUser) message).getAttribute().getFriendlyName().equals(getSecondarySourceAttributeFriendlyName())) {

			AttributeDefinition attributeDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getDestinationAttributeName());
			resolvingMessages.add(new AttributeChangedForUser(new Attribute(attributeDefinition), ((AttributeRemovedForUser) message).getUser()));

		} else if (message instanceof AllAttributesRemovedForUser) {

			boolean skip = false;
			try {
				AttributeDefinition sourceExists = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getSecondarySourceAttributeName());
				User user = perunSession.getPerunBl().getUsersManagerBl().getUserById(perunSession, ((AllAttributesRemovedForUser) message).getUser().getId());
			} catch (AttributeNotExistsException | UserNotExistsException ex) {
				// silently skip this event, since source attribute couldn't be between deleted
				// or user no longer exist
				skip = true;
			}

			if (!skip) {
				AttributeDefinition attributeDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getDestinationAttributeName());
				resolvingMessages.add(new AttributeChangedForUser(new Attribute(attributeDefinition), ((AllAttributesRemovedForUser) message).getUser()));
			}

		}

		// handle group attr changes, exclude "members" group, since its not counted within attr value

		if (message instanceof AttributeSetForGroup &&
				!VosManager.MEMBERS_GROUP.equals(((AttributeSetForGroup) message).getGroup().getName()) &&
				((AttributeSetForGroup) message).getAttribute().getName().equals(getTertiarySourceAttributeName())) {

			AttributeDefinition attributeDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getDestinationAttributeName());
			// TODO - get only active group users, since expired are not affected by current group affiliations
			List<User> users = perunSession.getPerunBl().getGroupsManagerBl().getGroupUsers(perunSession, ((AttributeSetForGroup) message).getGroup());
			for (User user : users) {
				resolvingMessages.add(new AttributeChangedForUser(new Attribute(attributeDefinition), user));
			}

		} else if (message instanceof AttributeRemovedForGroup &&
				!VosManager.MEMBERS_GROUP.equals(((AttributeRemovedForGroup) message).getGroup().getName()) &&
				((AttributeRemovedForGroup) message).getAttribute().getName().equals(getTertiarySourceAttributeName())) {

			AttributeDefinition attributeDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getDestinationAttributeName());
			// TODO - get only active group users, since expired are not affected by current group affiliations
			List<User> users = perunSession.getPerunBl().getGroupsManagerBl().getGroupUsers(perunSession, ((AttributeRemovedForGroup) message).getGroup());
			for (User user : users) {
				resolvingMessages.add(new AttributeChangedForUser(new Attribute(attributeDefinition), user));
			}

		} else if (message instanceof AllAttributesRemovedForGroup &&
				!VosManager.MEMBERS_GROUP.equals(((AllAttributesRemovedForGroup) message).getGroup().getName())) {

			boolean skip = false;
			try {
				AttributeDefinition sourceExists = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getTertiarySourceAttributeName());
				Group group = perunSession.getPerunBl().getGroupsManagerBl().getGroupById(perunSession, ((AllAttributesRemovedForGroup) message).getGroup().getId());
			} catch (AttributeNotExistsException | GroupNotExistsException ex) {
				// silently skip this event, since source attribute couldn't be between deleted
				// or group no longer exist.
				skip = true;
			}

			if (!skip) {
				AttributeDefinition attributeDefinition = perunSession.getPerunBl().getAttributesManagerBl().getAttributeDefinition(perunSession, getDestinationAttributeName());
				// TODO - get only active group users, since expired are not affected by current group affiliations
				List<User> users = perunSession.getPerunBl().getGroupsManagerBl().getGroupUsers(perunSession, ((AllAttributesRemovedForGroup) message).getGroup());
				for (User user : users) {
					resolvingMessages.add(new AttributeChangedForUser(new Attribute(attributeDefinition), user));
				}
			}

		}

		// case AllAttributesRemovedForGroup doesn't matter, everything was processed by removing members before group deletion

		return resolvingMessages;

	}

}