<commit_before>package tools.vitruv.dsls.commonalities.generator

import java.util.Collections
import tools.vitruv.dsls.commonalities.language.CommonalityAttributeMapping
import tools.vitruv.dsls.commonalities.language.Participation
import tools.vitruv.dsls.commonalities.language.elements.EClassAdapter
import tools.vitruv.dsls.commonalities.language.elements.EDataTypeAdapter
import tools.vitruv.dsls.reactions.builder.FluentReactionsSegmentBuilder
import tools.vitruv.dsls.reactions.builder.FluentRoutineBuilder.RoutineStartBuilder
import tools.vitruv.dsls.reactions.builder.FluentRoutineBuilder.UndecidedMatcherStatementBuilder

import static com.google.common.base.Preconditions.*

import static extension tools.vitruv.dsls.commonalities.generator.EmfAccessExpressions.*
import static extension tools.vitruv.dsls.commonalities.generator.ReactionsGeneratorConventions.*
import static extension tools.vitruv.dsls.commonalities.language.extensions.CommonalitiesLanguageModelExtensions.*

package class ParticipationAttributeChangeReactionsBuilder extends ReactionsSubGenerator {

	static class Factory extends InjectingFactoryBase {
		def createFor(Participation participation) {
			return new ParticipationAttributeChangeReactionsBuilder(participation).injectMembers
		}
	}

	val Participation participation

	private new(Participation participation) {
		checkNotNull(participation, "participation is null")
		this.participation = participation
	}

	// Dummy constructor for Guice
	package new() {
		this.participation = null
		throw new IllegalStateException("Use the Factory to create instances of this class!")
	}

	def package void generateReactions(FluentReactionsSegmentBuilder segment) {
		segment += commonality.attributes.flatMap[mappings].filter [
			isRead && it.participation == participation
		].flatMap[reactionsForAttributeMappingRightChange]
	}

	def private reactionsForAttributeMappingRightChange(CommonalityAttributeMapping mapping) {
		switch (mapping.attribute.type) {
			EDataTypeAdapter case !mapping.attribute.isMultiValued:
				Collections.singleton(singleAttributeSetReaction(mapping))

			EDataTypeAdapter case mapping.attribute.isMultiValued:
				#[multiAttributeAddReaction(mapping), multiAttributeRemoveReaction(mapping)]

			EClassAdapter case !mapping.attribute.isMultiValued:
				Collections.singleton(singleReferenceSetReaction(mapping))

			EClassAdapter case mapping.attribute.isMultiValued:
				#[multiReferenceAddReaction(mapping), multiReferenceRemoveReaction(mapping)]
		}
	}

	def private singleAttributeSetReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Change''')
			.afterAttributeReplacedAt(mapping.participationChangeClass, mapping.participationEAttribute)
			.call [
				buildSingleFeatureSetRoutine(mapping)
			]
	}

	def private multiAttributeAddReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Insert''')
			.afterAttributeInsertIn(mapping.participationChangeClass, mapping.participationEAttribute)
			.call [
				buildMultiFeatureAddRoutine(mapping)
			]
	}

	def private multiAttributeRemoveReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Remove''')
			.afterAttributeRemoveFrom(mapping.participationChangeClass, mapping.participationEAttribute)
			.call [
				buildMultiFeatureRemoveRoutine(mapping)
			]
	}

	def private singleReferenceSetReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Change''')
			.afterElement.replacedAt(mapping.participationChangeClass, mapping.participationEReference)
			.call [
				buildSingleFeatureSetRoutine(mapping)
			]
	}

	def private multiReferenceAddReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participation.name»«mapping.attribute.name.toFirstUpper»Insert''')
			.afterElement.insertedIn(mapping.participationChangeClass, mapping.participationEReference)
			.call [
				buildMultiFeatureAddRoutine(mapping)
			]
	}

	def private multiReferenceRemoveReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Remove''').
			afterElement.removedFrom(mapping.participationChangeClass, mapping.participationEReference)
			.call [
				buildMultiFeatureRemoveRoutine(mapping)
			]
	}

	def private buildSingleFeatureSetRoutine(extension RoutineStartBuilder routineBuilder,
		CommonalityAttributeMapping mapping) {
		input [newValue]
		.match [
			retrieveIntermediate()
		]
		.action [
			update(INTERMEDIATE) [
				setFeatureValue(variable(INTERMEDIATE), mapping.commonalityEFeature, newValue)
			]
		]
	}

	def private buildMultiFeatureAddRoutine(extension RoutineStartBuilder routineBuilder,
		CommonalityAttributeMapping mapping) {
		input [newValue]
		.match [
			retrieveIntermediate()
		]
		.action [
			update(INTERMEDIATE) [
				addToListFeatureValue(variable(INTERMEDIATE), mapping.commonalityEFeature, newValue)
			]
		]
	}

	def private buildMultiFeatureRemoveRoutine(extension RoutineStartBuilder routineBuilder,
		CommonalityAttributeMapping mapping) {
		input [oldValue]
		.match [
			retrieveIntermediate()
		]
		.action [
			update(INTERMEDIATE) [
				removeFromListFeatureValue(variable(INTERMEDIATE), mapping.commonalityEFeature, oldValue)
			]
		]
	}

	def private retrieveIntermediate(extension UndecidedMatcherStatementBuilder builder) {
		vall(INTERMEDIATE).retrieve(commonality.changeClass).correspondingTo.affectedEObject
	}
}<commit_msg>Fixed: When using multiple participations classes for the same metaclass, change propagation would sometimes not come to an end due to cyclic changes.<commit_after>package tools.vitruv.dsls.commonalities.generator

import java.util.Collections
import tools.vitruv.dsls.commonalities.language.CommonalityAttributeMapping
import tools.vitruv.dsls.commonalities.language.Participation
import tools.vitruv.dsls.commonalities.language.elements.EClassAdapter
import tools.vitruv.dsls.commonalities.language.elements.EDataTypeAdapter
import tools.vitruv.dsls.reactions.builder.FluentReactionsSegmentBuilder
import tools.vitruv.dsls.reactions.builder.FluentRoutineBuilder.RoutineStartBuilder
import tools.vitruv.dsls.reactions.builder.FluentRoutineBuilder.UndecidedMatcherStatementBuilder

import static com.google.common.base.Preconditions.*

import static extension tools.vitruv.dsls.commonalities.generator.EmfAccessExpressions.*
import static extension tools.vitruv.dsls.commonalities.generator.ReactionsGeneratorConventions.*
import static extension tools.vitruv.dsls.commonalities.language.extensions.CommonalitiesLanguageModelExtensions.*

package class ParticipationAttributeChangeReactionsBuilder extends ReactionsSubGenerator {

	static class Factory extends InjectingFactoryBase {
		def createFor(Participation participation) {
			return new ParticipationAttributeChangeReactionsBuilder(participation).injectMembers
		}
	}

	val Participation participation

	private new(Participation participation) {
		checkNotNull(participation, "participation is null")
		this.participation = participation
	}

	// Dummy constructor for Guice
	package new() {
		this.participation = null
		throw new IllegalStateException("Use the Factory to create instances of this class!")
	}

	def package void generateReactions(FluentReactionsSegmentBuilder segment) {
		segment += commonality.attributes.flatMap[mappings].filter [
			isRead && it.participation == participation
		].flatMap[reactionsForAttributeMappingRightChange]
	}

	def private reactionsForAttributeMappingRightChange(CommonalityAttributeMapping mapping) {
		switch (mapping.attribute.type) {
			EDataTypeAdapter case !mapping.attribute.isMultiValued:
				Collections.singleton(singleAttributeSetReaction(mapping))

			EDataTypeAdapter case mapping.attribute.isMultiValued:
				#[multiAttributeAddReaction(mapping), multiAttributeRemoveReaction(mapping)]

			EClassAdapter case !mapping.attribute.isMultiValued:
				Collections.singleton(singleReferenceSetReaction(mapping))

			EClassAdapter case mapping.attribute.isMultiValued:
				#[multiReferenceAddReaction(mapping), multiReferenceRemoveReaction(mapping)]
		}
	}

	def private singleAttributeSetReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Change''')
			.afterAttributeReplacedAt(mapping.participationChangeClass, mapping.participationEAttribute)
			.call [
				buildSingleFeatureSetRoutine(mapping)
			]
	}

	def private multiAttributeAddReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Insert''')
			.afterAttributeInsertIn(mapping.participationChangeClass, mapping.participationEAttribute)
			.call [
				buildMultiFeatureAddRoutine(mapping)
			]
	}

	def private multiAttributeRemoveReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Remove''')
			.afterAttributeRemoveFrom(mapping.participationChangeClass, mapping.participationEAttribute)
			.call [
				buildMultiFeatureRemoveRoutine(mapping)
			]
	}

	def private singleReferenceSetReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Change''')
			.afterElement.replacedAt(mapping.participationChangeClass, mapping.participationEReference)
			.call [
				buildSingleFeatureSetRoutine(mapping)
			]
	}

	def private multiReferenceAddReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participation.name»«mapping.attribute.name.toFirstUpper»Insert''')
			.afterElement.insertedIn(mapping.participationChangeClass, mapping.participationEReference)
			.call [
				buildMultiFeatureAddRoutine(mapping)
			]
	}

	def private multiReferenceRemoveReaction(CommonalityAttributeMapping mapping) {
		create.reaction('''«mapping.participationAttributeReactionName»Remove''').
			afterElement.removedFrom(mapping.participationChangeClass, mapping.participationEReference)
			.call [
				buildMultiFeatureRemoveRoutine(mapping)
			]
	}

	def private buildSingleFeatureSetRoutine(extension RoutineStartBuilder routineBuilder,
		CommonalityAttributeMapping mapping) {
		input [newValue]
		.match [
			retrieveIntermediate(mapping)
		]
		.action [
			update(INTERMEDIATE) [
				setFeatureValue(variable(INTERMEDIATE), mapping.commonalityEFeature, newValue)
			]
		]
	}

	def private buildMultiFeatureAddRoutine(extension RoutineStartBuilder routineBuilder,
		CommonalityAttributeMapping mapping) {
		input [newValue]
		.match [
			retrieveIntermediate(mapping)
		]
		.action [
			update(INTERMEDIATE) [
				addToListFeatureValue(variable(INTERMEDIATE), mapping.commonalityEFeature, newValue)
			]
		]
	}

	def private buildMultiFeatureRemoveRoutine(extension RoutineStartBuilder routineBuilder,
		CommonalityAttributeMapping mapping) {
		input [oldValue]
		.match [
			retrieveIntermediate(mapping)
		]
		.action [
			update(INTERMEDIATE) [
				removeFromListFeatureValue(variable(INTERMEDIATE), mapping.commonalityEFeature, oldValue)
			]
		]
	}

	def private retrieveIntermediate(extension UndecidedMatcherStatementBuilder builder,
		CommonalityAttributeMapping mapping) {
		val commonality = mapping.containingCommonality
		val participationClass = mapping.attribute.participationClass
		vall(INTERMEDIATE).retrieve(commonality.changeClass)
			.correspondingTo.affectedEObject
			.taggedWith(participationClass.correspondenceTag)
	}
}
{'fraction_non_alphanumeric': 0.07775471371734993, 'fraction_numerical': 0.0, 'mean_word_length': 6.765614506380121, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3116598', 'n_tokens_mistral': 3539, 'n_tokens_neox': 3084, 'n_words': 532}