using Speckle.Automate.Sdk; using Speckle.Automate.Sdk.Schema; using Speckle.Core.Api; using Speckle.Core.Models; using Speckle.Core.Models.Extensions; using Speckle.Core.Transports; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SpeckleAutomateDotnetExample { internal class Utils { /// /// Receives a commit object from the same project and account as the /// /// The id of the commit to receive /// The Automation context /// /// public static async Task RecieveVersionAsync( string commitId, AutomationContext context ) { ServerTransport serverTransport = new ServerTransport( context.SpeckleClient.Account, context.AutomationRunData.ProjectId ); Base? receivedCommitObject = await Operations .Receive( ( await context.SpeckleClient .CommitGet(context.AutomationRunData.ProjectId, commitId) .ConfigureAwait(continueOnCapturedContext: false) ).referencedObject, serverTransport, new MemoryTransport() ) .ConfigureAwait(continueOnCapturedContext: false); if (receivedCommitObject == null) { throw new Exception("Commit root object was null"); } return receivedCommitObject; } /// /// Creates Dictionaries from a commit Base, using applicationId if available or speckle id if no applicationId exists. /// /// The commit Base to create dictionaries from /// The dictionary of commit objects sorted by applicationId /// The dictionary of commit objects without applicationIds, sorted by speckle id public static void CreateDictionaryFromBaseById( Base commit, out Dictionary> appIdDict, out Dictionary> speckleIdDict, out int objectCount ) { IEnumerable commitObjects = commit.Flatten(); objectCount = commitObjects.Count(); appIdDict = new Dictionary>(); speckleIdDict = new Dictionary>(); foreach (var commitObject in commitObjects) { if (!string.IsNullOrWhiteSpace(commitObject.applicationId)) { if (appIdDict.ContainsKey(commitObject.applicationId)) { appIdDict[commitObject.applicationId].Add(commitObject); } else { appIdDict.Add( commitObject.applicationId, new List() { commitObject } ); } } else if (!string.IsNullOrWhiteSpace(commitObject.id)) { if (speckleIdDict.ContainsKey(commitObject.id)) { speckleIdDict[commitObject.id].Add(commitObject); } else { speckleIdDict.Add(commitObject.id, new List() { commitObject }); } } } } /// /// Filters two lists by removing all objects from with a matching speckle id in /// /// The list to filter /// The list to filter against /// A list of matches found in public static List> FilterListsBySpeckleIdMatch( List setA, List setB ) { var matches = new List>(); for (int i = setA.Count - 1; i >= 0; i--) { var testObject = setA[i]; for (int j = setB.Count - 1; j >= 0; j--) { var releaseObject = setB[j]; // if a match was found, remove from both lists and add to matches if (testObject.id == releaseObject.id) { matches.Add( new Tuple( testObject.id, testObject.applicationId, testObject.speckle_type ) ); setA.RemoveAt(i); setB.RemoveAt(j); } } } return matches; } /// /// Compares the properties of against /// /// /// /// Properties on that do not exist on /// Properties on that do not exist on /// Properties on that have a different value on . The second string is the category of modification (eg count/primitive/base) public static void CompareBaseProperties( Base a, Base b, out List addedProps, out List deletedProps, out List> modifiedProps ) { addedProps = new List(); deletedProps = new List(); modifiedProps = new List>(); Dictionary bObjectPropDict = b.GetMembers(); Dictionary aObjectPropDict = a.GetMembers(); foreach (KeyValuePair entry in aObjectPropDict) { if (bObjectPropDict.ContainsKey(entry.Key)) { bool changed = !IsEqual( entry.Value, bObjectPropDict[entry.Key], out string category ); if (changed) { modifiedProps.Add(new Tuple(entry.Key, category)); } bObjectPropDict.Remove(entry.Key); } else { addedProps.Add(entry.Key); } } // check if there are any props left on the b - these were missing in the a foreach (var entry in bObjectPropDict) { deletedProps.Add(entry.Key); } } /// /// Determines equality between two objects /// /// /// /// /// The category of the modification, if objects are not equal /// public static bool IsEqual(T a, T b, out string category) { category = "Value"; switch (a) { case Base aBase: if (b is Base bBase && bBase.speckle_type == aBase.speckle_type) { return aBase.id == bBase.id; } else { category = "Type"; return false; } case List aList: if (b is List bList) { if (aList.Count != bList.Count) { category = "Count"; return false; } for (int i = 0; i < aList.Count; i++) { if (!Equals(aList[i], bList[i])) { return false; } } return true; } else { category = "Type"; return false; } case Dictionary aDictionary: if (b is Dictionary bDictionary) { if (aDictionary.Count != bDictionary.Count) { category = "Count"; return false; } foreach (var entry in aDictionary) { if ( !bDictionary.ContainsKey(entry.Key) || !Equals(entry.Value, bDictionary[entry.Key]) ) { return false; } } return true; } else { category = "Type"; return false; } default: try { return EqualityComparer.Default.Equals(a, b); } catch { return false; } } } } }