internal override PropagationMacroCommand PrePropagation()
        {
            List <PSMAssociation> list = Project.TranslateComponent <PIMAssociation>(AssociationGuid).GetInterpretedComponents().Cast <PSMAssociation>().ToList <PSMAssociation>();

            if (list.Count == 0)
            {
                return(null);
            }

            PropagationMacroCommand command = new PropagationMacroCommand(Controller);

            command.Report = new CommandReport("Pre-propagation (delete PIM association)");

            if (list.Count > 0)
            {
                List <PSMAssociation> list2 = new List <PSMAssociation>(list);
                foreach (PSMAssociation a1 in list2)
                {
                    foreach (PSMAssociation a2 in list2)
                    {
                        if (a1.IsDescendantFrom(a2))
                        {
                            list.Remove(a1);
                        }
                    }
                }

                foreach (PSMAssociation a in list)
                {
                    cmdDeletePSMAssociation d = new cmdDeletePSMAssociation(Controller)
                    {
                        Propagate = false
                    };
                    d.Set(a);
                    command.Commands.Add(d);
                }
            }

            return(command);
        }
        internal override PropagationMacroCommand PrePropagation()
        {
            PropagationMacroCommand command = new PropagationMacroCommand(Controller);

            command.Report = new CommandReport("Pre-propagation (reconnect PIM association end)");

            PIMAssociationEnd assocEnd    = Project.TranslateComponent <PIMAssociationEnd>(associationEndGuid);
            PIMClass          targetClass = Project.TranslateComponent <PIMClass>(newClassGuid);
            PIMClass          sourceClass = assocEnd.PIMClass;

            IEnumerable <PIMAssociation> pimAssociations         = targetClass.GetAssociationsWith(sourceClass);
            IEnumerable <PSMAssociation> interpretedAssociations = assocEnd.PIMAssociation.GetInterpretedComponents().Cast <PSMAssociation>().Where(a => a.ID != PropagateSource);

            foreach (PSMAssociation psmAssociation in interpretedAssociations)
            {
                if (psmAssociation.NearestInterpretedClass().Interpretation == sourceClass)
                // C1 => C2, C1 (intclass) source, C2 (its descendant) target //I(R')=R^(E2)
                {
                    //C'u
                    PSMClass intclass = psmAssociation.NearestInterpretedClass();

                    //C', it is a PSMClass because psmAssociation has interpretation
                    PSMClass child = psmAssociation.Child as PSMClass;

                    Debug.Assert(intclass.Interpretation == sourceClass, "Intclass != sourceclass");

                    bool           found             = false;
                    PSMAssociation parentAssociation = intclass.ParentAssociation;

                    foreach (PIMAssociation association in pimAssociations)
                    {
                        if (parentAssociation != null && parentAssociation.Interpretation == association)
                        {
                            //moving the association up in PSM
                            found = true;

                            Guid classGuid2 = Guid.NewGuid();
                            Guid assocGuid2 = Guid.NewGuid();

                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid2
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid2, child.Name));
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid2, child.Interpretation));
                            command.Commands.Add(new acmdSetRepresentedClass(Controller, classGuid2, child));
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, intclass, classGuid2, psmAssociation.Schema)
                            {
                                AssociationGuid = assocGuid2
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid2, psmAssociation.Interpretation.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid2, psmAssociation.Lower, psmAssociation.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid2, psmAssociation.InterpretedAssociationEnd, psmAssociation.Interpretation)
                            {
                                ForceExecute = true
                            });

                            if (psmAssociation.Parent != intclass)
                            {
                                command.Commands.Add(new cmdReconnectPSMAssociation(Controller)
                                {
                                    AssociationGuid = psmAssociation, NewParentGuid = intclass, Propagate = false
                                });
                            }

                            acmdSynchroPSMAssociations s = new acmdSynchroPSMAssociations(Controller)
                            {
                                Propagate = false
                            };
                            s.X1.Add(psmAssociation);
                            s.X2.Add(assocGuid2);
                            command.Commands.Add(s);

                            if (psmAssociation.Parent != intclass)
                            {
                                command.Commands.Add(new cmdReconnectPSMAssociation(Controller)
                                {
                                    AssociationGuid = psmAssociation, NewParentGuid = psmAssociation.Parent, Propagate = false
                                });
                            }

                            cmdReconnectPSMAssociation r = new cmdReconnectPSMAssociation(Controller)
                            {
                                Propagate = false
                            };
                            r.Set(assocGuid2, parentAssociation.NearestInterpretedClass());
                            command.Commands.Add(r);
                        }

                        //select nearest interpreted child PSM classes, whose parent association's interpretation is the PIM association through which we are moving the association
                        IEnumerable <PSMClass> children = intclass.InterpretedSubClasses().Where(pc => pc.Interpretation == targetClass && pc.ParentAssociation.Interpretation == association);
                        foreach (PSMClass childClass in children)
                        {
                            found = true;
                            Guid classGuid2 = Guid.NewGuid();
                            Guid assocGuid2 = Guid.NewGuid();

                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid2
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid2, child.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid2, child.Interpretation));
                            command.Commands.Add(new acmdSetRepresentedClass(Controller, classGuid2, child));
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, intclass, classGuid2, psmAssociation.Schema)
                            {
                                AssociationGuid = assocGuid2
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid2, psmAssociation.Interpretation.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid2, psmAssociation.Lower, psmAssociation.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid2, psmAssociation.InterpretedAssociationEnd, psmAssociation.Interpretation)
                            {
                                ForceExecute = true
                            });

                            if (psmAssociation.Parent != intclass)
                            {
                                command.Commands.Add(new cmdReconnectPSMAssociation(Controller)
                                {
                                    AssociationGuid = psmAssociation, NewParentGuid = intclass, Propagate = false
                                });
                            }

                            acmdSynchroPSMAssociations s = new acmdSynchroPSMAssociations(Controller)
                            {
                                Propagate = false
                            };
                            s.X1.Add(psmAssociation);
                            s.X2.Add(assocGuid2);
                            command.Commands.Add(s);

                            if (psmAssociation.Parent != intclass)
                            {
                                command.Commands.Add(new cmdReconnectPSMAssociation(Controller)
                                {
                                    AssociationGuid = psmAssociation, NewParentGuid = psmAssociation.Parent, Propagate = false
                                });
                            }

                            cmdReconnectPSMAssociation r = new cmdReconnectPSMAssociation(Controller)
                            {
                                Propagate = false
                            };
                            r.Set(assocGuid2, childClass);
                            command.Commands.Add(r);
                        }

                        if (!found)
                        {
                            Guid classGuid = Guid.NewGuid();
                            Guid assocGuid = Guid.NewGuid();

                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid, targetClass.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid, targetClass));
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, intclass, classGuid, psmAssociation.Schema)
                            {
                                AssociationGuid = assocGuid
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid, association.Name)
                            {
                                Propagate = false
                            });
                            PIMAssociationEnd e = targetClass.PIMAssociationEnds.Single <PIMAssociationEnd>(aend => aend.PIMAssociation == association);
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid, e.Lower, e.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid, e, association)
                            {
                                ForceExecute = true
                            });

                            Guid classGuid2 = Guid.NewGuid();
                            Guid assocGuid2 = Guid.NewGuid();

                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid2
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid2, child.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid2, child.Interpretation));
                            command.Commands.Add(new acmdSetRepresentedClass(Controller, classGuid2, child));
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, intclass, classGuid2, psmAssociation.Schema)
                            {
                                AssociationGuid = assocGuid2
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid2, psmAssociation.Interpretation.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid2, psmAssociation.Lower, psmAssociation.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid2, psmAssociation.InterpretedAssociationEnd, psmAssociation.Interpretation)
                            {
                                ForceExecute = true
                            });

                            if (psmAssociation.Parent != intclass)
                            {
                                command.Commands.Add(new cmdReconnectPSMAssociation(Controller)
                                {
                                    AssociationGuid = psmAssociation, NewParentGuid = intclass, Propagate = false
                                });
                            }

                            acmdSynchroPSMAssociations s = new acmdSynchroPSMAssociations(Controller)
                            {
                                Propagate = false
                            };
                            s.X1.Add(psmAssociation);
                            s.X2.Add(assocGuid2);
                            command.Commands.Add(s);

                            if (psmAssociation.Parent != intclass)
                            {
                                command.Commands.Add(new cmdReconnectPSMAssociation(Controller)
                                {
                                    AssociationGuid = psmAssociation, NewParentGuid = psmAssociation.Parent, Propagate = false
                                });
                            }

                            cmdReconnectPSMAssociation r = new cmdReconnectPSMAssociation(Controller)
                            {
                                Propagate = false
                            };
                            r.Set(assocGuid2, classGuid);
                            command.Commands.Add(r);
                        }
                    }
                    //delete association
                    cmdDeletePSMAssociation d = new cmdDeletePSMAssociation(Controller)
                    {
                        Propagate = false
                    };
                    d.Set(psmAssociation);
                    command.Commands.Add(d);
                }
                else
                // C1 => C2, C2 source, C1 target
                {
                    //C'
                    PSMClass intclass = psmAssociation.NearestInterpretedClass();

                    //C'u, it is a PSMClass because psmAssociation has interpretation
                    PSMClass child = psmAssociation.Child as PSMClass;

                    Debug.Assert(child.Interpretation == sourceClass, "Child != sourceclass");

                    foreach (PIMAssociation association in pimAssociations)
                    {
                        //The case that C'v would be an ancestor of intclass does not apply here

                        //select nearest interpreted child PSM classes, whose parent association's interpretation is the PIM association through which we are moving the association
                        Dictionary <Guid, Guid> children = new Dictionary <Guid, Guid>();
                        foreach (PSMClass ch in intclass.InterpretedSubClasses().Where(pc => pc.Interpretation == sourceClass && pc.ParentAssociation.Interpretation == association))
                        {
                            children.Add(ch, ch.ParentAssociation);
                        }
                        if (children.Count() == 0)
                        {
                            Guid classGuid = Guid.NewGuid();
                            Guid assocGuid = Guid.NewGuid();

                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid, targetClass.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid, targetClass));
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, psmAssociation.Child, classGuid, psmAssociation.Schema)
                            {
                                AssociationGuid = assocGuid
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid, association.Name)
                            {
                                Propagate = false
                            });
                            PIMAssociationEnd e = targetClass.PIMAssociationEnds.Single(aend => aend.PIMAssociation == association);
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid, e.Lower, e.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid, e, association)
                            {
                                ForceExecute = true
                            });
                            children.Add(classGuid, assocGuid);
                        }

                        foreach (KeyValuePair <Guid, Guid> p in children)
                        {
                            Guid classGuid = Guid.NewGuid();
                            Guid assocGuid = Guid.NewGuid();

                            //C'_
                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid, intclass.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid, intclass.Interpretation));
                            //command.Commands.Add(new acmdSetRepresentedClass(Controller, classGuid, intclass));
                            //R'_
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, child, classGuid, psmAssociation.Schema)
                            {
                                AssociationGuid = assocGuid
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid, psmAssociation.Interpretation.Name)
                            {
                                Propagate = false
                            });
                            PIMAssociationEnd e1 = (psmAssociation.Interpretation as PIMAssociation).PIMAssociationEnds.Single(aend => aend.PIMClass == intclass.Interpretation);
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid, e1.Lower, e1.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid, e1, psmAssociation.Interpretation)
                            {
                                ForceExecute = true
                            });
                            acmdSynchroPSMAssociations s = new acmdSynchroPSMAssociations(Controller)
                            {
                                Propagate = false, ForceExecute = true
                            };
                            s.X1.Add(psmAssociation);
                            s.X2.Add(assocGuid);
                            command.Commands.Add(s);

                            cmdReconnectPSMAssociation r = new cmdReconnectPSMAssociation(Controller)
                            {
                                Propagate = false
                            };
                            r.Set(assocGuid, p.Key);
                            command.Commands.Add(r);

                            Guid classGuid3 = Guid.NewGuid();
                            Guid assocGuid3 = Guid.NewGuid();

                            //Cu'^_
                            command.Commands.Add(new acmdNewPSMClass(Controller, psmAssociation.Schema)
                            {
                                ClassGuid = classGuid3
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, classGuid3, child.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMClassInterpretation(Controller, classGuid3, child.Interpretation));
                            command.Commands.Add(new acmdSetRepresentedClass(Controller, classGuid3, child)
                            {
                                Propagate = false
                            });

                            //Rx'^_
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, p.Key, classGuid3, psmAssociation.PSMSchema)
                            {
                                AssociationGuid = assocGuid3
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid3, association.Name)
                            {
                                Propagate = false
                            });
                            PIMAssociationEnd e2 = association.PIMAssociationEnds.Single(aend => aend.PIMClass == sourceClass);
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid3, e2.Lower, e2.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid3, e2, association)
                            {
                                ForceExecute = true
                            });

                            acmdSynchroPSMAssociations s2 = new acmdSynchroPSMAssociations(Controller)
                            {
                                Propagate = false
                            };
                            s2.X1.Add(p.Value);
                            s2.X2.Add(assocGuid3);
                            command.Commands.Add(s2);

                            cmdDeletePSMAssociation d0 = new cmdDeletePSMAssociation(Controller)
                            {
                                Propagate = false
                            };
                            d0.Set(p.Value);
                            command.Commands.Add(d0);

                            //R'^_
                            Guid assocGuid4 = Guid.NewGuid();
                            command.Commands.Add(new acmdNewPSMAssociation(Controller, psmAssociation.Parent, p.Key, psmAssociation.PSMSchema)
                            {
                                AssociationGuid = assocGuid4
                            });
                            command.Commands.Add(new acmdRenameComponent(Controller, assocGuid4, psmAssociation.Interpretation.Name)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdUpdatePSMAssociationCardinality(Controller, assocGuid4, assocEnd.Lower, assocEnd.Upper)
                            {
                                Propagate = false
                            });
                            command.Commands.Add(new acmdSetPSMAssociationInterpretation(Controller, assocGuid4, assocEnd, psmAssociation.Interpretation)
                            {
                                ForceExecute = true
                            });

                            acmdSynchroPSMAssociations s3 = new acmdSynchroPSMAssociations(Controller)
                            {
                                Propagate = false
                            };
                            s3.X1.Add(assocGuid);
                            s3.X2.Add(assocGuid4);
                            command.Commands.Add(s3);

                            cmdDeletePSMAssociation d2 = new cmdDeletePSMAssociation(Controller)
                            {
                                Propagate = false
                            };
                            d2.Set(assocGuid);
                            command.Commands.Add(d2);

                            cmdDeleteRootPSMClass d3 = new cmdDeleteRootPSMClass(Controller)
                            {
                                Propagate = false
                            };
                            d3.Set(classGuid);
                            command.Commands.Add(d3);
                        }
                    }
                    //delete association
                    cmdDeletePSMAssociation d = new cmdDeletePSMAssociation(Controller)
                    {
                        Propagate = false
                    };
                    d.Set(psmAssociation);
                    command.Commands.Add(d);
                }
            }

            command.CheckFirstOnlyInCanExecute = true;
            return(command);
        }