// Intersect elements exported in this sync with cached elements.
            // Those out of the intersection set are either deleted or hidden
            // and need to be removed from cache.
            public void Purge(FDatasmithFacadeScene DatasmithScene, bool bInRecursive)
            {
                if (bInRecursive)
                {
                    // Call purge on linked docs first.
                    foreach (var Link in LinkedDocumentsCache.Values)
                    {
                        Link.Purge(DatasmithScene, true);
                    }
                }

                List <ElementId> ElementsToRemove = new List <ElementId>();

                foreach (var ElemId in CachedElements.Keys)
                {
                    if (!ExportedElements.Contains(ElemId))
                    {
                        ElementsToRemove.Add(ElemId);
                    }
                }

                // Apply deletions according to the accumulated sets of elements.
                foreach (var ElemId in ElementsToRemove)
                {
                    if (!CachedElements.ContainsKey(ElemId))
                    {
                        continue;
                    }
                    FDocumentData.FBaseElementData ElementData = CachedElements[ElemId];
                    CachedElements.Remove(ElemId);
                    ElementData.Parent?.ChildElements.Remove(ElementData);
                    DatasmithScene.RemoveActor(ElementData.ElementActor);
                }
            }
 public void CacheElement(Document InDocument, Element InElement, FDocumentData.FBaseElementData InElementData)
 {
     if (!CurrentCache.CachedElements.ContainsKey(InElement.Id))
     {
         CurrentCache.CachedElements[InElement.Id] = InElementData;
         CurrentCache.ElementsWithoutMetadata.Enqueue(new KeyValuePair <ElementId, FDocumentData.FBaseElementData>(InElement.Id, InElementData));
     }
 }
        void ExportMetadata()
        {
            int DelayExport      = 2000;                // milliseconds
            int ExportBatchSize  = 1000;                // After each batch is exported, the process will wait for DelayExport and resume (unless cancelled)
            int CurrentBatchSize = 0;

            Func <FCachedDocumentData, bool> AddElements = (FCachedDocumentData CacheData) =>
            {
                while (CacheData.ElementsWithoutMetadata.Count > 0)
                {
                    if (CurrentBatchSize == ExportBatchSize)
                    {
                        // Add some delay before exporting next batch.
                        CurrentBatchSize = 0;

                        // Send metadata to DirectLink.
                        DatasmithScene.BuildScene(SceneName);
                        DatasmithDirectLink.UpdateScene(DatasmithScene);

                        MetadataEvent.WaitOne(DelayExport);
                    }

                    if (MetadataCancelToken.IsCancellationRequested)
                    {
                        return(false);
                    }

                    var Entry = CacheData.ElementsWithoutMetadata.Dequeue();

                    // Handle the case where element might be deleted in the main export path.
                    if (!CacheData.CachedElements.ContainsKey(Entry.Key))
                    {
                        continue;
                    }

                    Element RevitElement = CacheData.SourceDocument.GetElement(Entry.Key);

                    if (RevitElement == null)
                    {
                        continue;
                    }

                    FDocumentData.FBaseElementData ElementData = Entry.Value;
                    FDatasmithFacadeActor          Actor       = ElementData.ElementActor;

                    ElementData.ElementMetaData = new FDatasmithFacadeMetaData(Actor.GetName() + "_DATA");
                    ElementData.ElementMetaData.SetLabel(Actor.GetLabel());
                    ElementData.ElementMetaData.SetAssociatedElement(Actor);

                    FDocumentData.AddActorMetadata(RevitElement, ElementData.ElementMetaData);

                    ++CurrentBatchSize;

#if DEBUG
                    Debug.WriteLine($"metadata batch element {CurrentBatchSize}, remain in Q {CacheData.ElementsWithoutMetadata.Count}");
#endif
                }

                return(true);
            };

            List <FCachedDocumentData> CachesToExport = new List <FCachedDocumentData>();

            Action <FCachedDocumentData> GetLinkedDocuments = null;

            GetLinkedDocuments = (FCachedDocumentData InParent) =>
            {
                CachesToExport.Add(InParent);
                foreach (var Cache in InParent.LinkedDocumentsCache.Values)
                {
                    GetLinkedDocuments(Cache);
                }
            };

            GetLinkedDocuments(RootCache);

            foreach (var Cache in CachesToExport)
            {
                bool Success = AddElements(Cache);
                if (!Success)
                {
#if DEBUG
                    Debug.WriteLine("metadata cancelled");
#endif
                    return;                     // Metadata export was cancelled.
                }
            }

            if (CurrentBatchSize > 0)
            {
                // Send remaining chunk of metadata.
                DatasmithScene.BuildScene(SceneName);
                DatasmithDirectLink.UpdateScene(DatasmithScene);
            }

#if DEBUG
            Debug.WriteLine("metadata exported");
#endif
        }
 public FDocumentData.FBaseElementData GetCachedElement(Element InElement)
 {
     FDocumentData.FBaseElementData Result = null;
     CurrentCache.CachedElements.TryGetValue(InElement.Id, out Result);
     return(Result);
 }