From d1ba9fd011815e5cafc7e21b1ac61939f12cecdd Mon Sep 17 00:00:00 2001
From: Daniel Haag <daniel.haag@uibk.ac.at>
Date: Wed, 20 Jun 2018 14:49:50 +0000
Subject: [PATCH] OPENOLAT-579: major refactoring to use the new
 CourseFragmentEnvironmentMapper in the node wizard

---
 .../uibk/course/CreateCourseContentStep.java  |   4 +-
 .../CopyStructureWizardFactory.java           |   6 +-
 .../CopyStructureWizardFactoryImpl.java       |  36 +--
 ...CopyStructureWizardStepRunnerCallback.java |  66 ++--
 .../_i18n/LocalStrings_de.properties          |   1 -
 .../_i18n/LocalStrings_en.properties          |   1 -
 .../AbstractCourseNodeCopyConfigurator.java   | 289 +++---------------
 .../BCCourseNodeCopyConfigurator.java         |   6 +-
 .../COCourseNodeCopyConfigurator.java         |   6 +-
 .../DialogCourseNodeCopyConfigurator.java     |   6 +-
 .../ENCourseNodeCopyConfigurator.java         | 111 +------
 .../FOCourseNodeCopyConfigurator.java         |   6 +-
 .../GTACourseNodeCopyConfigurator.java        |   6 +-
 .../ICourseNodeCopyConfigurator.java          |   4 +-
 .../InfoCourseNodeCopyConfigurator.java       |   6 +-
 .../LLCourseNodeCopyConfigurator.java         |   6 +-
 .../PortfolioCourseNodeCopyConfigurator.java  |   6 +-
 ...ojectBrokerCourseNodeCopyConfigurator.java |   9 +-
 .../SPCourseNodeCopyConfigurator.java         |  14 +-
 .../STCourseNodeCopyConfigurator.java         |  45 ++-
 .../TACourseNodeCopyConfigurator.java         |   6 +-
 .../WikiCourseNodeCopyConfigurator.java       |   6 +-
 .../CourseFragmentEnvironmentMapper.java      |  55 ++++
 ...StructureWizardStepRunnerCallbackTest.java |   8 +-
 24 files changed, 243 insertions(+), 466 deletions(-)
 create mode 100644 src/main/java/org/olat/course/export/CourseFragmentEnvironmentMapper.java

diff --git a/src/main/java/at/ac/uibk/course/CreateCourseContentStep.java b/src/main/java/at/ac/uibk/course/CreateCourseContentStep.java
index f575b42460b..3353d999953 100644
--- a/src/main/java/at/ac/uibk/course/CreateCourseContentStep.java
+++ b/src/main/java/at/ac/uibk/course/CreateCourseContentStep.java
@@ -76,9 +76,7 @@ public class CreateCourseContentStep extends BasicStep {
 	@Override
 	public StepFormController getStepController(UserRequest ureq, WindowControl windowControl, StepsRunContext stepsRunContext, Form form) {
 		stepsRunContext.put("stepProcess", stepProcess);
-		StepFormController stepP = new CreateCourseContentStepForm(ureq, windowControl, form, stepsRunContext, null);
-		
-		return stepP;
+		return new CreateCourseContentStepForm(ureq, windowControl, form, stepsRunContext, null);
 	}
 
 
diff --git a/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactory.java b/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactory.java
index ad64fd082d0..dded773fe70 100644
--- a/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactory.java
+++ b/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactory.java
@@ -26,6 +26,7 @@ import org.olat.core.gui.control.generic.wizard.StepRunnerCallback;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.ICourse;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 
@@ -60,7 +61,8 @@ public abstract class CopyStructureWizardFactory {
 
 	public abstract StepRunnerCallback createCopyStructureWizardStepRunnerCallback();
 
-	public abstract ICourseNodeCopyConfigurator getCourseNodeCopyConfigurator(Identity fallbackIdentity, CourseEnvironment srcCourseEnv,
-			CourseEnvironment targetCourseEnv, CourseNode srcCourseNode, CourseNode targetCourseNode, boolean canCopyToCourseFolder, Translator translator);
+	public abstract ICourseNodeCopyConfigurator getCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv,
+			final CourseEnvironment targetCourseEnv, final CourseNode srcCourseNode, final CourseNode targetCourseNode,
+			final CourseFragmentEnvironmentMapper courseEnvironmentMapper, final boolean canCopyToCourseFolder);
 
 }
diff --git a/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactoryImpl.java b/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactoryImpl.java
index ac47c8cb386..016dd09b49f 100644
--- a/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactoryImpl.java
+++ b/src/main/java/de/bps/course/nodewizard/CopyStructureWizardFactoryImpl.java
@@ -22,9 +22,9 @@ package de.bps.course.nodewizard;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.control.generic.wizard.Step;
 import org.olat.core.gui.control.generic.wizard.StepRunnerCallback;
-import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.ICourse;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.BCCourseNode;
 import org.olat.course.nodes.COCourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -85,69 +85,69 @@ public class CopyStructureWizardFactoryImpl extends CopyStructureWizardFactory {
 
 	@Override
 	public ICourseNodeCopyConfigurator getCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv,
-			final CourseEnvironment targetCourseEnv, final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder,
-			final Translator translator) {
+			final CourseEnvironment targetCourseEnv, final CourseNode srcCourseNode, final CourseNode targetCourseNode,
+			final CourseFragmentEnvironmentMapper courseEnvironmentMapper, final boolean canCopyToCourseFolder) {
 		ICourseNodeCopyConfigurator configurator;
 
 		if (srcCourseNode instanceof SPCourseNode) {
 			// Single page
 			configurator = new SPCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof BCCourseNode) {
 			// Folder
 			configurator = new BCCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof LLCourseNode) {
 			// link list
 			configurator = new LLCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof DialogCourseNode) {
 			// dialog
 			configurator = new DialogCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof FOCourseNode) {
 			// forum
 			configurator = new FOCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof InfoCourseNode) {
 			// info
 			configurator = new InfoCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof PortfolioCourseNode) {
 			// portfolio
 			configurator = new PortfolioCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof ProjectBrokerCourseNode) {
 			// project broker
 			configurator = new ProjectBrokerCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof TACourseNode) {
 			// task
 			configurator = new TACourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof GTACourseNode) {
 			// task
 			configurator = new GTACourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof WikiCourseNode) {
 			// wiki
 			configurator = new WikiCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof ENCourseNode) {
 			// enrolment
 			configurator = new ENCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof COCourseNode) {
 			// mail
 			configurator = new COCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else if (srcCourseNode instanceof STCourseNode) {
 			// structure
 			configurator = new STCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		} else {
 			configurator = new AbstractCourseNodeCopyConfigurator(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode,
-					canCopyToCourseFolder, translator);
+					courseEnvironmentMapper, canCopyToCourseFolder);
 		}
 
 		return configurator;
diff --git a/src/main/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallback.java b/src/main/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallback.java
index 5202d1e898c..641b0a9bde0 100644
--- a/src/main/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallback.java
+++ b/src/main/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallback.java
@@ -20,25 +20,28 @@ import org.olat.core.util.nodes.INode;
 import org.olat.core.util.vfs.MergeSource;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.course.CourseFactory;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
+import org.olat.course.tree.CourseEditorTreeModel;
 
 import de.bps.course.nodewizard.coursenode.ICourseNodeCopyConfigurator;
 
 public class CopyStructureWizardStepRunnerCallback implements StepRunnerCallback {
 
 	private WizardStepProcess process;
+	
+	private CourseFragmentEnvironmentMapper courseFragmentEnvironmentMapper;
 
-	private HashMap<String, String> nodeSrcTargetMapping = new HashMap<>();
-
-	public Map<String, String> getNodeSrcTargetMapping() {
-		return nodeSrcTargetMapping;
+	public CourseFragmentEnvironmentMapper getCourseFragmentEnvironmentMapper() {
+		return courseFragmentEnvironmentMapper;
 	}
 
 	@Override
 	public Step execute(final UserRequest ureq, final WindowControl wControl, final StepsRunContext runContext) {
 		boolean hasChanges = false;
 		final Translator translator = new PackageTranslator(this.getClass().getPackage().getName(), ureq.getLocale());
+		courseFragmentEnvironmentMapper = new CourseFragmentEnvironmentMapper();
 
 		process = (WizardStepProcess) runContext.get("stepProcess");
 
@@ -52,9 +55,11 @@ public class CopyStructureWizardStepRunnerCallback implements StepRunnerCallback
 		if (rootNode.getChildCount() > 0) {
 			hasChanges = true;
 			for (int i = 0; i < rootNode.getChildCount(); i++) {
-				addChildNode(ureq.getIdentity(), process.getTargetCourse().getRunStructure().getRootNode(), rootNode.getChildAt(i), translator);
+				addChildNode(ureq.getIdentity(), process.getTargetCourse().getRunStructure().getRootNode(), rootNode.getChildAt(i));
 			}
-			nodeSrcTargetMapping.keySet().stream().forEach(srcId -> configureNode(ureq.getIdentity(), srcId, translator));
+			// after all the selected nodes are added to the target course, configure all the added nodes and apply the node id mapping
+			courseFragmentEnvironmentMapper.getNodeSourceIds().stream()
+				.forEach(srcId -> configureNode(ureq.getIdentity(), srcId, translator));
 			CourseFactory.saveCourseEditorTreeModel(process.getTargetCourse().getResourceableId());
 		}
 		return hasChanges ? StepsMainRunController.DONE_MODIFIED : StepsMainRunController.DONE_UNCHANGED;
@@ -82,38 +87,30 @@ public class CopyStructureWizardStepRunnerCallback implements StepRunnerCallback
 		}
 	}
 
-	private void addChildNode(final Identity fallbackIdentity, CourseNode parentNode, final INode childNode, final Translator translator) {
-		final CourseNode srcCourseNode = process.getSrcCourse().getRunStructure().getNode(childNode.getIdent());
-		CourseNode newSrcCourseNode = srcCourseNode;
-		if (process.getSelectedKeys().contains(childNode.getIdent())) {
+	private void addChildNode(final Identity fallbackIdentity, CourseNode targetParentNode, final INode node) {
+		final CourseNode srcCourseNode = process.getSrcCourse().getRunStructure().getNode(node.getIdent());
+		final CourseNode selectedTargetParentNode;
+		if (process.getSelectedKeys().contains(node.getIdent())) {
 			// add course node
-			final boolean isNewTitle = process.getTargetCourse().getEditorTreeModel().getNodeById(childNode.getIdent()) != null;
-			newSrcCourseNode = srcCourseNode.createInstanceForCopy(isNewTitle, process.getTargetCourse(),fallbackIdentity);
+			CourseEditorTreeModel targetEditorTreeModel = process.getTargetCourse().getEditorTreeModel();
+			final boolean isNewTitle = targetEditorTreeModel.getNodeById(node.getIdent()) != null;
+			final CourseNode targetCourseNode = srcCourseNode.createInstanceForCopy(isNewTitle, process.getTargetCourse(),fallbackIdentity);
 
 			// Remove the parent and the children references as the new node ends up in the editortreemodel,
 			// where the tree structure is not in the Course Nodes but in the EditorTreeNodes.
-			newSrcCourseNode.setParent(null);
-			newSrcCourseNode.removeAllChildren();
+			targetCourseNode.setParent(null);
+			targetCourseNode.removeAllChildren();
 			//------
 
-			// if parent node not selected then calculate new parent node
-			if (!process.getSelectedKeys().contains(parentNode.getIdent())) {
-				INode parent = parentNode;
-				while (process.getTargetCourse().getEditorTreeModel().getNodeById(parent.getIdent()) == null) {
-					parent = parent.getParent();
-					if (parent.getIdent().equals(process.getSrcCourse().getEditorTreeModel().getRootNode().getIdent())) {
-						parent = process.getTargetCourse().getEditorTreeModel().getRootNode();
-						break;
-					}
-				}
-				parentNode = process.getTargetCourse().getEditorTreeModel().getCourseNode(parent.getIdent());
-			}
-			process.getTargetCourse().getEditorTreeModel().addCourseNode(newSrcCourseNode, parentNode);
-			nodeSrcTargetMapping.put(childNode.getIdent(), newSrcCourseNode.getIdent());
+			targetEditorTreeModel.addCourseNode(targetCourseNode, targetParentNode);
+			courseFragmentEnvironmentMapper.addNodeIdentKeyPair(srcCourseNode.getIdent(), targetCourseNode.getIdent());
+			selectedTargetParentNode = targetCourseNode;
+		} else {
+			selectedTargetParentNode = targetParentNode;
 		}
 		// handle children
-		for (int i = 0; i < childNode.getChildCount(); i++) {
-			addChildNode(fallbackIdentity, newSrcCourseNode, childNode.getChildAt(i), translator);
+		for (int i = 0; i < node.getChildCount(); i++) {
+			addChildNode(fallbackIdentity, selectedTargetParentNode, node.getChildAt(i));
 		}
 	}
 
@@ -123,16 +120,19 @@ public class CopyStructureWizardStepRunnerCallback implements StepRunnerCallback
 		final CourseEnvironment targetCourseEnv = process.getTargetCourse().getCourseEnvironment();
 
 		final CourseNode srcCourseNode = process.getSrcCourse().getRunStructure().getNode(srcNodeId);
-		final CourseNode targetCourseNode = process.getTargetCourse().getEditorTreeModel().getCourseNode(nodeSrcTargetMapping.get(srcNodeId));
+		final CourseNode targetCourseNode = process.getTargetCourse().getEditorTreeModel()
+				.getCourseNode(courseFragmentEnvironmentMapper.getNodeTargetIdent(srcNodeId));
 
+		// we do not let the individual nodes copy their files if the copy all
+		// option is selected as all the files should be there already.
 		final boolean canCopyToCourseFolder = !process.getCopyAll();
 
 		final ICourseNodeCopyConfigurator cncc = CopyStructureWizardFactory.getInstance().getCourseNodeCopyConfigurator(
 				fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode,
-				targetCourseNode, canCopyToCourseFolder, translator);
+				targetCourseNode, courseFragmentEnvironmentMapper, canCopyToCourseFolder);
 
 		cncc.configure();
-		cncc.updateNodeReferences(nodeSrcTargetMapping);
+		cncc.updateNodeReferences();
 	}
 
 
diff --git a/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_de.properties b/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_de.properties
index e21bcc62e94..262766eccc8 100644
--- a/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_de.properties
+++ b/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_de.properties
@@ -1,4 +1,3 @@
-configurator.sp.copy.extension=Kopie{0}
 editor.success.info.message=Die gew\u00e4hlten Kursbausteine wurden erfolgreich hinzugef\u00fcgt.
 editor.tool.entry=Aus anderem Kurs
 editor.wizard.title=Kursbausteine kopieren
diff --git a/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_en.properties b/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_en.properties
index 883b66dd74a..676c23970f3 100644
--- a/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_en.properties
+++ b/src/main/java/de/bps/course/nodewizard/_i18n/LocalStrings_en.properties
@@ -1,4 +1,3 @@
-configurator.sp.copy.extension=Copy{0}
 editor.success.info.message=Course elements successfully copied into course.
 editor.tool.entry=From other course
 editor.wizard.title=Copy course elements from other courses
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/AbstractCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/AbstractCourseNodeCopyConfigurator.java
index 34693b8f1b7..2494f5aae17 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/AbstractCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/AbstractCourseNodeCopyConfigurator.java
@@ -21,26 +21,18 @@ package de.bps.course.nodewizard.coursenode;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
-import org.olat.course.CourseFactory;
-import org.olat.course.ICourse;
 import org.olat.course.condition.Condition;
+import org.olat.course.condition.KeyAndNameConverter;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
-import org.olat.group.BusinessGroup;
-import org.olat.group.BusinessGroupService;
-import org.olat.group.area.BGArea;
 import org.olat.group.area.BGAreaManager;
-import org.olat.repository.RepositoryEntry;
-import org.olat.repository.RepositoryManager;
-import org.olat.resource.OLATResource;
-import org.olat.resource.OLATResourceManager;
+
 
 /**
  * 
@@ -53,13 +45,14 @@ public class AbstractCourseNodeCopyConfigurator implements ICourseNodeCopyConfig
 	protected CourseNode targetCourseNode;
 	protected CourseEnvironment srcCourseEnv;
 	protected CourseEnvironment targetCourseEnv;
+	protected CourseFragmentEnvironmentMapper courseEnvMapper;
 	protected boolean canCopyToCourseFolder;
 	protected final Identity fallbackIdentity;
 	protected final BGAreaManager areaManager;
-	protected final Translator translator;
 
 	public AbstractCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
 		// area manager
 		this.areaManager = CoreSpringFactory.getImpl(BGAreaManager.class);
 		this.fallbackIdentity = fallbackIdentity;
@@ -67,8 +60,8 @@ public class AbstractCourseNodeCopyConfigurator implements ICourseNodeCopyConfig
 		this.targetCourseNode = targetCourseNode;
 		this.srcCourseEnv = srcCourseEnv;
 		this.targetCourseEnv = targetCourseEnv;
+		this.courseEnvMapper = courseEnvironmentMapper;
 		this.canCopyToCourseFolder = canCopyToCourseFolder;
-		this.translator = translator;
 	}
 
 	@Override
@@ -83,14 +76,14 @@ public class AbstractCourseNodeCopyConfigurator implements ICourseNodeCopyConfig
 
 		// configure conditions
 		configureConditions(srcPreConditionAccess, targetPreConditionAccess);
-		configureConditions(srcPreConditionVisibility, targetPreConditionVisibility);
+		configureConditions(srcPreConditionVisibility, targetPreConditionVisibility);		
 	}
 
 	/**
 	 * @param srcPreConditionAccess
 	 * @param targetPreConditionAccess
 	 */
-	void configureConditions(final Condition srcPreCondition, final Condition targetPreCondition) {
+	protected void configureConditions(final Condition srcPreCondition, final Condition targetPreCondition) {
 		// in the abstract implementation configure only general access rules
 		configureOnlyGeneralAccess(srcPreCondition, targetPreCondition);
 	}
@@ -102,56 +95,20 @@ public class AbstractCourseNodeCopyConfigurator implements ICourseNodeCopyConfig
 	 * @param targetCondition
 	 */
 	private void configureOnlyGeneralAccess(final Condition srcCondition, final Condition targetCondition) {
-		targetCondition.setExpertMode(false);
-		targetCondition.clearEasyConfig();
-		targetCondition.setEasyModeCoachesAndAdmins(srcCondition.isEasyModeCoachesAndAdmins());
-		targetCondition.setEasyModeAlwaysAllowCoachesAndAdmins(srcCondition.isEasyModeAlwaysAllowCoachesAndAdmins());
-		targetCondition.setAssessmentMode(srcCondition.isAssessmentMode());
-		targetCondition.setConditionExpression(targetCondition.getConditionFromEasyModeConfiguration());
-	}
-
-	/**
-	 * @param groupIds
-	 * @return
-	 */
-	protected Map<Long, Long> createBusinessGroups(final Map<Long, String> groupIds) {
-		// business group service
-		final BusinessGroupService businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
-		final Map<Long, Long> oldIdNewIdMap = new HashMap<>();
-		// result group ids
-		final Map<Long, String> mapIdName = new HashMap<>();
-		for (final Long id : groupIds.keySet()) {
-			final BusinessGroup bg = businessGroupService.loadBusinessGroup(id);
-			if (bg != null) {
-				final String name = bg.getName();
-				mapIdName.put(id, name);
-			}
-		}
-		if (!mapIdName.isEmpty()) {
-			oldIdNewIdMap.putAll(buildBusinessGroups(mapIdName));
-		}
-		return oldIdNewIdMap;
-	}
-
-	/**
-	 * @param groupIds
-	 * @return
-	 */
-	protected Map<Long, Long> createAreas(final Map<Long, String> groupIds) {
-		final Map<Long, Long> oldIdNewIdMap = new HashMap<>();
-		// result group ids
-		final Map<Long, String> mapIdName = new HashMap<>();
-		for (final Long id : groupIds.keySet()) {
-			final BGArea bgArea = areaManager.loadArea(id);
-			if (bgArea != null) {
-				final String name = bgArea.getName();
-				mapIdName.put(id, name);
-			}
-		}
-		if (!mapIdName.isEmpty()) {
-			oldIdNewIdMap.putAll(buildAreas(mapIdName));
+		if (srcCondition.isExpertMode()) {
+			targetCondition.setConditionExpression(srcCondition.getConditionExpression());
+		} else {
+			// if expert mode is not set, remove easy group and area rules
+			targetCondition.setEasyModeGroupAccess(null);
+			targetCondition.setEasyModeGroupAccessIds(null);
+			targetCondition.setEasyModeGroupAreaAccess(null);
+			targetCondition.setEasyModeGroupAreaAccessIds(null);
+			// remove also begin and end dates as they don't make sense anymore in the new course time frame
+			targetCondition.setEasyModeBeginDate(null);
+			targetCondition.setEasyModeEndDate(null);
+			// recalculate the new condition expression
+			targetCondition.setConditionExpression(targetCondition.getConditionFromEasyModeConfiguration());			
 		}
-		return oldIdNewIdMap;
 	}
 
 	protected List<String> listNames(final String list, final String separator) {
@@ -164,192 +121,38 @@ public class AbstractCourseNodeCopyConfigurator implements ICourseNodeCopyConfig
 		return names;
 	}
 
-	/**
-	 * create business group
-	 * 
-	 * @param groupNames
-	 */
-	protected void createBusinessGroups(final List<String> groupNames) {
-		// business group service
-		final BusinessGroupService businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
-		// exists groups in course
-		boolean groupExists = false;
-		for (final String groupName : groupNames) {
-			groupExists = false;
-			List<BusinessGroup> businessGroups = this.targetCourseEnv.getCourseGroupManager().getAllBusinessGroups();
-			for (final BusinessGroup businessGroup : businessGroups) {
-				if (businessGroup.getName().equals(groupName)) {
-					// group exists
-					groupExists = true;
-					break;
-				}
-			}
-
-			// if not exists then create groups
-			if (!groupExists) {
-				BusinessGroup srcGroup = null;
-				businessGroups = this.srcCourseEnv.getCourseGroupManager().getAllBusinessGroups();
-				for (final BusinessGroup businessGroup : businessGroups) {
-					if (businessGroup.getName().equals(groupName)) {
-						// group exists
-						groupExists = true;
-						srcGroup = businessGroup;
-						break;
-					}
-				}
-
-				if (groupExists) {
-					businessGroupService.copyBusinessGroup(this.fallbackIdentity, srcGroup, srcGroup.getName(), srcGroup.getDescription(),
-							srcGroup.getMinParticipants(), srcGroup.getMaxParticipants(), true, true, true, false, false, true, false, false);
-				}
-			}
-		}
-	}
-
-	private Map<Long, Long> buildBusinessGroups(final Map<Long, String> mapIdName) {
-		final Map<Long, Long> oldIdNewIdMap = new HashMap<>();
-		// business group service
-		final BusinessGroupService businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
-		// exists groups in course
-		boolean groupExists = false;
-		// new business group
-		for (final Long oldId : mapIdName.keySet()) {
-			groupExists = false;
-			List<BusinessGroup> businessGroups = this.targetCourseEnv.getCourseGroupManager().getAllBusinessGroups();
-			for (final BusinessGroup businessGroup : businessGroups) {
-				if (businessGroup.getName().equals(mapIdName.get(oldId))) {
-					// group exists
-					groupExists = true;
-					oldIdNewIdMap.put(oldId, businessGroup.getKey());
-					break;
-				}
-			}
-
-			// if not exists then create groups
-			if (!groupExists) {
-				BusinessGroup srcGroup = null;
-				businessGroups = this.srcCourseEnv.getCourseGroupManager().getAllBusinessGroups();
-				for (final BusinessGroup businessGroup : businessGroups) {
-					if (businessGroup.getName().equals(mapIdName.get(oldId))) {
-						// group exists
-						groupExists = true;
-						srcGroup = businessGroup;
-						break;
-					}
-				}
-
-				if (groupExists) {
-					final BusinessGroup newBusinessGroup = businessGroupService.copyBusinessGroup(this.fallbackIdentity, srcGroup, srcGroup.getName(),
-							srcGroup.getDescription(), srcGroup.getMinParticipants(), srcGroup.getMaxParticipants(), true, false, true, false, false, true,
-							false, false);
-					oldIdNewIdMap.put(oldId, newBusinessGroup.getKey());
-				}
-			}
-		}
-		return oldIdNewIdMap;
+	@Override
+	public void updateNodeReferences() {
+		// Override/extend this function if your node references other nodes
+		updateCondition(targetCourseNode.getPreConditionAccess());
+		updateCondition(targetCourseNode.getPreConditionVisibility());
+		return;
 	}
-
-	/**
-	 * @param mapIdName
-	 * @return
-	 */
-	private Map<Long, Long> buildAreas(final Map<Long, String> mapIdName) {
-		final Map<Long, Long> oldIdNewIdMap = new HashMap<>();
-		// target
-		final ICourse course = CourseFactory.loadCourse(this.targetCourseEnv.getCourseResourceableId());
-		final RepositoryEntry re = RepositoryManager.getInstance().lookupRepositoryEntry(course, false);
-		// exists areas in course
-		boolean areaExists = false;
-		for (final Long oldId : mapIdName.keySet()) {
-			areaExists = false;
-			List<BGArea> areas = this.targetCourseEnv.getCourseGroupManager().getAllAreas();
-			for (final BGArea area : areas) {
-				if (area.getName().equals(mapIdName.get(oldId))) {
-					// group exists
-					areaExists = true;
-					oldIdNewIdMap.put(oldId, area.getKey());
-					break;
-				}
-			}
-
-			// if not exists then create areas
-			if (!areaExists) {
-				BGArea srcArea = null;
-				areas = this.srcCourseEnv.getCourseGroupManager().getAllAreas();
-				for (final BGArea area : areas) {
-					if (area.getName().equals(mapIdName.get(oldId))) {
-						// group exists
-						areaExists = true;
-						srcArea = area;
-						break;
-					}
-				}
-
-				if (areaExists) {
-					final BGArea newArea = areaManager.createAndPersistBGArea(srcArea.getName(), srcArea.getDescription(), re.getOlatResource());
-					oldIdNewIdMap.put(oldId, newArea.getKey());
-				}
-			}
+	
+	private void updateCondition(Condition preCondition) {
+		String easyModeNodePassedId = courseEnvMapper.getNodeTargetIdent(preCondition.getEasyModeNodePassedId());
+		if (easyModeNodePassedId != null) {
+			preCondition.setEasyModeNodePassedId(easyModeNodePassedId);
 		}
-		return oldIdNewIdMap;
-	}
-
-	protected void createAreas(final List<String> areaNames) {
-		// target
-		final ICourse targetCourse = CourseFactory.loadCourse(this.targetCourseEnv.getCourseResourceableId());
-		final OLATResource targetCourseResource = OLATResourceManager.getInstance().findOrPersistResourceable(targetCourse);
-		// source
-		final ICourse srcCourse = CourseFactory.loadCourse(this.srcCourseEnv.getCourseResourceableId());
-		final OLATResource srcCourseResource = OLATResourceManager.getInstance().findOrPersistResourceable(srcCourse);
-
-		if (targetCourseResource != null && srcCourseResource != null) {
-			// exists areas in course
-			boolean areaExists = false;
-			for (final String areaName : areaNames) {
-				areaExists = false;
-				List<BGArea> areas = this.targetCourseEnv.getCourseGroupManager().getAllAreas();
-				for (final BGArea area : areas) {
-					if (area.getName().equals(areaName)) {
-						// group exists
-						areaExists = true;
-						break;
-					}
-				}
-
-				// if not exists then create areas
-				if (!areaExists) {
-					areas = this.srcCourseEnv.getCourseGroupManager().getAllAreas();
-					for (final BGArea area : areas) {
-						if (area.getName().equals(areaName)) {
-							// group exists
-							areaExists = true;
-							break;
-						}
-					}
-
-					if (areaExists) {
-						areaManager.copyBGAreasOfResource(srcCourseResource, targetCourseResource);
-					}
-				}
-			}
+		if (preCondition.isExpertMode()) {
+			preCondition.setConditionExpression(
+					replaceIdsInCondition(preCondition.getConditionExpression()));
+		} else {
+			preCondition.setConditionExpression(
+					preCondition.getConditionFromEasyModeConfiguration());
 		}
 	}
 
-	@Override
-	public void updateNodeReferences(Map<String, String> nodeSrcTargetMapping) {
-		// Override/extend this function if your node references other nodes
+	protected String replaceIdsInCondition(String condition) {
 
-		if (nodeSrcTargetMapping.containsKey(srcCourseNode.getPreConditionAccess().getEasyModeNodePassedId())) {
-			targetCourseNode.getPreConditionAccess().setEasyModeNodePassedId(
-					nodeSrcTargetMapping.get(srcCourseNode.getPreConditionAccess().getEasyModeNodePassedId()));
-		}
+		condition = KeyAndNameConverter.convertExpressionKeyToKey(condition, courseEnvMapper);
 
-		if (nodeSrcTargetMapping.containsKey(srcCourseNode.getPreConditionVisibility().getEasyModeNodePassedId())) {
-			targetCourseNode.getPreConditionVisibility().setEasyModeNodePassedId(
-					nodeSrcTargetMapping.get(srcCourseNode.getPreConditionVisibility().getEasyModeNodePassedId()));
+		for (String nodeSourceId : courseEnvMapper.getNodeSourceIds()) {
+			condition = condition.replaceAll(
+					"\"" + nodeSourceId + "\"",
+					"\"" + courseEnvMapper.getNodeTargetIdent(nodeSourceId) + "\"");
 		}
-
-		return;
+		return condition;
 	}
 
 }
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/BCCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/BCCourseNodeCopyConfigurator.java
index 26033843313..1fd17a37fc9 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/BCCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/BCCourseNodeCopyConfigurator.java
@@ -26,6 +26,7 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.util.FileUtils;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.BCCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -38,8 +39,9 @@ import org.olat.course.run.environment.CourseEnvironment;
 public class BCCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigurator {
 
 	public BCCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	@Override
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/COCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/COCourseNodeCopyConfigurator.java
index 0b40a7188bf..ccb988f533b 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/COCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/COCourseNodeCopyConfigurator.java
@@ -19,6 +19,7 @@ package de.bps.course.nodewizard.coursenode;
 
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.modules.ModuleConfiguration;
@@ -41,8 +42,9 @@ public class COCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	 * @param translator
 	 */
 	public COCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/DialogCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/DialogCourseNodeCopyConfigurator.java
index 3d979fab2d5..9e7b6d7fc2d 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/DialogCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/DialogCourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ package de.bps.course.nodewizard.coursenode;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.DialogCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -44,8 +45,9 @@ public class DialogCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConf
 	 * @param translator
 	 */
 	public DialogCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/ENCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/ENCourseNodeCopyConfigurator.java
index e80e3b90c98..ae0da7ad815 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/ENCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/ENCourseNodeCopyConfigurator.java
@@ -27,11 +27,18 @@ import java.util.Map;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
+import org.olat.core.util.StringHelper;
+import org.olat.course.export.CourseEnvironmentMapper;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.ENCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupService;
+import org.olat.group.area.BGArea;
+import org.olat.group.model.BGAreaReference;
+import org.olat.group.model.BusinessGroupEnvironment;
+import org.olat.group.model.BusinessGroupReference;
 import org.olat.modules.ModuleConfiguration;
 
 /**
@@ -52,107 +59,9 @@ public class ENCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	 * @param translator
 	 */
 	public ENCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
-	}
-
-	/**
-	 * @see de.bps.course.nodewizard.coursenode.AbstractCourseNodeCopyConfigurator#configure()
-	 */
-	@Override
-	public void configure() {
-		super.configure();
-
-		final ModuleConfiguration srcModulConfig = srcCourseNode.getModuleConfiguration();
-		final ModuleConfiguration targetModulConfig = targetCourseNode.getModuleConfiguration();
-
-		// configure group names
-		configureGroupNames(srcModulConfig);
-		// configure area names
-		configureAreaNames(srcModulConfig);
-		// configure ids
-		configureIds(srcModulConfig, targetModulConfig, true);
-		// configure area ids
-		configureIds(srcModulConfig, targetModulConfig, false);
-	}
-
-	/**
-	 * @param srcModulConfig
-	 */
-	private void configureAreaNames(final ModuleConfiguration srcModulConfig) {
-		final List<String> areaNames = new ArrayList<String>();
-		final String areaName = (String) srcModulConfig.get(ENCourseNode.CONFIG_AREANAME);
-		areaNames.add(areaName);
-		createAreas(areaNames);
-	}
-
-	/**
-	 * @param srcModulConfig
-	 */
-	private void configureGroupNames(final ModuleConfiguration srcModulConfig) {
-		final String groupName = (String) srcModulConfig.get(ENCourseNode.CONFIG_GROUPNAME);
-		// business group service
-		final BusinessGroupService businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
-		// exists groups in course
-		boolean groupExists = false;
-		List<BusinessGroup> businessGroups = this.targetCourseEnv.getCourseGroupManager().getAllBusinessGroups();
-		for (final BusinessGroup businessGroup : businessGroups) {
-			if (businessGroup.getName().equals(groupName)) {
-				// group exists
-				groupExists = true;
-				break;
-			}
-		}
-		if (!groupExists) {
-			BusinessGroup srcGroup = null;
-			businessGroups = this.srcCourseEnv.getCourseGroupManager().getAllBusinessGroups();
-			for (final BusinessGroup businessGroup : businessGroups) {
-				if (businessGroup.getName().equals(groupName)) {
-					// group exists
-					groupExists = true;
-					srcGroup = businessGroup;
-					break;
-				}
-			}
-
-			if (groupExists) {
-				businessGroupService.copyBusinessGroup(this.fallbackIdentity, srcGroup, srcGroup.getName(), srcGroup.getDescription(),
-						srcGroup.getMinParticipants(), srcGroup.getMaxParticipants(), true, false, true, false, false, true, false, false);
-			}
-		}
-	}
-
-	/**
-	 * @param srcModulConfig
-	 * @param targetModulConfig
-	 * @param isBusinessGroup
-	 */
-	private void configureIds(final ModuleConfiguration srcModulConfig, final ModuleConfiguration targetModulConfig, final boolean isBusinessGroup) {
-		final Map<Long, String> groupIds = new HashMap<Long, String>();
-		final Map<Long, Long> oldIdNewIds = new HashMap<Long, Long>();
-		if (isBusinessGroup) {
-			// is business group
-			@SuppressWarnings("unchecked")
-			final List<Long> groupKeys = (List<Long>) srcModulConfig.get(ENCourseNode.CONFIG_GROUP_IDS);
-			if (groupKeys != null) { 
-				for (final Long id : groupKeys) {
-					groupIds.put(id, "");
-				}
-			}
-			oldIdNewIds.putAll(createBusinessGroups(groupIds));
-			targetModulConfig.set(ENCourseNode.CONFIG_GROUP_IDS, new ArrayList<Long>(oldIdNewIds.values()));
-		} else {
-			// is area
-			@SuppressWarnings("unchecked")
-			final List<Long> areaKeys = (List<Long>) srcModulConfig.get(ENCourseNode.CONFIG_AREA_IDS);
-			if (areaKeys != null) { 
-				for (final Long id : areaKeys) {
-					groupIds.put(id, "");
-				}
-			}
-			oldIdNewIds.putAll(createAreas(groupIds));
-			targetModulConfig.set(ENCourseNode.CONFIG_AREA_IDS, new ArrayList<Long>(oldIdNewIds.values()));
-		}
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 }
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/FOCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/FOCourseNodeCopyConfigurator.java
index 22276d235f2..7a5872a93f5 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/FOCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/FOCourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ package de.bps.course.nodewizard.coursenode;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.FOCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -44,8 +45,9 @@ public class FOCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	 * @param translator
 	 */
 	public FOCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/GTACourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/GTACourseNodeCopyConfigurator.java
index 152d030a9b5..4ec9f327012 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/GTACourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/GTACourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.util.FileUtils;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.GTACourseNode;
 import org.olat.course.nodes.gta.GTAManager;
@@ -46,8 +47,9 @@ public class GTACourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigu
 	 * @param translator
 	 */
 	public GTACourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	@Override
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/ICourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/ICourseNodeCopyConfigurator.java
index 8a76b096a30..cd07669f741 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/ICourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/ICourseNodeCopyConfigurator.java
@@ -19,8 +19,6 @@
  */
 package de.bps.course.nodewizard.coursenode;
 
-import java.util.Map;
-
 /**
  * 
  * @author bja
@@ -30,6 +28,6 @@ public interface ICourseNodeCopyConfigurator {
 
 	void configure();
 
-	void updateNodeReferences(Map<String, String> nodeSrcTargetMapping);
+	void updateNodeReferences();
 
 }
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/InfoCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/InfoCourseNodeCopyConfigurator.java
index 7ea0c426e6f..94efa54f605 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/InfoCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/InfoCourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ package de.bps.course.nodewizard.coursenode;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.InfoCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -44,8 +45,9 @@ public class InfoCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfig
 	 * @param translator
 	 */
 	public InfoCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/LLCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/LLCourseNodeCopyConfigurator.java
index c0abb62e298..9128c54cacf 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/LLCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/LLCourseNodeCopyConfigurator.java
@@ -23,6 +23,7 @@ import java.util.List;
 
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
 import org.olat.modules.ModuleConfiguration;
@@ -45,8 +46,9 @@ public class LLCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	 * @param translator
 	 */
 	public LLCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	@Override
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/PortfolioCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/PortfolioCourseNodeCopyConfigurator.java
index d8af08b7d72..78da16a1572 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/PortfolioCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/PortfolioCourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ package de.bps.course.nodewizard.coursenode;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.PortfolioCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -44,8 +45,9 @@ public class PortfolioCourseNodeCopyConfigurator extends AbstractCourseNodeCopyC
 	 * @param translator
 	 */
 	public PortfolioCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/ProjectBrokerCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/ProjectBrokerCourseNodeCopyConfigurator.java
index bceb2834ea5..2eea68cf728 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/ProjectBrokerCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/ProjectBrokerCourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ package de.bps.course.nodewizard.coursenode;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.ProjectBrokerCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -43,10 +44,10 @@ public class ProjectBrokerCourseNodeCopyConfigurator extends AbstractCourseNodeC
 	 * @param canCopyToCourseFolder
 	 * @param translator
 	 */
-	public ProjectBrokerCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv,
-			final CourseEnvironment targetCourseEnv, final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder,
-			final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+	public ProjectBrokerCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/SPCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/SPCourseNodeCopyConfigurator.java
index 08fcc226483..27fef783a64 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/SPCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/SPCourseNodeCopyConfigurator.java
@@ -26,11 +26,13 @@ import java.nio.file.Paths;
 import java.util.regex.Pattern;
 
 import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
+import org.olat.core.gui.translator.PackageTranslator;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.vfs.MergeSource;
 import org.olat.core.util.vfs.VFSContainer;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.sp.SPEditController;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -42,11 +44,12 @@ import org.olat.course.run.environment.CourseEnvironment;
  */
 public class SPCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigurator {
 
-	public static final Integer FILE_RENAME_LIMIT = 20;
+	public static final Integer FILE_RENAME_LIMIT = 100;
 	
 	public SPCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	public static Path enhanceWithCopyPattern(final Path filePath, final String copyExtension ) {
@@ -63,10 +66,9 @@ public class SPCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	
 	private File enhancedFilenameIfExists(File origFile) {
 		File newFile = origFile;
-		Integer i = 0;
+		Integer i = 1;
 		while (newFile.exists() && i < FILE_RENAME_LIMIT) {
-			newFile = enhanceWithCopyPattern(origFile.toPath(), translator.translate("configurator.sp.copy.extension",
-					 new String[] {i > 0 ? i.toString() : ""})).toFile();
+			newFile = enhanceWithCopyPattern(origFile.toPath(), i.toString()).toFile();
 			i++;
 		}
 		return newFile;
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/STCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/STCourseNodeCopyConfigurator.java
index a796392b844..90573d26271 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/STCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/STCourseNodeCopyConfigurator.java
@@ -20,6 +20,7 @@ package de.bps.course.nodewizard.coursenode;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 import org.olat.core.gui.translator.Translator;
@@ -27,6 +28,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.id.Roles;
 import org.olat.course.condition.interpreter.ConditionInterpreter;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.STCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -41,8 +43,6 @@ import org.olat.course.run.userview.UserCourseEnvironmentImpl;
  */
 public class STCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigurator {
 
-	private ConditionInterpreter conditionInterpreter;
-	
 	/**
 	 * @param fallbackIdentity
 	 * @param srcCourseEnv
@@ -53,25 +53,14 @@ public class STCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	 * @param translator
 	 */
 	public STCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
-
-		Roles roles = new Roles(false, false, false, false, false, false, false);
-		IdentityEnvironment identityEnv = new IdentityEnvironment(fallbackIdentity, roles);
-		UserCourseEnvironment uce = new UserCourseEnvironmentImpl(identityEnv, targetCourseEnv);
-		conditionInterpreter = new ConditionInterpreter(uce);
-	}
-
-	private String replaceIdsInCondition(String condition, Map<String, String> mapping) {
-		for (Map.Entry<String, String> entry : mapping.entrySet()) {
-			condition = condition.replaceAll("\"" + entry.getKey() + "\"", "\"" + entry.getValue() + "\"");
-		}
-		return condition;
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	@Override
-	public void updateNodeReferences(Map<String, String> nodeSrcTargetMapping) {
-		super.updateNodeReferences(nodeSrcTargetMapping);
+	public void updateNodeReferences() {
+		super.updateNodeReferences();
 
 		STCourseNode srcNode = (STCourseNode) srcCourseNode;
 		STCourseNode targetNode = (STCourseNode) targetCourseNode;
@@ -79,8 +68,9 @@ public class STCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 		List<String> snodes = srcNode.getScoreCalculator().getSumOfScoreNodes();
 		if (snodes != null) {
 			targetNode.getScoreCalculator().setSumOfScoreNodes(
-				snodes.stream().filter(nodeSrcTargetMapping::containsKey)
-					.map(nodeSrcTargetMapping::get)
+				snodes.stream()
+					.map(courseEnvMapper::getNodeTargetIdent)
+					.filter(Objects::nonNull)
 					.collect(Collectors.toList()));
 			if (!targetNode.getScoreCalculator().isExpertMode()) {
 				targetNode.getScoreCalculator().setScoreExpression(
@@ -91,8 +81,9 @@ public class STCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 		List<String> spnodes = srcNode.getScoreCalculator().getPassedNodes();
 		if (spnodes != null) {
 			targetNode.getScoreCalculator().setPassedNodes(
-					spnodes.stream().filter(nodeSrcTargetMapping::containsKey)
-						.map(nodeSrcTargetMapping::get)
+					spnodes.stream()
+						.map(courseEnvMapper::getNodeTargetIdent)
+						.filter(Objects::nonNull)
 						.collect(Collectors.toList()));
 			if (!targetNode.getScoreCalculator().isExpertMode()) {
 				targetNode.getScoreCalculator().setPassedExpression(
@@ -101,13 +92,11 @@ public class STCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 		}
 
 		if (targetNode.getScoreCalculator().isExpertMode()) {
-			String passedExpression = replaceIdsInCondition(targetNode.getScoreCalculator().getPassedExpression(), nodeSrcTargetMapping);
-			conditionInterpreter.evaluateCondition(passedExpression);
-			targetNode.getScoreCalculator().setPassedExpression(passedExpression);
+			targetNode.getScoreCalculator().setPassedExpression(
+					replaceIdsInCondition(targetNode.getScoreCalculator().getPassedExpression()));
 			
-			String scoreExpression = replaceIdsInCondition(targetNode.getScoreCalculator().getScoreExpression(), nodeSrcTargetMapping);				
-			conditionInterpreter.evaluateCalculation(scoreExpression);
-			targetNode.getScoreCalculator().setScoreExpression(scoreExpression);			
+			targetNode.getScoreCalculator().setScoreExpression(
+					replaceIdsInCondition(targetNode.getScoreCalculator().getScoreExpression()));			
 		}
 		
 		return;
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/TACourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/TACourseNodeCopyConfigurator.java
index 3f3afb2f09c..e682abc48c5 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/TACourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/TACourseNodeCopyConfigurator.java
@@ -26,6 +26,7 @@ import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.util.FileUtils;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.TACourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -48,8 +49,9 @@ public class TACourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfigur
 	 * @param translator
 	 */
 	public TACourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	@Override
diff --git a/src/main/java/de/bps/course/nodewizard/coursenode/WikiCourseNodeCopyConfigurator.java b/src/main/java/de/bps/course/nodewizard/coursenode/WikiCourseNodeCopyConfigurator.java
index 75615b64a39..9b090d7441e 100644
--- a/src/main/java/de/bps/course/nodewizard/coursenode/WikiCourseNodeCopyConfigurator.java
+++ b/src/main/java/de/bps/course/nodewizard/coursenode/WikiCourseNodeCopyConfigurator.java
@@ -22,6 +22,7 @@ package de.bps.course.nodewizard.coursenode;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.course.condition.Condition;
+import org.olat.course.export.CourseFragmentEnvironmentMapper;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.WikiCourseNode;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -44,8 +45,9 @@ public class WikiCourseNodeCopyConfigurator extends AbstractCourseNodeCopyConfig
 	 * @param translator
 	 */
 	public WikiCourseNodeCopyConfigurator(final Identity fallbackIdentity, final CourseEnvironment srcCourseEnv, final CourseEnvironment targetCourseEnv,
-			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final boolean canCopyToCourseFolder, final Translator translator) {
-		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, canCopyToCourseFolder, translator);
+			final CourseNode srcCourseNode, final CourseNode targetCourseNode, final CourseFragmentEnvironmentMapper courseEnvironmentMapper,
+			final boolean canCopyToCourseFolder) {
+		super(fallbackIdentity, srcCourseEnv, targetCourseEnv, srcCourseNode, targetCourseNode, courseEnvironmentMapper, canCopyToCourseFolder);
 	}
 
 	/**
diff --git a/src/main/java/org/olat/course/export/CourseFragmentEnvironmentMapper.java b/src/main/java/org/olat/course/export/CourseFragmentEnvironmentMapper.java
new file mode 100644
index 00000000000..93b5aa60afc
--- /dev/null
+++ b/src/main/java/org/olat/course/export/CourseFragmentEnvironmentMapper.java
@@ -0,0 +1,55 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Original Author:
+ * Daniel Haag <at> uibk.ac.at
+ * <p>
+ */
+package org.olat.course.export;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import org.olat.course.export.CourseEnvironmentMapper;
+
+/**
+ * This subclass of CourseEnvironmentMapper is used when only a node subset is mapped
+ * resulting in new node identifiers for the nodes as they might be imported into a new
+ * course multiple times.
+ * 
+ * @author Daniel Haag
+ */
+public class CourseFragmentEnvironmentMapper extends CourseEnvironmentMapper {
+
+	private Map<String,String> courseNodeIdentMap;
+
+	public CourseFragmentEnvironmentMapper() {
+		super();
+		courseNodeIdentMap = new HashMap<>();
+	}
+	
+	public void addNodeIdentKeyPair(String sourceIdent, String targetIdent) {
+		courseNodeIdentMap.put(sourceIdent, targetIdent);
+	}
+	
+	public String getNodeTargetIdent(String sourceIdent) {
+		return courseNodeIdentMap.get(sourceIdent);
+	}
+	
+	public Set<String> getNodeSourceIds() {
+		return courseNodeIdentMap.keySet();
+	}
+}
diff --git a/src/test/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallbackTest.java b/src/test/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallbackTest.java
index c29a1a22a24..dca333c4e7d 100644
--- a/src/test/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallbackTest.java
+++ b/src/test/java/de/bps/course/nodewizard/CopyStructureWizardStepRunnerCallbackTest.java
@@ -98,13 +98,15 @@ public class CopyStructureWizardStepRunnerCallbackTest extends OlatTestCase {
 		List<INode> newTargetNodes = getFlatNodeListFromCourseNode(newTargetCourse.getRunStructure().getRootNode());
 		
 		selectedNodeIds.stream().forEach(
-			n -> assertTrue("Node ID " + n + " is present in mapping", stepRunnerCallback.getNodeSrcTargetMapping().containsKey(n))
+			n -> assertTrue("Node ID " + n + " is present in mapping", stepRunnerCallback.getCourseFragmentEnvironmentMapper()
+					.getNodeSourceIds().contains(n))
 		);
 
 		sourceNodes.stream().filter(n -> selectedNodeIds.contains(n.getIdent())).forEach(
-				x -> assertTrue("Node " + x.toString() + " is present in target course with ID " + stepRunnerCallback.getNodeSrcTargetMapping().get(x.getIdent()),
+				x -> assertTrue("Node " + x.toString() + " is present in target course with ID "
+								+ stepRunnerCallback.getCourseFragmentEnvironmentMapper().getNodeTargetIdent(x.getIdent()),
 						newTargetNodes.stream().anyMatch(
-								tn -> tn.getIdent().equals(stepRunnerCallback.getNodeSrcTargetMapping().get(x.getIdent()))
+								tn -> tn.getIdent().equals(stepRunnerCallback.getCourseFragmentEnvironmentMapper().getNodeTargetIdent(x.getIdent()))
 								)
 						)
 				);
-- 
GitLab