Ejemplo n.º 1
0
        private void MapEntities <T>(AssetCompositeHierarchyData <EntityDesign, Entity> hierarchyData, Dictionary <GroupPartKey, T> entities, Guid?instancePartIdArg = null) where T : EntityEntry
        {
            if (hierarchyData == null)
            {
                return;
            }

            // Important, if the hierarchy is coming from a part, we need to clone it entirely
            // and associate correctly the instancePartId with each entities that it is composed of.
            if (instancePartIdArg.HasValue)
            {
                hierarchyData = (AssetCompositeHierarchyData <EntityDesign, Entity>)AssetCloner.Clone(hierarchyData);
            }


            foreach (var entityDesign in hierarchyData.Parts)
            {
                if (instancePartIdArg.HasValue)
                {
                    entityDesign.BasePartInstanceId = instancePartIdArg;
                }

                var key = new GroupPartKey(instancePartIdArg, entityDesign.Entity.Id);

                if (entities.ContainsKey(key))
                {
                    continue;
                }

                EntityEntry remap;
                if (typeof(T) == typeof(NewEntityEntry))
                {
                    remap = new NewEntityEntry(entityDesign, hierarchyData, entities.Count);
                }
                else if (typeof(T) == typeof(BaseEntityEntry))
                {
                    remap = new BaseEntityEntry(entityDesign, hierarchyData, entities.Count);
                }
                else
                {
                    throw new ArgumentException($"Invalid type [{typeof(T)}]. Expecting concrete type NewEntityEntry or BaseEntityEntry");
                }

                entities[key] = (T)remap;
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Prepare the merge by computing internal dictionaries
        /// </summary>
        private void PrepareMerge()
        {
            // Process NewAsset
            MapEntities(newAsset.Hierarchy, newEntities);

            // Process BaseAsset
            MapEntities(baseAsset?.Hierarchy, baseEntities);
            if (newAsset.BaseParts != null)
            {
                foreach (var partItem in newAsset.GetBasePartInstanceIds())
                {
                    foreach (var groupPartId in partItem.Value)
                    {
                        // Because we have a groupPartId, it will clone the hierarchy so that
                        // we can safely merge instances later with NewEntity
                        MapEntities(partItem.Key.Hierarchy, baseEntities, groupPartId);
                    }
                }
            }

            // Process NewBaseAsset
            MapEntities(newBaseAsset?.Hierarchy, newBaseEntities);
            if (newBaseParts != null)
            {
                foreach (var partItem in newAsset.GetBasePartInstanceIds(newBaseParts))
                {
                    foreach (var groupPartId in partItem.Value)
                    {
                        // Because we have a groupPartId, it will clone the hierarchy so that
                        // we can safely merge instances later with NewEntity
                        MapEntities(partItem.Key.Hierarchy, newBaseEntities, groupPartId);
                    }
                }
            }

            // Compute Entities Added by newbase (not present in base)
            foreach (var entityFromNewBase in newBaseEntities)
            {
                var entityId = entityFromNewBase.Value.EntityDesign.Entity.Id;
                // For PartInstanceId key, we take it from the entityFromNewBase.Key
                var basePartInstanceId = entityFromNewBase.Key.PartInstanceId;
                var key = new GroupPartKey(basePartInstanceId, entityId);

                if (!baseEntities.ContainsKey(key))
                {
                    var tempHiearchy = new AssetCompositeHierarchyData <EntityDesign, Entity>();
                    tempHiearchy.Parts.Add(entityFromNewBase.Value.EntityDesign);

                    // The new entity added by the newbase
                    // Because we are cloning the entity, we need to restore children temporarely in order to clone them as well
                    entityFromNewBase.Value.PopChildren();
                    var newEntityDesign = ((AssetCompositeHierarchyData <EntityDesign, Entity>)AssetCloner.Clone(tempHiearchy)).Parts[0];
                    entityFromNewBase.Value.PushChildren();

                    var newId = Guid.NewGuid();
                    newEntityDesign.Entity.Id          = newId;
                    newEntityDesign.BaseId             = entityId;
                    newEntityDesign.BasePartInstanceId = basePartInstanceId;

                    // Because we are going to modify the NewBase we need to clone it
                    // We tag this entry as special, as we will have to process its children differently later in the merge hierarchy
                    var item = new NewEntityEntry(newEntityDesign, null, newEntities.Count)
                    {
                        IsNewBase = true
                    };

                    // Add this to the list of entities from newAsset
                    // Specific to the newEntities, GroupPartKey.PartInstanceId is always Guid.Empty
                    newEntities.Add(new GroupPartKey(null, newId), item);

                    // If the entity is coming from a part and is from root Entities, we need to add it to the rootEntities by default
                    if (basePartInstanceId.HasValue && entityFromNewBase.Value.Hierarchy.RootPartIds.Contains(entityId))
                    {
                        rootEntitiesToAdd.Add(newId);
                    }
                }
            }

            // Compute Entities Removed in newbase (present in base)
            foreach (var entityFromBase in baseEntities)
            {
                var entityId = entityFromBase.Value.EntityDesign.Entity.Id;
                var key      = new GroupPartKey(entityFromBase.Key.PartInstanceId, entityId);

                if (!newBaseEntities.ContainsKey(key))
                {
                    entitiesRemovedInNewBase.Add(entityId);
                }
            }

            // Compute the GUID -> index in list for RootEntities for Base and NewBase
            var baseRootEntities = new Dictionary <Guid, int>();

            if (baseAsset != null)
            {
                for (int i = 0; i < baseAsset.Hierarchy.RootPartIds.Count; i++)
                {
                    var id = baseAsset.Hierarchy.RootPartIds[i];
                    baseRootEntities.Add(id, i);
                }
            }
            var newBaseRootEntities = new Dictionary <Guid, int>();

            if (newBaseAsset != null)
            {
                for (int i = 0; i < newBaseAsset.Hierarchy.RootPartIds.Count; i++)
                {
                    var id = newBaseAsset.Hierarchy.RootPartIds[i];
                    newBaseRootEntities.Add(id, i);
                }
            }

            // Associate all NewEntity entries to their base
            foreach (var newEntityEntry in newEntities.ToList()) // use ToList so we can modify the dictionary while iterating
            {
                // Skip entities that don't have a base, as we don't have to do anything in the merge
                var entityDesign = newEntityEntry.Value.EntityDesign;
                if (!entityDesign.BaseId.HasValue)
                {
                    continue;
                }

                // Else we will associate entries
                var newEntity = entityDesign.Entity;
                var baseId    = entityDesign.BaseId.Value;
                var baseKey   = new GroupPartKey(entityDesign.BasePartInstanceId, baseId);

                BaseEntityEntry baseRemap;
                BaseEntityEntry newBaseRemap;
                baseEntities.TryGetValue(baseKey, out baseRemap);
                newBaseEntities.TryGetValue(baseKey, out newBaseRemap);

                // Link between base and new entity
                if (baseRemap != null)
                {
                    baseRemap.NewEntity = newEntityEntry.Value;
                }

                if (newBaseRemap != null)
                {
                    newBaseRemap.NewEntity = newEntityEntry.Value;
                }

                // Link the new entity to its base
                newEntityEntry.Value.Base    = baseRemap;
                newEntityEntry.Value.NewBase = newBaseRemap;

                if (entitiesRemovedInNewBase.Contains(baseId))
                {
                    entitiesToRemoveFromNew.Add(newEntity.Id);

                    // Else the entity has been removed
                    newEntities.Remove(newEntityEntry.Key);
                }
                else
                {
                    // Remap ids in the RootEntities for base
                    int index;
                    if (baseAsset != null && baseRootEntities.TryGetValue(baseId, out index))
                    {
                        baseRootEntities.Remove(baseId);
                        baseAsset.Hierarchy.RootPartIds[index] = newEntity.Id;
                    }

                    // Remap ids in the RootEntities for newBase
                    if (newBaseAsset != null && newBaseRootEntities.TryGetValue(baseId, out index))
                    {
                        newBaseRootEntities.Remove(baseId);
                        newBaseAsset.Hierarchy.RootPartIds[index] = newEntity.Id;
                    }
                }
            }

            // Uncomment the following code to dump the content of the different entities and how
            // they are remapped
            if (Debug)
            {
                System.Diagnostics.Debug.WriteLine(string.Empty);
                System.Diagnostics.Debug.WriteLine("**********************************");
                System.Diagnostics.Debug.WriteLine($"Merge Entity [{debugLocation}] => {newAsset.Id} Base: {baseAsset?.Id}");
                System.Diagnostics.Debug.WriteLine("==================================");
                Dump("\n**********\nBase\n==========", baseEntities);
                Dump("\n**********\nNewBase\n==========", newBaseEntities);
                Dump("\n**********\nNew\n==========", newEntities);
            }
        }