diff --git a/Adaptation/.vscode/tasks.json b/Adaptation/.vscode/tasks.json index 81d3cea..19f4d04 100644 --- a/Adaptation/.vscode/tasks.json +++ b/Adaptation/.vscode/tasks.json @@ -60,6 +60,26 @@ "command": "code ../EC.csproj", "problemMatcher": [] }, + { + "label": "Readme", + "type": "shell", + "command": "code ../README.md", + "problemMatcher": [] + }, + { + "label": "File-Folder-Helper AOT s X Day-Helper-2025-03-20", + "type": "shell", + "command": "L:/DevOps/Mesa_FI/File-Folder-Helper/bin/Release/net8.0/win-x64/publish/File-Folder-Helper.exe", + "args": [ + "s", + "X", + "L:/DevOps/EAF-Mesa-Integration/EC", + "Day-Helper-2025-03-20", + "false", + "4" + ], + "problemMatcher": [] + }, { "label": "Git Config", "type": "shell", diff --git a/Adaptation/EC.Tests.csproj b/Adaptation/EC.Tests.csproj index f85e4a7..0edcaad 100644 --- a/Adaptation/EC.Tests.csproj +++ b/Adaptation/EC.Tests.csproj @@ -67,7 +67,7 @@ - NU1701 + NU1701 diff --git a/Adaptation/FileHandlers/CellInstanceConnectionName.cs b/Adaptation/FileHandlers/CellInstanceConnectionName.cs index 8f78c68..06537cc 100644 --- a/Adaptation/FileHandlers/CellInstanceConnectionName.cs +++ b/Adaptation/FileHandlers/CellInstanceConnectionName.cs @@ -9,7 +9,7 @@ namespace Adaptation.FileHandlers; public class CellInstanceConnectionName { - internal static IFileRead Get(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, int? connectionCount) + internal static IFileRead Get(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, int? connectionCount) { IFileRead result = cellInstanceConnectionName switch { diff --git a/Adaptation/FileHandlers/MapEafDrives/FileRead.cs b/Adaptation/FileHandlers/MapEafDrives/FileRead.cs index b7ca935..59f1f09 100644 --- a/Adaptation/FileHandlers/MapEafDrives/FileRead.cs +++ b/Adaptation/FileHandlers/MapEafDrives/FileRead.cs @@ -18,7 +18,7 @@ public class FileRead : Shared.FileRead, IFileRead private readonly AppSettings _AppSettings; - public FileRead(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), true, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; diff --git a/Adaptation/FileHandlers/RijndaelEncryption/FileRead.cs b/Adaptation/FileHandlers/RijndaelEncryption/FileRead.cs index 286e994..24458e4 100644 --- a/Adaptation/FileHandlers/RijndaelEncryption/FileRead.cs +++ b/Adaptation/FileHandlers/RijndaelEncryption/FileRead.cs @@ -18,7 +18,7 @@ public class FileRead : Shared.FileRead, IFileRead private readonly AppSettings _AppSettings; - public FileRead(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), true, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; diff --git a/Adaptation/Shared/FileRead.cs b/Adaptation/Shared/FileRead.cs index f66b29b..49a4526 100644 --- a/Adaptation/Shared/FileRead.cs +++ b/Adaptation/Shared/FileRead.cs @@ -44,9 +44,9 @@ public class FileRead : Properties.IFileRead protected readonly string _CellInstanceConnectionNameBase; protected readonly Dictionary> _DummyRuns; protected readonly Dictionary _FileParameter; - protected readonly Dictionary> _StaticRuns; protected readonly string _ParameterizedModelObjectDefinitionType; protected readonly FileConnectorConfiguration _FileConnectorConfiguration; + protected readonly Dictionary> _StaticRuns; protected readonly IList _ModelObjectParameterDefinitions; bool Properties.IFileRead.IsEvent => _IsEvent; @@ -63,7 +63,147 @@ public class FileRead : Properties.IFileRead string Properties.IFileRead.CellInstanceConnectionName => _CellInstanceConnectionName; string Properties.IFileRead.ParameterizedModelObjectDefinitionType => _ParameterizedModelObjectDefinitionType; - public FileRead(IDescription description, bool isEvent, ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) + protected static string GetTupleFile(Logistics logistics, List descriptions, Properties.IScopeInfo scopeInfo, string duplicateDirectory, string duplicateFile) where T : Properties.IDescription + { + string result; + string rds; + string fileName; + string dateValue; + string rdsPlaceholder = "%RDS%"; + string mesEntityPlaceholder = "%MesEntity%"; + if (descriptions.Count == 0 || string.IsNullOrEmpty(descriptions[0].RDS)) + rds = logistics.MID; + else + rds = descriptions[0].RDS; + string[] segments = scopeInfo.FileName.Split(new string[] { "DateTime:" }, StringSplitOptions.RemoveEmptyEntries); + if (segments.Length == 0) + result = string.Concat(duplicateDirectory, @"\", scopeInfo.FileNameWithoutExtension.Replace(rdsPlaceholder, rds).Replace(mesEntityPlaceholder, logistics.MesEntity)); + else + { + segments = segments[1].Split('%'); + string datePlaceholder = "%DateTime%"; + dateValue = logistics.DateTimeFromSequence.ToString(segments[0]); + foreach (string segment in scopeInfo.FileName.Split('%')) + { + if (!segment.Contains(segments[0])) + continue; + datePlaceholder = string.Concat('%', segment, '%'); + } + fileName = scopeInfo.FileName.Replace(rdsPlaceholder, rds).Replace(mesEntityPlaceholder, logistics.MesEntity).Replace(datePlaceholder, dateValue); + if (!duplicateFile.Contains("Viewer")) + result = Path.Combine(duplicateDirectory, fileName); + else + result = Path.Combine(duplicateDirectory, $"Viewer_{fileName}"); + } + if (result.Contains('%')) + throw new Exception("Placeholder exists!"); + return result; + } + + protected void WaitForFileConsumption(string sourceDirectoryCloaking, Logistics logistics, DateTime dateTime, List descriptions, string successDirectory, string duplicateDirectory, string duplicateFile, List<(Properties.IScopeInfo, string)> collection) where T : Properties.IDescription + { + bool check; + long preWait; + string tupleFile; + string tupleFileName = string.Empty; + List duplicateFiles = new(); + StringBuilder stringBuilder = new(); + List consumedFileIndices = new(); + bool moreThanAnHour = _BreakAfterSeconds > 3600; + long breakAfter = dateTime.AddSeconds(_BreakAfterSeconds).Ticks; + if (_FileConnectorConfiguration?.FileHandleWaitTime is null) + preWait = dateTime.AddMilliseconds(1234).Ticks; + else + preWait = dateTime.AddMilliseconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; + if (collection.Count == 0) + duplicateFiles.Add(duplicateFile); + string fileName = Path.GetFileNameWithoutExtension(logistics.ReportFullPath); + string successFile = string.Concat(successDirectory, @"\", Path.GetFileName(logistics.ReportFullPath)); + foreach ((Properties.IScopeInfo scopeInfo, string text) in collection) + { + if (scopeInfo.FileName.StartsWith(@"\")) + tupleFile = scopeInfo.FileName; + else if (!scopeInfo.FileName.Contains('%')) + tupleFile = string.Concat(duplicateDirectory, @"\", fileName, "_", scopeInfo.FileNameWithoutExtension, ".pdsfc"); + else + tupleFile = GetTupleFile(logistics, descriptions, scopeInfo, duplicateDirectory, duplicateFile); + tupleFileName = Path.GetFileNameWithoutExtension(tupleFile).Split('.')[0]; + duplicateFiles.Add(tupleFile); + if (_IsEAFHosted) + File.WriteAllText(tupleFile, text); + } + for (short i = 0; i < short.MaxValue; i++) + { + if (DateTime.Now.Ticks > preWait) + break; + Thread.Sleep(100); + } + if (!moreThanAnHour) + { + for (short z = 0; z < short.MaxValue; z++) + { + try + { + check = string.IsNullOrEmpty(successDirectory) || File.Exists(successFile); + if (check) + { + consumedFileIndices.Clear(); + for (int i = 0; i < duplicateFiles.Count; i++) + { + if (!File.Exists(duplicateFiles[i])) + { + if (string.IsNullOrEmpty(tupleFileName)) + consumedFileIndices.Add(i); + else if (duplicateFiles.All(l => Path.GetFileNameWithoutExtension(l).Split('.')[0] == tupleFileName)) + { + for (int j = 0; j < duplicateFiles.Count; j++) + consumedFileIndices.Add(j); + } + else + consumedFileIndices.Add(i); + } + } + if (consumedFileIndices.Count == duplicateFiles.Count) + break; + } + } + catch (Exception) { } + if (DateTime.Now.Ticks > breakAfter) + { + for (int i = 0; i < duplicateFiles.Count; i++) + { + if (File.Exists(duplicateFiles[i])) + { + try + { File.Delete(duplicateFiles[i]); } + catch (Exception) { } + _ = stringBuilder.Append('<').Append(duplicateFiles[i]).Append("> "); + } + } + throw new Exception(string.Concat("After {", _BreakAfterSeconds, "} seconds, right side of {", sourceDirectoryCloaking, "} didn't consume file(s) ", stringBuilder)); + } + Thread.Sleep(250); + } + } + } + + protected void WaitForFileConsumption(DateTime dateTime, List descriptions, bool isDummyRun, string successDirectory, string duplicateDirectory, List<(Properties.IScopeInfo, string)> collection, string duplicateFile) where T : Properties.IDescription + { + if (!isDummyRun && _IsEAFHosted) + WaitForFileConsumption(_FileConnectorConfiguration.SourceDirectoryCloaking, _Logistics, dateTime, descriptions, successDirectory, duplicateDirectory, duplicateFile, collection); + else + { + long breakAfter = DateTime.Now.AddSeconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; + for (short i = 0; i < short.MaxValue; i++) + { + if (!_IsEAFHosted || DateTime.Now.Ticks > breakAfter) + break; + Thread.Sleep(500); + } + } + } + + public FileRead(IDescription description, bool isEvent, ISMTP smtp, Dictionary fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, Dictionary> dummyRuns, Dictionary> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) { _SMTP = smtp; _IsEvent = isEvent; @@ -160,10 +300,161 @@ public class FileRead : Properties.IFileRead return result; } + protected void UpdateLastTicksDuration(long ticksDuration) + { + if (ticksDuration < 50000000) + ticksDuration = 50000000; + _LastTicksDuration = (long)Math.Ceiling(ticksDuration * .667); + _Log.Info($"{new TimeSpan(ticksDuration).TotalMilliseconds} TotalMillisecond(s) to process{Environment.NewLine}{_CellInstanceConnectionName}{Environment.NewLine}<{_ReportFullPath}>"); + } + + internal static string GetParentParent(string value) + { + string result = Path.GetDirectoryName(Path.GetDirectoryName(value)); + return result; + } + + internal static List GetDirectoryNames(string directory) + { +#nullable enable + List results = new(); + string? fileName; + string? checkDirectory = directory; + string? pathRoot = Path.GetPathRoot(directory); + string extension = Path.GetExtension(directory); + if (string.IsNullOrEmpty(pathRoot)) + throw new NullReferenceException(nameof(pathRoot)); + if (Directory.Exists(directory)) + { + fileName = Path.GetFileName(directory); + if (!string.IsNullOrEmpty(fileName)) + results.Add(fileName); + } + else if ((string.IsNullOrEmpty(extension) || extension.Length > 3) && !File.Exists(directory)) + { + fileName = Path.GetFileName(directory); + if (!string.IsNullOrEmpty(fileName)) + results.Add(fileName); + } + for (int i = 0; i < int.MaxValue; i++) + { + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == pathRoot) + break; + fileName = Path.GetFileName(checkDirectory); + if (string.IsNullOrEmpty(fileName)) + continue; + results.Add(fileName); + } + results.Add(pathRoot); + results.Reverse(); + return results; +#nullable disable + } + + internal static string GetJobIdParentDirectory(string directory) + { + string result; + if (!string.IsNullOrEmpty(Path.GetFileName(directory))) + result = Path.GetFullPath(GetParentParent(directory)); + else + result = Path.GetFullPath(GetParentParent(Path.GetDirectoryName(directory))); + if (!Directory.Exists(result)) + _ = Directory.CreateDirectory(result); + return result; + } + + internal static string GetFileNameAfterUnderscoreSplit(string reportFullPath) + { + string result; + string[] segments = Path.GetFileNameWithoutExtension(reportFullPath).Split('_'); + if (segments.Length <= 2) + result = segments[0]; + else + result = string.Concat(segments[0], segments[2]); + return result; + } + + internal string[] GetInProcessDirectory(string jobIdDirectory) + { + List results = new(); + if (!_IsEAFHosted) + results = new string[] { jobIdDirectory }.ToList(); + else + { + string[] files; + string logisticsSequence = _Logistics.Sequence.ToString(); + string[] directories = Directory.GetDirectories(jobIdDirectory, $"*{logisticsSequence}*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) + { + files = Directory.GetFiles(directory, "*", SearchOption.TopDirectoryOnly); + if (files.Length == 0) + continue; + results.Add(directory); + } + } + if ((results is null) || results.Count != 1) + throw new Exception("Didn't find directory by logistics sequence"); + return results.ToArray(); + } + + protected static string[] GetMatches(FileConnectorConfiguration fileConnectorConfiguration) + { + string[] segments; + string[] results = null; + foreach (string subSourceFileFilter in fileConnectorConfiguration.SourceFileFilters) + { + segments = subSourceFileFilter.Split('\\'); + if (fileConnectorConfiguration.IncludeSubDirectories.Value) + results = Directory.GetFiles(fileConnectorConfiguration.SourceFileLocation, segments.Last(), SearchOption.AllDirectories); + else + results = Directory.GetFiles(fileConnectorConfiguration.SourceFileLocation, segments.Last(), SearchOption.TopDirectoryOnly); + if (results.Length != 0) + break; + } + return results; + } + + protected static void NestExistingFiles(FileConnectorConfiguration fileConnectorConfiguration) + { + // if (!fileConnectorConfiguration.IncludeSubDirectories.Value && fileConnectorConfiguration.TriggerOnCreated is not null && fileConnectorConfiguration.TriggerOnCreated.Value) + if (!fileConnectorConfiguration.IncludeSubDirectories.Value) + { + string[] matches = GetMatches(fileConnectorConfiguration); + if (matches is not null && matches.Length > 0) + { + string fileName; + string nestedDirectory = Path.Combine(fileConnectorConfiguration.SourceFileLocation, DateTime.Now.Ticks.ToString()); + if (!Directory.Exists(nestedDirectory)) + _ = Directory.CreateDirectory(nestedDirectory); + foreach (string match in matches) + { + fileName = Path.GetFileName(match); + File.Move(match, Path.Combine(nestedDirectory, fileName)); + } + } + } + } + + protected static List GetDuplicatorDescriptions(JsonElement[] jsonElements) + { + List results = new(); + Duplicator.Description description; + JsonSerializerOptions jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString }; + foreach (JsonElement jsonElement in jsonElements) + { + if (jsonElement.ValueKind != JsonValueKind.Object) + throw new Exception(); + description = JsonSerializer.Deserialize(jsonElement.ToString(), jsonSerializerOptions); + results.Add(description); + } + return results; + } + protected static ModelObjectParameterDefinition[] GetProperties(string cellInstanceConnectionName, IList modelObjectParameters, string propertyNamePrefix) { ModelObjectParameterDefinition[] results = (from l in modelObjectParameters where l.Name.StartsWith(propertyNamePrefix) select l).ToArray(); - if (!results.Any()) + if (results.Length == 0) throw new Exception(cellInstanceConnectionName); return results; } @@ -171,17 +462,43 @@ public class FileRead : Properties.IFileRead protected static ModelObjectParameterDefinition[] GetProperties(string cellInstanceConnectionName, IList modelObjectParameters, string propertyNamePrefix, string propertyNameSuffix) { ModelObjectParameterDefinition[] results = (from l in modelObjectParameters where l.Name.StartsWith(propertyNamePrefix) && l.Name.EndsWith(propertyNameSuffix) select l).ToArray(); - if (!results.Any()) + if (results.Length == 0) throw new Exception(cellInstanceConnectionName); return results; } - protected void UpdateLastTicksDuration(long ticksDuration) + protected void SetFileParameter(string key, string value) { - if (ticksDuration < 50000000) - ticksDuration = 50000000; - _LastTicksDuration = (long)Math.Ceiling(ticksDuration * .667); - _Log.Info($"{new TimeSpan(ticksDuration).TotalMilliseconds} TotalMillisecond(s) to process{Environment.NewLine}{_CellInstanceConnectionName}{Environment.NewLine}<{_ReportFullPath}>"); + if (_FileConnectorConfiguration is null || _FileConnectorConfiguration.TargetFileLocation.Contains(string.Concat("%", key, "%")) || _FileConnectorConfiguration.ErrorTargetFileLocation.Contains(string.Concat("%", key, "%")) || _FileConnectorConfiguration.TargetFileName.Contains(string.Concat("%", key, "%")) || _FileConnectorConfiguration.ErrorTargetFileName.Contains(string.Concat("%", key, "%"))) + { + if (_FileParameter.ContainsKey(key)) + _FileParameter[key] = value; + else + _FileParameter.Add(key, value); + } + } + + protected void WritePDSF(IFileRead fileRead, JsonElement[] jsonElements) + { + string directory; + string day = $"{_Logistics.DateTimeFromSequence:yyyy-MM-dd}"; + string weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); + string weekDirectory = $"{_Logistics.DateTimeFromSequence:yyyy}_Week_{weekOfYear}"; + if (!_CellInstanceConnectionName.StartsWith(_CellInstanceName) && _CellInstanceConnectionNameBase == _EquipmentType) + directory = Path.Combine(_TracePath, _EquipmentType, "Target", weekDirectory, day, _CellInstanceName, _CellInstanceConnectionName); + else + directory = Path.Combine(_TracePath, _EquipmentType, "Source", weekDirectory, day, _CellInstanceName, _CellInstanceConnectionName); + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + string file = Path.Combine(directory, string.Concat(_Logistics.MesEntity, "_", _Logistics.Sequence, ".ipdsf")); + string lines = ProcessDataStandardFormat.GetPDSFText(fileRead, _Logistics, jsonElements, logisticsText: string.Empty); + File.WriteAllText(file, lines); + if (_Logistics.TotalSecondsSinceLastWriteTimeFromSequence > 600) + { + try + { File.SetLastWriteTime(file, _Logistics.DateTimeFromSequence); } + catch (Exception) { } + } } protected void WaitForThread(Thread thread, List threadExceptions) @@ -203,7 +520,7 @@ public class FileRead : Properties.IFileRead } lock (threadExceptions) { - if (threadExceptions.Any()) + if (threadExceptions.Count != 0) { foreach (Exception item in threadExceptions) _Log.Error(string.Concat(item.Message, Environment.NewLine, Environment.NewLine, item.StackTrace)); @@ -215,230 +532,6 @@ public class FileRead : Properties.IFileRead } } - private void WriteAllLines(string to, string[] exceptionLines) - { - string fileName = string.Concat(to, @"\readme.txt"); - try - { - if (!Directory.Exists(to)) - _ = Directory.CreateDirectory(to); - File.WriteAllLines(fileName, exceptionLines); - } - catch (Exception ex) { _Log.Error(ex.Message); } - } - - protected string[] Move(Tuple> extractResults, string to, string from, string resolvedFileLocation, Exception exception) - { - string[] results; - bool isErrorFile = exception is not null; - if (!to.EndsWith(@"\")) - _ = string.Concat(to, @"\"); - if (!isErrorFile) - results = Array.Empty(); - else - { - results = new string[] { _Logistics.Sequence.ToString(), _Logistics.ReportFullPath, from, resolvedFileLocation, to, string.Empty, string.Empty, exception.Message, string.Empty, string.Empty, exception.StackTrace }; - if (!_IsDuplicator) - WriteAllLines(to, results); - } - if (extractResults is not null && extractResults.Item4 is not null && extractResults.Item4.Any()) - { - string itemFile; - List directories = new(); - foreach (FileInfo sourceFile in extractResults.Item4) - { - if (sourceFile.FullName != _Logistics.ReportFullPath) - { - itemFile = sourceFile.FullName.Replace(from, to); - Shared1880(itemFile, directories, sourceFile, isErrorFile); - } - else if (!isErrorFile && _Logistics is not null) - Shared1811(to, sourceFile); - } - Shared0231(directories); - } - return results; - } - - protected static string GetTupleFile(Logistics logistics, List descriptions, Properties.IScopeInfo scopeInfo, string duplicateDirectory, string duplicateFile) where T : Properties.IDescription - { - string result; - string rds; - string fileName; - string dateValue; - string rdsPlaceholder = "%RDS%"; - string mesEntityPlaceholder = "%MesEntity%"; - if (!descriptions.Any() || string.IsNullOrEmpty(descriptions[0].RDS)) - rds = logistics.MID; - else - rds = descriptions[0].RDS; - string[] segments = scopeInfo.FileName.Split(new string[] { "DateTime:" }, StringSplitOptions.RemoveEmptyEntries); - if (segments.Length == 0) - result = string.Concat(duplicateDirectory, @"\", scopeInfo.FileNameWithoutExtension.Replace(rdsPlaceholder, rds).Replace(mesEntityPlaceholder, logistics.MesEntity)); - else - { - segments = segments[1].Split('%'); - string datePlaceholder = "%DateTime%"; - dateValue = logistics.DateTimeFromSequence.ToString(segments[0]); - foreach (string segment in scopeInfo.FileName.Split('%')) - { - if (!segment.Contains(segments[0])) - continue; - datePlaceholder = string.Concat('%', segment, '%'); - } - fileName = scopeInfo.FileName.Replace(rdsPlaceholder, rds).Replace(mesEntityPlaceholder, logistics.MesEntity).Replace(datePlaceholder, dateValue); - if (!duplicateFile.Contains("Viewer")) - result = Path.Combine(duplicateDirectory, fileName); - else - result = Path.Combine(duplicateDirectory, $"Viewer_{fileName}"); - } - if (result.Contains('%')) - throw new Exception("Placeholder exists!"); - return result; - } - - protected void WaitForFileConsumption(string sourceDirectoryCloaking, Logistics logistics, DateTime dateTime, List descriptions, string successDirectory, string duplicateDirectory, string duplicateFile, List<(Properties.IScopeInfo, string)> collection) where T : Properties.IDescription - { - bool check; - long preWait; - string tupleFile; - string tupleFileName = string.Empty; - List duplicateFiles = new(); - StringBuilder stringBuilder = new(); - List consumedFileIndices = new(); - bool moreThanAnHour = _BreakAfterSeconds > 3600; - long breakAfter = dateTime.AddSeconds(_BreakAfterSeconds).Ticks; - if (_FileConnectorConfiguration?.FileHandleWaitTime is null) - preWait = dateTime.AddMilliseconds(1234).Ticks; - else - preWait = dateTime.AddMilliseconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; - if (!collection.Any()) - duplicateFiles.Add(duplicateFile); - string fileName = Path.GetFileNameWithoutExtension(logistics.ReportFullPath); - string successFile = string.Concat(successDirectory, @"\", Path.GetFileName(logistics.ReportFullPath)); - foreach ((Properties.IScopeInfo scopeInfo, string text) in collection) - { - if (scopeInfo.FileName.StartsWith(@"\")) - tupleFile = scopeInfo.FileName; - else if (!scopeInfo.FileName.Contains('%')) - tupleFile = string.Concat(duplicateDirectory, @"\", fileName, "_", scopeInfo.FileNameWithoutExtension, ".pdsfc"); - else - tupleFile = GetTupleFile(logistics, descriptions, scopeInfo, duplicateDirectory, duplicateFile); - tupleFileName = Path.GetFileNameWithoutExtension(tupleFile).Split('.')[0]; - duplicateFiles.Add(tupleFile); - if (_IsEAFHosted) - File.WriteAllText(tupleFile, text); - } - for (short i = 0; i < short.MaxValue; i++) - { - if (DateTime.Now.Ticks > preWait) - break; - Thread.Sleep(100); - } - if (!moreThanAnHour) - { - for (short z = 0; z < short.MaxValue; z++) - { - try - { - check = string.IsNullOrEmpty(successDirectory) || File.Exists(successFile); - if (check) - { - consumedFileIndices.Clear(); - for (int i = 0; i < duplicateFiles.Count; i++) - { - if (!File.Exists(duplicateFiles[i])) - { - if (string.IsNullOrEmpty(tupleFileName)) - consumedFileIndices.Add(i); - else if (duplicateFiles.All(l => Path.GetFileNameWithoutExtension(l).Split('.')[0] == tupleFileName)) - { - for (int j = 0; j < duplicateFiles.Count; j++) - consumedFileIndices.Add(j); - } - else - consumedFileIndices.Add(i); - } - } - if (consumedFileIndices.Count == duplicateFiles.Count) - break; - } - } - catch (Exception) { } - if (DateTime.Now.Ticks > breakAfter) - { - for (int i = 0; i < duplicateFiles.Count; i++) - { - if (File.Exists(duplicateFiles[i])) - { - try - { File.Delete(duplicateFiles[i]); } - catch (Exception) { } - _ = stringBuilder.Append('<').Append(duplicateFiles[i]).Append("> "); - } - } - throw new Exception(string.Concat("After {", _BreakAfterSeconds, "} seconds, right side of {", sourceDirectoryCloaking, "} didn't consume file(s) ", stringBuilder)); - } - Thread.Sleep(250); - } - } - } - - protected void SetFileParameter(string key, string value) - { - if (_FileConnectorConfiguration is null || _FileConnectorConfiguration.TargetFileLocation.Contains(string.Concat("%", key, "%")) || _FileConnectorConfiguration.ErrorTargetFileLocation.Contains(string.Concat("%", key, "%")) || _FileConnectorConfiguration.TargetFileName.Contains(string.Concat("%", key, "%")) || _FileConnectorConfiguration.ErrorTargetFileName.Contains(string.Concat("%", key, "%"))) - { - if (_FileParameter.ContainsKey(key)) - _FileParameter[key] = value; - else - _FileParameter.Add(key, value); - } - } - - protected void SetFileParameterLotIDToLogisticsMID(bool includeLogisticsSequence = true) - { - string key; - if (!includeLogisticsSequence) - key = "LotID"; - else - key = "LotIDWithLogisticsSequence"; - string value = string.Concat(_Logistics.MID, "_", _Logistics.Sequence, "_", DateTime.Now.Ticks - _Logistics.Sequence); - SetFileParameter(key, value); - } - - protected void SetFileParameterLotID(string value, bool includeLogisticsSequence = true) - { - string key; - if (!includeLogisticsSequence) - key = "LotID"; - else - { - key = "LotIDWithLogisticsSequence"; - value = string.Concat(value, "_", _Logistics.Sequence, "_", DateTime.Now.Ticks - _Logistics.Sequence); - } - SetFileParameter(key, value); - } - - protected void WritePDSF(IFileRead fileRead, JsonElement[] jsonElements) - { - string directory; - if (!_CellInstanceConnectionName.StartsWith(_CellInstanceName) && _CellInstanceConnectionNameBase == _EquipmentType) - directory = Path.Combine(_TracePath, _EquipmentType, "Target", _CellInstanceName, _CellInstanceConnectionName); - else - directory = Path.Combine(_TracePath, _EquipmentType, "Source", _CellInstanceName, _CellInstanceConnectionName); - if (!Directory.Exists(directory)) - _ = Directory.CreateDirectory(directory); - string file = Path.Combine(directory, string.Concat(_Logistics.MesEntity, "_", _Logistics.Sequence, ".ipdsf")); - string lines = ProcessDataStandardFormat.GetPDSFText(fileRead, _Logistics, jsonElements, logisticsText: string.Empty); - File.WriteAllText(file, lines); - if (_Logistics.TotalSecondsSinceLastWriteTimeFromSequence > 600) - { - try - { File.SetLastWriteTime(file, _Logistics.DateTimeFromSequence); } - catch (Exception) { } - } - } - protected void Move(Tuple> extractResults) { if (!_IsEAFHosted) @@ -457,80 +550,49 @@ public class FileRead : Properties.IFileRead } } - protected void TriggerEvents(Tuple> extractResults, List headerNames, Dictionary keyValuePairs) + protected string[] Move(Tuple> extractResults, string to, string from, string resolvedFileLocation, Exception exception) { - object value; - string description; - List list; - for (int i = 0; i < extractResults.Item3.Length; i++) - { - _Log.Debug(string.Concat("TriggerEvent - {", _Logistics.ReportFullPath, "} ", i, " of ", extractResults.Item3.Length)); - foreach (JsonProperty jsonProperty in extractResults.Item3[i].EnumerateObject()) - { - if (jsonProperty.Value.ValueKind != JsonValueKind.String || !keyValuePairs.ContainsKey(jsonProperty.Name)) - description = string.Empty; - else - description = keyValuePairs[jsonProperty.Name].Split('|')[0]; - if (!_UseCyclicalForDescription || headerNames.Contains(jsonProperty.Name)) - value = jsonProperty.Value.ToString(); - else - { - list = new List(); - for (int z = 0; z < extractResults.Item3.Length; z++) - list.Add(new object[] { z, extractResults.Item3[z].GetProperty(jsonProperty.Name).ToString() }); - value = list; - } - } - if (_UseCyclicalForDescription) - break; - } - } - - protected Tuple> ReExtract(IFileRead fileRead, List headerNames, Dictionary keyValuePairs) - { - Tuple> results; - if (!Directory.Exists(_FileConnectorConfiguration.SourceFileLocation)) - results = null; + string[] results; + bool isErrorFile = exception is not null; + if (!to.EndsWith(@"\")) + _ = string.Concat(to, @"\"); + if (!isErrorFile) + results = Array.Empty(); else { - string[] segments; - string[] matches = null; - foreach (string subSourceFileFilter in _FileConnectorConfiguration.SourceFileFilters) + results = new string[] { _Logistics.Sequence.ToString(), _Logistics.ReportFullPath, from, resolvedFileLocation, to, string.Empty, string.Empty, exception.Message, string.Empty, string.Empty, exception.StackTrace }; + if (!_IsDuplicator) + WriteAllLines(to, results); + } + if (extractResults is not null && extractResults.Item4 is not null && extractResults.Item4.Count != 0) + { + string itemFile; + List directories = new(); + foreach (FileInfo sourceFile in extractResults.Item4) { - segments = subSourceFileFilter.Split('\\'); - if (_FileConnectorConfiguration.IncludeSubDirectories.Value) - matches = Directory.GetFiles(_FileConnectorConfiguration.SourceFileLocation, segments.Last(), SearchOption.AllDirectories); - else - matches = Directory.GetFiles(_FileConnectorConfiguration.SourceFileLocation, segments.Last(), SearchOption.TopDirectoryOnly); - if (matches.Any()) - break; - } - if (matches is null || !matches.Any()) - results = null; - else - { - _ReportFullPath = matches[0]; - results = fileRead.GetExtractResult(_ReportFullPath, _EventName); - if (!_IsEAFHosted) - TriggerEvents(results, headerNames, keyValuePairs); + if (sourceFile.FullName != _Logistics.ReportFullPath) + { + itemFile = sourceFile.FullName.Replace(from, to); + Shared1880(itemFile, directories, sourceFile, isErrorFile); + } + else if (!isErrorFile && _Logistics is not null) + Shared1811(to, sourceFile); } + Shared0231(directories); } return results; } - protected static List GetDuplicatorDescriptions(JsonElement[] jsonElements) + private void WriteAllLines(string to, string[] exceptionLines) { - List results = new(); - Duplicator.Description description; - JsonSerializerOptions jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString }; - foreach (JsonElement jsonElement in jsonElements) + string fileName = string.Concat(to, @"\readme.txt"); + try { - if (jsonElement.ValueKind != JsonValueKind.Object) - throw new Exception(); - description = JsonSerializer.Deserialize(jsonElement.ToString(), jsonSerializerOptions); - results.Add(description); + if (!Directory.Exists(to)) + _ = Directory.CreateDirectory(to); + File.WriteAllLines(fileName, exceptionLines); } - return results; + catch (Exception ex) { _Log.Error(ex.Message); } } private void Shared1880(string itemFile, List directories, FileInfo sourceFile, bool isErrorFile) @@ -562,6 +624,9 @@ public class FileRead : Properties.IFileRead case FileConnectorConfiguration.PostProcessingModeEnum.Delete: File.Delete(sourceFile.FullName); break; + case FileConnectorConfiguration.PostProcessingModeEnum.None: + File.Move(sourceFile.FullName, itemFile); + break; default: throw new Exception(); } @@ -573,11 +638,12 @@ public class FileRead : Properties.IFileRead if (!_IsDuplicator && _FileConnectorConfiguration.SourceFileFilter != "*" && sourceFile.Exists && sourceFile.Length < _MinFileLength) { string directoryName = Path.GetFileName(to); - string jobIdDirectory = Path.GetDirectoryName(to); + string jobIdDirectory = GetJobIdDirectory(to); DateTime dateTime = DateTime.Now.AddMinutes(-15); + string day = $"{_Logistics.DateTimeFromSequence:yyyy-MM-dd}"; string weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); - string weekDirectory = $"{_Logistics.DateTimeFromSequence:yyyy}_Week_{weekOfYear}{@"\"}{_Logistics.DateTimeFromSequence:yyyy-MM-dd}"; - string destinationDirectory = string.Concat(jobIdDirectory, @"\_ Ignore 100 bytes\", weekDirectory, @"\", directoryName); + string weekDirectory = $"{_Logistics.DateTimeFromSequence:yyyy}_Week_{weekOfYear}"; + string destinationDirectory = Path.Combine(jobIdDirectory, "_ Ignore 100 bytes", weekDirectory, day, directoryName); if (!Directory.Exists(destinationDirectory)) _ = Directory.CreateDirectory(destinationDirectory); File.Move(sourceFile.FullName, string.Concat(destinationDirectory, @"\", sourceFile.Name)); @@ -588,13 +654,13 @@ public class FileRead : Properties.IFileRead { if (!checkDirectory.Contains('_')) continue; - if (Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly).Any()) + if (Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly).Length != 0) continue; - if (Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly).Any()) + if (Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly).Length != 0) continue; - if (Directory.GetDirectories(checkDirectory, "*", SearchOption.AllDirectories).Any()) + if (Directory.GetDirectories(checkDirectory, "*", SearchOption.AllDirectories).Length != 0) continue; - if (Directory.GetFiles(checkDirectory, "*", SearchOption.AllDirectories).Any()) + if (Directory.GetFiles(checkDirectory, "*", SearchOption.AllDirectories).Length != 0) continue; if (new DirectoryInfo(checkDirectory).CreationTime > dateTime) continue; @@ -602,6 +668,52 @@ public class FileRead : Properties.IFileRead } } catch (Exception) { throw; } + DeleteEmptyTopDirectories(jobIdDirectory); + } + } + + private string GetJobIdDirectory(string path) + { + string result; + List directoryNames = GetDirectoryNames(path); + if (!directoryNames.Contains(_Logistics.JobID)) + result = Path.GetDirectoryName(path); + else + { + result = string.Empty; + foreach (string directoryName in directoryNames) + { + result = Path.Combine(result, directoryName); + if (directoryName == _Logistics.JobID) + break; + } + } + return result; + } + + private static void DeleteEmptyTopDirectories(string rootDirectory) + { + if (Directory.Exists(rootDirectory)) + { + string[] files; + string[] directories; + string[] subDirectories = Directory.GetDirectories(rootDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string subDirectory in subDirectories) + { + files = Directory.GetFiles(subDirectory, "*", SearchOption.AllDirectories); + if (files.Length > 0) + continue; + directories = Directory.GetDirectories(subDirectory, "*", SearchOption.TopDirectoryOnly); + if (directories.Length > 0) + continue; + try + { Directory.Delete(subDirectory); } + catch (UnauthorizedAccessException) + { + new DirectoryInfo(subDirectory).Attributes = FileAttributes.Normal; + Directory.Delete(subDirectory); + } + } } } @@ -611,72 +723,87 @@ public class FileRead : Properties.IFileRead { foreach (string directory in (from l in directories orderby l.Split('\\').Length descending select l).Distinct()) { - if (Directory.Exists(directory) && !Directory.GetFiles(directory).Any()) + if (Directory.Exists(directory) && Directory.GetFiles(directory).Length == 0) Directory.Delete(directory); } } } - protected void WaitForFileConsumption(DateTime dateTime, List descriptions, bool isDummyRun, string successDirectory, string duplicateDirectory, List<(Properties.IScopeInfo, string)> collection, string duplicateFile) where T : Properties.IDescription + protected void SetFileParameterLotID(string value, bool includeLogisticsSequence = true) { - if (!isDummyRun && _IsEAFHosted) - WaitForFileConsumption(_FileConnectorConfiguration.SourceDirectoryCloaking, _Logistics, dateTime, descriptions, successDirectory, duplicateDirectory, duplicateFile, collection); + string key; + if (!includeLogisticsSequence) + key = "LotID"; else { - long breakAfter = DateTime.Now.AddSeconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; - for (short i = 0; i < short.MaxValue; i++) + key = "LotIDWithLogisticsSequence"; + value = string.Concat(value, "_", _Logistics.Sequence, "_", DateTime.Now.Ticks - _Logistics.Sequence); + } + SetFileParameter(key, value); + } + + protected void SetFileParameterLotIDToLogisticsMID(bool includeLogisticsSequence = true) + { + string key; + if (!includeLogisticsSequence) + key = "LotID"; + else + key = "LotIDWithLogisticsSequence"; + string value = string.Concat(_Logistics.MID, "_", _Logistics.Sequence, "_", DateTime.Now.Ticks - _Logistics.Sequence); + SetFileParameter(key, value); + } + + protected Tuple> ReExtract(IFileRead fileRead, List headerNames, Dictionary keyValuePairs) + { + Tuple> results; + if (!Directory.Exists(_FileConnectorConfiguration.SourceFileLocation)) + results = null; + else + { + string[] matches = GetMatches(_FileConnectorConfiguration); + if (matches is null || matches.Length == 0) + results = null; + else { - if (!_IsEAFHosted || DateTime.Now.Ticks > breakAfter) - break; - Thread.Sleep(500); + _ReportFullPath = matches[0]; + results = fileRead.GetExtractResult(_ReportFullPath, _EventName); + if (!_IsEAFHosted) + TriggerEvents(results, headerNames, keyValuePairs); } } - } - - internal static string GetJobIdParentDirectory(string directory) - { - string result; - if (!string.IsNullOrEmpty(Path.GetFileName(directory))) - result = Path.GetFullPath(GetParentParent(directory)); - else - result = Path.GetFullPath(GetParentParent(Path.GetDirectoryName(directory))); - if (!Directory.Exists(result)) - _ = Directory.CreateDirectory(result); - return result; - } - - internal string[] GetInProcessDirectory(string jobIdDirectory) - { - string[] results; - if (!_IsEAFHosted) - results = new string[] { jobIdDirectory }; - else - { - string logisticsSequence = _Logistics.Sequence.ToString(); - results = Directory.GetDirectories(jobIdDirectory, string.Concat(_Logistics.MID, '*', logisticsSequence, '*'), SearchOption.TopDirectoryOnly); - } - if ((results is null) || results.Length != 1) - throw new Exception("Didn't find directory by logistics sequence"); return results; } - internal static string GetFileNameAfterUnderscoreSplit(string reportFullPath) + protected void TriggerEvents(Tuple> extractResults, List headerNames, Dictionary keyValuePairs) { - string result; - string[] segments = Path.GetFileNameWithoutExtension(reportFullPath).Split('_'); - if (segments.Length <= 2) - result = segments[0]; - else - result = string.Concat(segments[0], segments[2]); - return result; - } - - internal static string GetParentParent(string value) - { - string result = Path.GetDirectoryName(Path.GetDirectoryName(value)); - return result; + object value; + string segments; + string description; + List list; + for (int i = 0; i < extractResults.Item3.Length; i++) + { + _Log.Debug(string.Concat("TriggerEvent - {", _Logistics.ReportFullPath, "} ", i, " of ", extractResults.Item3.Length)); + foreach (JsonProperty jsonProperty in extractResults.Item3[i].EnumerateObject()) + { + if (jsonProperty.Value.ValueKind != JsonValueKind.String || !keyValuePairs.TryGetValue(jsonProperty.Name, out segments)) + description = string.Empty; + else + description = segments.Split('|')[0]; + if (!_UseCyclicalForDescription || headerNames.Contains(jsonProperty.Name)) + value = jsonProperty.Value.ToString(); + else + { + list = new List(); + for (int z = 0; z < extractResults.Item3.Length; z++) + list.Add(new object[] { z, extractResults.Item3[z].GetProperty(jsonProperty.Name).ToString() }); + value = list; + } + } + if (_UseCyclicalForDescription) + break; + } } } -// 2022-06-08 -> Shared - FileRead \ No newline at end of file +// 2025-03-25 -> Shared - FileRead \ No newline at end of file diff --git a/Adaptation/Shared/Logistics.cs b/Adaptation/Shared/Logistics.cs index a6ca882..4f187f8 100644 --- a/Adaptation/Shared/Logistics.cs +++ b/Adaptation/Shared/Logistics.cs @@ -35,6 +35,9 @@ public class Logistics : ILogistics public long Sequence => _Sequence; public double TotalSecondsSinceLastWriteTimeFromSequence => _TotalSecondsSinceLastWriteTimeFromSequence; + private static string DefaultMesEntity(DateTime dateTime) => + string.Concat(dateTime.Ticks, "_MES_ENTITY"); + public Logistics(IFileRead fileRead) { DateTime dateTime = DateTime.Now; @@ -84,14 +87,14 @@ public class Logistics : ILogistics _Logistics2 = new List(); } - public Logistics(string reportFullPath, string logistics) + internal Logistics(string reportFullPath, ProcessDataStandardFormat processDataStandardFormat) { string key; DateTime dateTime; string[] segments; _FileInfo = new(reportFullPath); - _Logistics1 = logistics.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries).ToList(); - if (!Logistics1.Any() || !Logistics1[0].StartsWith("LOGISTICS_1")) + _Logistics1 = processDataStandardFormat.Logistics.ToList(); + if (Logistics1.Count == 0 || !Logistics1[0].StartsWith("LOGISTICS_1")) { _NullData = null; _JobID = "null"; @@ -190,8 +193,6 @@ public class Logistics : ILogistics } } - private static string DefaultMesEntity(DateTime dateTime) => string.Concat(dateTime.Ticks, "_MES_ENTITY"); - internal void Update(string mid, string processJobID) { _MID = mid; diff --git a/Adaptation/Shared/Metrology/WS.Attachment.cs b/Adaptation/Shared/Metrology/WS.Attachment.cs index ea105ed..0a7950e 100644 --- a/Adaptation/Shared/Metrology/WS.Attachment.cs +++ b/Adaptation/Shared/Metrology/WS.Attachment.cs @@ -2,18 +2,29 @@ public partial class WS { + public class Attachment { - public string UniqueId { get; set; } - public string DestinationFileName { get; set; } - public string SourceFileName { get; set; } +#nullable enable - public Attachment(string uniqueId, string destinationFileName, string sourceFileName) + public long HeaderId { get; set; } + public string UniqueId { get; set; } + public string SubGroupId { get; set; } + public string AttachmentId { get; set; } + public string SourceFileName { get; set; } + public string HeaderIdDirectory { get; set; } + public string DestinationFileName { get; set; } + + public Attachment(Results? results, string headerIdDirectory, string uniqueId, string destinationFileName, string sourceFileName) { UniqueId = uniqueId; - DestinationFileName = destinationFileName; SourceFileName = sourceFileName; + HeaderIdDirectory = headerIdDirectory; + DestinationFileName = destinationFileName; + AttachmentId = System.Guid.NewGuid().ToString(); + HeaderId = results?.HeaderId is null ? -1 : results.HeaderId.Value; + SubGroupId = results?.SubgroupId is null ? string.Empty : results.SubgroupId.Value.ToString(); } } diff --git a/Adaptation/Shared/Metrology/WS.Results.cs b/Adaptation/Shared/Metrology/WS.Results.cs index 2d1c603..07685a3 100644 --- a/Adaptation/Shared/Metrology/WS.Results.cs +++ b/Adaptation/Shared/Metrology/WS.Results.cs @@ -1,27 +1,75 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; namespace Adaptation.Shared.Metrology; public partial class WS { - // this class represents the response from the Inbound API endpoint + public class Results { - // true or false if data was written to the database - public bool Success { get; set; } - // if true, contains ID of the Header record in the database - public long HeaderID { get; set; } +#nullable enable - // if false, this collection will contain a list of errors - public List Errors { get; set; } + [JsonConstructor] + public Results(List? errors, + long? headerId, + long? subgroupId, + bool? success, + List? warnings) + { + Errors = errors; + Success = success; + HeaderId = headerId; + Warnings = warnings; + SubgroupId = subgroupId; + } - // this collection will contain a list of warnings, they will not prevent data from being saved - public List Warnings { get; set; } + [JsonPropertyName("errors")] public List? Errors { get; set; } + [JsonPropertyName("headerID")] public long? HeaderId { get; set; } + [JsonPropertyName("subgroupId")] public long? SubgroupId { get; set; } + [JsonPropertyName("success")] public bool? Success { get; set; } + [JsonPropertyName("warnings")] public List? Warnings { get; set; } + + public override string ToString() + { + string result = JsonSerializer.Serialize(this, ResultsSourceGenerationContext.Default.Results); + return result; + } + + internal static Results Get(Results results, long? subgroupId) => + new(results.Errors, results.HeaderId, subgroupId, results.Success, results.Warnings); + + internal static Results Get(string resultsJson, Exception e) + { + Results results; + Exception? exception = e; + List errors = new(); + StringBuilder stringBuilder = new(); + while (exception is not null) + { + _ = stringBuilder.AppendLine(exception.Message); + exception = exception.InnerException; + } + errors.Add(resultsJson); + errors.Add(stringBuilder.ToString()); + results = new(errors: errors, + headerId: null, + subgroupId: null, + success: false, + warnings: new()); + return results; + } - // this is just a helper function to make displaying the results easier - public override string ToString() => JsonSerializer.Serialize(this, GetType()); } +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(WS.Results))] +internal partial class ResultsSourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Adaptation/Shared/Metrology/WS.cs b/Adaptation/Shared/Metrology/WS.cs index 844efea..b7666db 100644 --- a/Adaptation/Shared/Metrology/WS.cs +++ b/Adaptation/Shared/Metrology/WS.cs @@ -10,9 +10,11 @@ namespace Adaptation.Shared.Metrology; public partial class WS { - public static (string, Results) SendData(string url, object payload, int timeoutSeconds = 120) +#nullable enable + + public static (string, Results) SendData(string url, long sequence, string directory, object payload, int timeoutSeconds = 120) { - Results results = new(); + Results? wsResults = null; string resultsJson = string.Empty; try { @@ -30,85 +32,83 @@ public partial class WS }; HttpResponseMessage httpResponseMessage = httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead).Result; resultsJson = httpResponseMessage.Content.ReadAsStringAsync().Result; - results = JsonSerializer.Deserialize(resultsJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + wsResults = JsonSerializer.Deserialize(resultsJson, ResultsSourceGenerationContext.Default.Results); + if (wsResults is null) + throw new NullReferenceException(nameof(wsResults)); + string checkDirectory = Path.Combine(directory, $"-{wsResults.HeaderId}"); + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + File.WriteAllText(Path.Combine(checkDirectory, $"{sequence}.json"), json); } - if (!results.Success) - results.Errors.Add(results.ToString()); + if (wsResults.Success is null || !wsResults.Success.Value) + wsResults.Errors?.Add(wsResults.ToString()); } catch (Exception e) - { - Exception exception = e; - StringBuilder stringBuilder = new(); - while (exception is not null) - { - _ = stringBuilder.AppendLine(exception.Message); - exception = exception.InnerException; - } - results.Errors ??= new List(); - results.Errors.Add(resultsJson); - results.Errors.Add(stringBuilder.ToString()); - } - return new(resultsJson, results); + { wsResults ??= Results.Get(resultsJson, e); } + return new(resultsJson, wsResults); } - // this method is a wrapper for attaching a file to either a header or data record - // URL is the same URL used for SendData, ex: http://localhost/api/inbound/CDE - // attachToHeaderId is the ID returned by SendData - // attachToDataUniqueId is the string unique ID for the data record, aka the Title of the Sharepoint list entry - // fileContents is a byte array with the contents of the file - // fileName is which attachment this is, image.pdf, data.pdf, data.txt, header.pdf, etc - // timeoutSeconds is configured as the request timeout - // this method will either succeed or throw an exception - // also, this has been made synchronous - public static void AttachFile(string url, long attachToHeaderId, string attachToDataUniqueId, byte[] fileContents, string fileName, int timeoutSeconds = 60) + public static void AttachFile(string url, Attachment attachment, int timeoutSeconds = 60) { using HttpClient httpClient = new(); - string requestUrl = url + "/attachment?headerid=" + attachToHeaderId.ToString(); - if (!string.IsNullOrWhiteSpace(attachToDataUniqueId)) - { - requestUrl += "&datauniqueid="; - requestUrl += System.Net.WebUtility.UrlEncode(attachToDataUniqueId); - } - requestUrl += "&filename="; // this is just so the web server log shows the filename - requestUrl += System.Net.WebUtility.UrlEncode(fileName); - + string json = JsonSerializer.Serialize(attachment); httpClient.Timeout = new TimeSpan(0, 0, 0, timeoutSeconds, 0); - - MultipartFormDataContent multipartFormDataContent = new(); - ByteArrayContent byteArrayContent = new(fileContents); - byteArrayContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream"); - - multipartFormDataContent.Add(byteArrayContent, "attachment", fileName); - - HttpResponseMessage httpResponseMessage = httpClient.PostAsync(requestUrl, multipartFormDataContent).Result; - - if (httpResponseMessage.IsSuccessStatusCode) - return; - - string resultBody = httpResponseMessage.Content.ReadAsStringAsync().Result; - - throw new Exception("Attachment failed: " + resultBody); + StringContent httpContent = new(json, Encoding.UTF8, "application/json"); + HttpResponseMessage httpResponseMessage = httpClient.PostAsync($"{url}/attachment", httpContent).Result; + if (!httpResponseMessage.IsSuccessStatusCode) + { + string resultBody = httpResponseMessage.Content.ReadAsStringAsync().Result; + throw new Exception($"Attachment failed: {resultBody}"); + } } - public static void AttachFiles(string url, long headerID, List headerAttachments = null, List dataAttachments = null) + public static void AttachFiles(string url, List? headerAttachments = null, List? dataAttachments = null) { + string directory; try { + string? directoryName; if (headerAttachments is not null) { foreach (Attachment attachment in headerAttachments) - AttachFile(url, headerID, "", File.ReadAllBytes(attachment.SourceFileName), attachment.DestinationFileName); + { + directoryName = Path.GetDirectoryName(attachment.HeaderIdDirectory); + if (string.IsNullOrEmpty(directoryName)) + continue; + directory = Path.Combine(directoryName, attachment.AttachmentId) ?? throw new Exception(); + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + File.Copy(attachment.SourceFileName, Path.Combine(directory, attachment.DestinationFileName), overwrite: true); + } } if (dataAttachments is not null) { foreach (Attachment attachment in dataAttachments) - AttachFile(url, headerID, attachment.UniqueId, File.ReadAllBytes(attachment.SourceFileName), attachment.DestinationFileName); + { + directoryName = Path.GetDirectoryName(attachment.HeaderIdDirectory.Replace("Header", "Data")); + if (string.IsNullOrEmpty(directoryName)) + continue; + directory = Path.Combine(directoryName, attachment.AttachmentId) ?? throw new Exception(); + if (!Directory.Exists(directory)) + _ = Directory.CreateDirectory(directory); + File.Copy(attachment.SourceFileName, Path.Combine(directory, attachment.DestinationFileName), overwrite: true); + } + } + if (headerAttachments is not null) + { + foreach (Attachment attachment in headerAttachments) + AttachFile(url, attachment); + } + if (dataAttachments is not null) + { + foreach (Attachment attachment in dataAttachments) + AttachFile(url, attachment); } //MessageBox.Show(r.ToString()); } catch (Exception e) { - Exception exception = e; + Exception? exception = e; StringBuilder stringBuilder = new(); while (exception is not null) { diff --git a/Adaptation/Shared/ProcessDataStandardFormat.cs b/Adaptation/Shared/ProcessDataStandardFormat.cs index e523676..a86241d 100644 --- a/Adaptation/Shared/ProcessDataStandardFormat.cs +++ b/Adaptation/Shared/ProcessDataStandardFormat.cs @@ -1,18 +1,22 @@ using Adaptation.Shared.Methods; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.Json; +using System.Text.Json.Serialization; namespace Adaptation.Shared; -public class ProcessDataStandardFormat +#nullable enable + +internal class ProcessDataStandardFormat { - public enum SearchFor + internal enum SearchFor { EquipmentIntegration = 1, BusinessIntegration = 2, @@ -20,324 +24,47 @@ public class ProcessDataStandardFormat Archive = 4 } - public static string GetPDSFText(IFileRead fileRead, Logistics logistics, JsonElement[] jsonElements, string logisticsText) + internal long? Sequence { get; private set; } + internal ReadOnlyCollection Body { get; private set; } + internal ReadOnlyCollection Footer { get; private set; } + internal ReadOnlyCollection Header { get; private set; } + internal ReadOnlyCollection Columns { get; private set; } + internal ProcessDataStandardFormat? InputPDSF { get; private set; } + internal ReadOnlyCollection Logistics { get; private set; } + + internal ProcessDataStandardFormat(ReadOnlyCollection body, + ReadOnlyCollection columns, + ReadOnlyCollection footer, + ReadOnlyCollection header, + ProcessDataStandardFormat? inputPDSF, + ReadOnlyCollection logistics, + long? sequence) { - string result; - if (!jsonElements.Any()) - result = string.Empty; - else - { - int columns = 0; - List lines; - string endOffset = "E#######T"; - string dataOffset = "D#######T"; - string headerOffset = "H#######T"; - string format = "MM/dd/yyyy HH:mm:ss"; - StringBuilder stringBuilder = new(); - lines = new string[] { "HEADER_TAG\tHEADER_VALUE", "FORMAT\t2.00", "NUMBER_PASSES\t0001", string.Concat("HEADER_OFFSET\t", headerOffset), string.Concat("DATA_OFFSET\t", dataOffset), string.Concat("END_OFFSET\t", endOffset) }.ToList(); - _ = stringBuilder.Append("\"Time\"").Append('\t'); - _ = stringBuilder.Append("\"A_LOGISTICS\"").Append('\t'); - _ = stringBuilder.Append("\"B_LOGISTICS\"").Append('\t'); - for (int i = 0; i < jsonElements.Length;) - { - foreach (JsonProperty jsonProperty in jsonElements[0].EnumerateObject()) - { - columns += 1; - _ = stringBuilder.Append('"').Append(jsonProperty.Name).Append('"').Append('\t'); - } - break; - } - _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); - lines.Add(stringBuilder.ToString()); - for (int i = 0; i < jsonElements.Length; i++) - { - _ = stringBuilder.Clear(); - _ = stringBuilder.Append("0.1").Append('\t'); - _ = stringBuilder.Append('1').Append('\t'); - _ = stringBuilder.Append('2').Append('\t'); - foreach (JsonProperty jsonProperty in jsonElements[i].EnumerateObject()) - _ = stringBuilder.Append(jsonProperty.Value).Append('\t'); - _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); - lines.Add(stringBuilder.ToString()); - } - lines.Add(string.Concat("NUM_DATA_ROWS ", jsonElements.Length.ToString().PadLeft(9, '0'))); - lines.Add(string.Concat("NUM_DATA_COLUMNS ", (columns + 3).ToString().PadLeft(9, '0'))); - lines.Add("DELIMITER ;"); - lines.Add(string.Concat("START_TIME_FORMAT ", format)); - lines.Add(string.Concat("START_TIME ", logistics.DateTimeFromSequence.ToString(format))); //12/26/2019 15:22:44 - lines.Add(string.Concat("LOGISTICS_COLUMN", '\t', "A_LOGISTICS")); - lines.Add(string.Concat("LOGISTICS_COLUMN", '\t', "B_LOGISTICS")); - if (!string.IsNullOrEmpty(logisticsText)) - lines.Add(logisticsText); - else - { - lines.Add(string.Concat("LOGISTICS_1", '\t', "A_CHAMBER=;A_INFO=", fileRead.EventName, ";A_INFO2=", fileRead.EquipmentType, ";A_JOBID=", fileRead.CellInstanceName, ";A_MES_ENTITY=", fileRead.MesEntity, ";A_MID=", logistics.MID, ";A_NULL_DATA=", fileRead.NullData, ";A_PPID=NO_PPID;A_PROCESS_JOBID=", logistics.ProcessJobID, ";A_PRODUCT=;A_SEQUENCE=", logistics.Sequence, ";A_WAFER_ID=;")); - lines.Add(string.Concat("LOGISTICS_2", '\t', "B_CHAMBER=;B_INFO=", fileRead.EventName, ";B_INFO2=", fileRead.EquipmentType, ";B_JOBID=", fileRead.CellInstanceName, ";B_MES_ENTITY=", fileRead.MesEntity, ";B_MID=", logistics.MID, ";B_NULL_DATA=", fileRead.NullData, ";B_PPID=NO_PPID;B_PROCESS_JOBID=", logistics.ProcessJobID, ";B_PRODUCT=;B_SEQUENCE=", logistics.Sequence, ";B_WAFER_ID=;")); - lines.Add("END_HEADER"); - } - _ = stringBuilder.Clear(); - foreach (string line in lines) - _ = stringBuilder.AppendLine(line); - result = stringBuilder.ToString(); - result = result.Replace(headerOffset, result.IndexOf("NUM_DATA_ROWS").ToString().PadLeft(9, '0')). - Replace(dataOffset, result.IndexOf('"').ToString().PadLeft(9, '0')). - Replace(endOffset, result.Length.ToString().PadLeft(9, '0')); - } - return result; + Body = body; + Columns = columns; + Footer = footer; + Header = header; + InputPDSF = inputPDSF; + Logistics = logistics; + Sequence = sequence; } - public static Tuple GetLogisticsColumnsAndBody(string reportFullPath, string[] lines = null) - { - string segment; - List body = new(); - StringBuilder logistics = new(); - lines ??= File.ReadAllLines(reportFullPath); - string[] segments; - if (lines.Length < 7) - segments = Array.Empty(); - else - segments = lines[6].Trim().Split('\t'); - List columns = new(); - for (int c = 0; c < segments.Length; c++) - { - segment = segments[c].Substring(1, segments[c].Length - 2); - if (!columns.Contains(segment)) - columns.Add(segment); - else - { - for (short i = 1; i < short.MaxValue; i++) - { - segment = string.Concat(segment, "_", i); - if (!columns.Contains(segment)) - { - columns.Add(segment); - break; - } - } - } - } - bool lookForLogistics = false; - for (int r = 7; r < lines.Length; r++) - { - if (lines[r].StartsWith("NUM_DATA_ROWS")) - lookForLogistics = true; - if (!lookForLogistics) - { - body.Add(lines[r]); - continue; - } - if (lines[r].StartsWith("LOGISTICS_1")) - { - for (int i = r; i < lines.Length; i++) - { - if (lines[r].StartsWith("END_HEADER")) - break; - _ = logistics.AppendLine(lines[i]); - } - break; - } - } - return new Tuple(logistics.ToString(), columns.ToArray(), body.ToArray()); - } + internal static string EquipmentIntegration(bool addSpaces = true, char separator = ' ') => + GetString(SearchFor.EquipmentIntegration, addSpaces, separator); - public static JsonElement[] GetArray(Tuple pdsf, bool lookForNumbers = false) - { - JsonElement[] results; - string logistics = pdsf.Item1; - string[] columns = pdsf.Item2; - string[] bodyLines = pdsf.Item3; - if (!bodyLines.Any() || !bodyLines[0].Contains('\t')) - results = JsonSerializer.Deserialize("[]"); - else - { - string value; - string[] segments; - List lines = new(); - StringBuilder stringBuilder = new(); - foreach (string bodyLine in bodyLines) - { - _ = stringBuilder.Clear(); - _ = stringBuilder.Append('{'); - segments = bodyLine.Trim().Split('\t'); - if (!lookForNumbers) - { - for (int c = 1; c < segments.Length; c++) - { - value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); - _ = stringBuilder.Append('"').Append(columns[c]).Append("\":\"").Append(value).Append("\","); - } - } - else - { - for (int c = 1; c < segments.Length; c++) - { - value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); - if (string.IsNullOrEmpty(value)) - _ = stringBuilder.Append('"').Append(columns[c]).Append("\":").Append(value).Append("null,"); - else if (value.All(char.IsDigit)) - _ = stringBuilder.Append('"').Append(columns[c]).Append("\":").Append(value).Append(','); - else - _ = stringBuilder.Append('"').Append(columns[c]).Append("\":\"").Append(value).Append("\","); - } - } - _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); - _ = stringBuilder.AppendLine("}"); - lines.Add(stringBuilder.ToString()); - } - string json = $"[{string.Join(",", lines)}]"; - results = JsonSerializer.Deserialize(json); - } - return results; - } + internal static string BusinessIntegration(bool addSpaces = true, char separator = ' ') => + GetString(SearchFor.BusinessIntegration, addSpaces, separator); - public static Dictionary> GetDictionary(Tuple pdsf) - { - Dictionary> results = new(); - string[] segments; - string[] columns = pdsf.Item2; - string[] bodyLines = pdsf.Item3; - foreach (string column in columns) - results.Add(column, new List()); - foreach (string bodyLine in bodyLines) - { - segments = bodyLine.Split('\t'); - for (int c = 1; c < segments.Length; c++) - { - if (c >= columns.Length) - continue; - results[columns[c]].Add(segments[c]); - } - } - return results; - } + internal static string SystemExport(bool addSpaces = true, char separator = ' ') => + GetString(SearchFor.SystemExport, addSpaces, separator); - public static Tuple>>> GetTestDictionary(Tuple pdsf) - { - Dictionary>> results = new(); - string testColumn = nameof(Test); - Dictionary> keyValuePairs = GetDictionary(pdsf); - if (!keyValuePairs.ContainsKey(testColumn)) - throw new Exception(); - int min; - int max; - Test testKey; - List vs; - string columnKey; - Dictionary> tests = new(); - for (int i = 0; i < keyValuePairs[testColumn].Count; i++) - { - if (Enum.TryParse(keyValuePairs[testColumn][i], out Test test)) - { - if (!results.ContainsKey(test)) - { - tests.Add(test, new List()); - results.Add(test, new Dictionary>()); - } - tests[test].Add(i); - } - } - foreach (KeyValuePair> testKeyValuePair in tests) - { - testKey = testKeyValuePair.Key; - min = testKeyValuePair.Value.Min(); - max = testKeyValuePair.Value.Max() + 1; - foreach (KeyValuePair> keyValuePair in keyValuePairs) - results[testKey].Add(keyValuePair.Key, new List()); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - { - vs = keyValuePair.Value; - columnKey = keyValuePair.Key; - for (int i = min; i < max; i++) - { - if (vs.Count > i) - results[testKey][columnKey].Add(vs[i]); - else - results[testKey][columnKey].Add(string.Empty); - } - } - } - return new Tuple>>>(pdsf.Item1, results); - } + internal static string Archive(bool addSpaces = true, char separator = ' ') => + GetString(SearchFor.Archive, addSpaces, separator); - private static string GetString(SearchFor searchFor, bool addSpaces, char separator = ' ') - { - if (!addSpaces) - return string.Concat(((int)searchFor).ToString().PadLeft(2, '0'), searchFor); - else - return string.Concat(((int)searchFor).ToString().PadLeft(2, '0'), separator, searchFor.ToString().Replace("In", string.Concat(separator, "In")).Replace("Ex", string.Concat(separator, "Ex"))); - } + internal static ProcessDataStandardFormat GetEmpty(Logistics logistics) => + new(new(Array.Empty()), new(Array.Empty()), new(Array.Empty()), new(Array.Empty()), null, new(logistics.Logistics1), null); - public static string EquipmentIntegration(bool addSpaces = true, char separator = ' ') => GetString(SearchFor.EquipmentIntegration, addSpaces, separator); - - public static string BusinessIntegration(bool addSpaces = true, char separator = ' ') => GetString(SearchFor.BusinessIntegration, addSpaces, separator); - - public static string SystemExport(bool addSpaces = true, char separator = ' ') => GetString(SearchFor.SystemExport, addSpaces, separator); - - public static string Archive(bool addSpaces = true, char separator = ' ') => GetString(SearchFor.Archive, addSpaces, separator); - - public static string GetLines(Logistics logistics, Properties.IScopeInfo scopeInfo, List names, Dictionary> keyValuePairs, string dateFormat, string timeFormat, List pairedParameterNames, bool useDateTimeFromSequence = true, string format = "", List ignoreParameterNames = null) - { - StringBuilder result = new(); - ignoreParameterNames ??= new List(); - if (useDateTimeFromSequence && !string.IsNullOrEmpty(format)) - throw new Exception(); - else if (!useDateTimeFromSequence && string.IsNullOrEmpty(format)) - throw new Exception(); - string nullData; - const string columnDate = "Date"; - const string columnTime = "Time"; - const string firstDuplicate = "_1"; - _ = result.AppendLine(scopeInfo.Header); - StringBuilder line = new(); - if (logistics.NullData is null) - nullData = string.Empty; - else - nullData = logistics.NullData.ToString(); - int count = (from l in keyValuePairs select l.Value.Count).Min(); - for (int r = 0; r < count; r++) - { - _ = line.Clear(); - _ = line.Append('!'); - foreach (KeyValuePair> keyValuePair in keyValuePairs) - { - if (!names.Contains(keyValuePair.Key)) - continue; - if (ignoreParameterNames.Contains(keyValuePair.Key)) - continue; - if (pairedParameterNames.Contains(keyValuePair.Key)) - { - if (string.IsNullOrEmpty(keyValuePair.Value[r]) || keyValuePair.Value[r] == nullData) - continue; - else - _ = result.Append(line).Append(keyValuePair.Key).Append(';').AppendLine(keyValuePair.Value[r]); - } - else - { - if (useDateTimeFromSequence && keyValuePair.Key == columnDate) - _ = line.Append(logistics.DateTimeFromSequence.ToString(dateFormat)); - else if (useDateTimeFromSequence && keyValuePair.Key == columnTime) - _ = line.Append(logistics.DateTimeFromSequence.ToString(timeFormat)); - else if (!useDateTimeFromSequence && keyValuePair.Key == columnDate && keyValuePair.Value[r].Length == format.Length) - _ = line.Append(DateTime.ParseExact(keyValuePair.Value[r], format, CultureInfo.InvariantCulture).ToString(dateFormat)); - else if (!useDateTimeFromSequence && keyValuePair.Key == columnTime && keyValuePairs.ContainsKey(string.Concat(keyValuePair.Key, firstDuplicate)) && keyValuePairs[string.Concat(keyValuePair.Key, firstDuplicate)][r].Length == format.Length) - _ = line.Append(DateTime.ParseExact(keyValuePairs[string.Concat(keyValuePair.Key, firstDuplicate)][r], format, CultureInfo.InvariantCulture).ToString(timeFormat)); - else if (string.IsNullOrEmpty(keyValuePair.Value[r]) || keyValuePair.Value[r] == nullData) - _ = line.Append(nullData); - else - _ = line.Append(keyValuePair.Value[r]); - _ = line.Append(';'); - } - } - if (!pairedParameterNames.Any()) - { - _ = line.Remove(line.Length - 1, 1); - _ = result.AppendLine(line.ToString()); - } - } - return result.ToString(); - } - - public static List PDSFToFixedWidth(string reportFullPath) + internal static List PDSFToFixedWidth(string reportFullPath) { List results = new(); if (!File.Exists(reportFullPath)) @@ -406,4 +133,634 @@ public class ProcessDataStandardFormat return results; } + internal static ProcessDataStandardFormat GetProcessDataStandardFormat(string reportFullPath, string[]? lines = null, int columnsLine = 6) + { + ProcessDataStandardFormat result; + string segment; + string[] segments; + bool addToFooter = false; + List body = new(); + List header = new(); + List footer = new(); + List columns = new(); + ReadOnlyCollection logistics; + lines ??= File.ReadAllLines(reportFullPath); + if (lines.Length < columnsLine + 1) + segments = Array.Empty(); + else + { + segments = lines[columnsLine].Trim().Split('\t'); + for (int i = 0; i < columnsLine; i++) + header.Add(lines[i]); + } + for (int c = 0; c < segments.Length; c++) + { + segment = segments[c].Substring(1, segments[c].Length - 2); + if (!columns.Contains(segment)) + columns.Add(segment); + else + { + for (short i = 1; i < short.MaxValue; i++) + { + segment = string.Concat(segment, "_", i); + if (!columns.Contains(segment)) + { + columns.Add(segment); + break; + } + } + } + } + for (int r = columnsLine + 1; r < lines.Length; r++) + { + if (lines[r].StartsWith("NUM_DATA_ROWS")) + addToFooter = true; + if (!addToFooter) + body.Add(lines[r]); + else + { + footer.Add(lines[r]); + if (lines[r].StartsWith("END_HEADER")) + break; + } + } + string? linesOne = lines.Length > 0 && body.Count == 0 && columns.Count == 0 ? lines[1] : null; + logistics = GetLogistics(footer, linesOne: linesOne); + result = new(body: body.AsReadOnly(), + columns: columns.AsReadOnly(), + footer: footer.AsReadOnly(), + header: header.AsReadOnly(), + inputPDSF: null, + logistics: logistics, + sequence: null); + return result; + } + + private static ReadOnlyCollection GetLogistics(List footer, string? linesOne) + { + List results = new(); + bool foundLogistics1 = false; + foreach (string line in footer) + { + if (line.StartsWith("END_HEADER")) + break; + if (line.StartsWith("LOGISTICS_1")) + foundLogistics1 = true; + if (foundLogistics1 && line.StartsWith("LOGISTICS_")) + results.Add(line); + } + if (!string.IsNullOrEmpty(linesOne) && results.Count == 0) + results.Add(linesOne); + return results.AsReadOnly(); + } + + internal static ProcessDataStandardFormat GetProcessDataStandardFormat(string reportFullPath, ProcessDataStandardFormatMapping pdsfMapping) + { + ProcessDataStandardFormat result; + const int columnsLine = 6; + FileInfo fileInfo = new(reportFullPath); + ProcessDataStandardFormat processDataStandardFormat = GetProcessDataStandardFormat(fileInfo.LastWriteTime, columnsLine, fileInfo.FullName, lines: null); + JsonElement[]? jsonElements = pdsfMapping.OldColumnNames.Count != pdsfMapping.ColumnIndices.Count ? null : GetFullArray(processDataStandardFormat); + JsonProperty[]? jsonProperties = jsonElements is null || jsonElements.Length == 0 ? null : jsonElements[0].EnumerateObject().ToArray(); + if (jsonElements is null || jsonProperties is null || jsonProperties.Length != pdsfMapping.NewColumnNames.Count) + result = processDataStandardFormat; + else + { + result = GetProcessDataStandardFormat(pdsfMapping, jsonElements, processDataStandardFormat); + if (result.Sequence is null || result.Columns.Count == 0 || result.Body.Count == 0 || result.Logistics.Count == 0) + result = processDataStandardFormat; + } + return result; + } + + private static ProcessDataStandardFormat GetProcessDataStandardFormat(DateTime lastWriteTime, int columnsLine, string path, string[]? lines) + { + ProcessDataStandardFormat result; + long sequence; + string[] segments; + bool addToFooter = false; + List body = new(); + List header = new(); + List footer = new(); + ReadOnlyCollection logistics; + lines ??= File.ReadAllLines(path); + if (lines.Length <= columnsLine) + segments = Array.Empty(); + else + { + segments = lines[columnsLine].Split('\t'); + for (int i = 0; i < columnsLine; i++) + header.Add(lines[i]); + } + string[] columns = segments.Select(l => l.Trim('"')).ToArray(); + for (int r = columnsLine + 1; r < lines.Length; r++) + { + if (lines[r].StartsWith("NUM_DATA_ROWS")) + addToFooter = true; + if (!addToFooter) + body.Add(lines[r]); + else + { + footer.Add(lines[r]); + if (lines[r].StartsWith("END_HEADER")) + break; + } + } + logistics = GetLogistics(footer, linesOne: null); + if (logistics.Count == 0) + sequence = lastWriteTime.Ticks; + else + { + segments = logistics[0].Split(new string[] { "SEQUENCE=" }, StringSplitOptions.None); + sequence = segments.Length < 2 || !long.TryParse(segments[1].Split(';')[0], out long s) ? lastWriteTime.Ticks : s; + } + result = new(body: body.AsReadOnly(), + columns: new(columns), + footer: footer.AsReadOnly(), + header: header.AsReadOnly(), + inputPDSF: null, + logistics: logistics, + sequence: sequence); + return result; + } + + private static JsonElement[]? GetFullArray(ProcessDataStandardFormat processDataStandardFormat) + { + JsonElement[]? results; + if (processDataStandardFormat.Body.Count == 0 || !processDataStandardFormat.Body[0].Contains('\t')) + results = JsonSerializer.Deserialize("[]", JsonElementCollectionSourceGenerationContext.Default.JsonElementArray) ?? throw new Exception(); + else + { + string value; + List segments; + List lines = new(); + StringBuilder stringBuilder = new(); + foreach (string bodyLine in processDataStandardFormat.Body) + { + _ = stringBuilder.Clear(); + _ = stringBuilder.Append('{'); + segments = bodyLine.Split('\t').ToList(); + for (int c = 0; c < segments.Count; c++) + { + value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":\"").Append(value).Append("\","); + } + _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); + _ = stringBuilder.AppendLine("}"); + lines.Add(stringBuilder.ToString()); + } + string json = $"[{string.Join(",", lines)}]"; + results = JsonSerializer.Deserialize(json, JsonElementCollectionSourceGenerationContext.Default.JsonElementArray); + } + return results; + } + + private static ProcessDataStandardFormat GetProcessDataStandardFormat(ProcessDataStandardFormatMapping processDataStandardFormatMapping, JsonElement[] jsonElements, ProcessDataStandardFormat processDataStandardFormat) + { + ProcessDataStandardFormat result; + int column; + string value; + JsonProperty jsonProperty; + List values = new(); + List results = new(); + JsonProperty[] jsonProperties; + List unknownColumns = new(); + for (int i = 0; i < jsonElements.Length; i++) + { + values.Clear(); + if (jsonElements[i].ValueKind != JsonValueKind.Object) + { + unknownColumns.Add(string.Empty); + break; + } + jsonProperties = jsonElements[i].EnumerateObject().ToArray(); + if (jsonProperties.Length != processDataStandardFormatMapping.NewColumnNames.Count) + continue; + for (int c = 0; c < processDataStandardFormatMapping.ColumnIndices.Count; c++) + { + column = processDataStandardFormatMapping.ColumnIndices[c]; + if (column == -1) + value = processDataStandardFormatMapping.OldColumnNames[c]; + else + { + jsonProperty = jsonProperties[column]; + value = jsonProperty.Value.ToString(); + } + values.Add(value); + } + results.Add(string.Join("\t", values)); + } + result = new(body: new(results), + columns: processDataStandardFormatMapping.OldColumnNames, + footer: processDataStandardFormat.Footer, + header: processDataStandardFormat.Header, + inputPDSF: processDataStandardFormat, + logistics: processDataStandardFormat.Logistics, + sequence: processDataStandardFormat.Sequence); + return result; + } + + private static string GetJson(ProcessDataStandardFormat processDataStandardFormat) + { + if (processDataStandardFormat.InputPDSF is null) + throw new NullReferenceException(nameof(processDataStandardFormat.InputPDSF)); +#pragma warning disable CA1845, IDE0057 + string result; + string line; + string value; + string[] segments; + List lines = new(); + for (int i = 0; i < processDataStandardFormat.InputPDSF.Body.Count; i++) + { + line = "{"; + segments = processDataStandardFormat.InputPDSF.Body[i].Trim().Split('\t'); + if (segments.Length != processDataStandardFormat.InputPDSF.Columns.Count) + break; + for (int c = 0; c < segments.Length; c++) + { + value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + line += string.Concat('"', processDataStandardFormat.InputPDSF.Columns[c].Trim('"'), '"', ':', '"', value, '"', ','); + } + line = string.Concat(line.Substring(0, line.Length - 1), '}'); + lines.Add(line); + } + result = string.Concat( + '{', + Environment.NewLine, + '"', + "Count", + '"', + ": ", + processDataStandardFormat.Body.Count, + ',', + Environment.NewLine, + '"', + "Records", + '"', + ": ", + Environment.NewLine, + '[', + Environment.NewLine, + string.Join($",{Environment.NewLine}", lines), + Environment.NewLine, + ']', + ',', + Environment.NewLine, + '"', + "Sequence", + '"', + ": ", + processDataStandardFormat.Sequence, + Environment.NewLine, + '}'); + return result; +#pragma warning restore CA1845, IDE0057 + } + + internal static void Write(string path, ProcessDataStandardFormat processDataStandardFormat, List? wsResults) + { + List results = new(); + if (processDataStandardFormat.Sequence is null) + throw new NullReferenceException(nameof(processDataStandardFormat.Sequence)); + string endOffset = "E#######T"; + string dataOffset = "D#######T"; + string headerOffset = "H#######T"; + string format = "MM/dd/yyyy HH:mm:ss"; + string startTime = new DateTime(processDataStandardFormat.Sequence.Value).ToString(format); + results.Add("HEADER_TAG\tHEADER_VALUE"); + results.Add("FORMAT\t2.00"); + results.Add("NUMBER_PASSES\t0001"); + results.Add($"HEADER_OFFSET\t{headerOffset}"); + results.Add($"DATA_OFFSET\t{dataOffset}"); + results.Add($"END_OFFSET\t{endOffset}"); + results.Add($"\"{string.Join("\"\t\"", processDataStandardFormat.Columns)}\""); + results.AddRange(processDataStandardFormat.Body); + results.Add($"NUM_DATA_ROWS\t{processDataStandardFormat.Body.Count.ToString().PadLeft(9, '0')}"); + results.Add($"NUM_DATA_COLUMNS\t{processDataStandardFormat.Columns.Count.ToString().PadLeft(9, '0')}"); + results.Add("DELIMITER\t;"); + results.Add($"START_TIME_FORMAT\t{format}"); + results.Add($"START_TIME\t{startTime}"); + results.Add("LOGISTICS_COLUMN\tA_LOGISTICS"); + results.Add("LOGISTICS_COLUMN\tB_LOGISTICS"); + if (wsResults is null || wsResults.Count != 1) + results.AddRange(processDataStandardFormat.Logistics); + else + { + string[] segments; + foreach (string logistics in processDataStandardFormat.Logistics) + { + segments = logistics.Split(new string[] { "\t" }, StringSplitOptions.None); + if (segments.Length != 2 || string.IsNullOrEmpty(segments[1])) + results.Add(logistics); + else + results.Add($"{segments[0]}\t{segments[1][0]}_HeaderId={wsResults[0].HeaderId};{segments[1][0]}_SubgroupId={wsResults[0].SubgroupId};{segments[1]}"); + } + } + results.Add("END_HEADER"); + if (processDataStandardFormat.InputPDSF is not null) + { + results.Add(string.Empty); + List hyphens = new(); + results.AddRange(processDataStandardFormat.InputPDSF.Header.Select(l => l.Replace('\t', '|'))); + results.Add(string.Empty); + results.Add($"|{string.Join("|", processDataStandardFormat.InputPDSF.Columns)}|"); + for (int i = 0; i < processDataStandardFormat.InputPDSF.Columns.Count; i++) + hyphens.Add('-'); + results.Add($"|{string.Join("|", hyphens)}|"); + results.AddRange(processDataStandardFormat.InputPDSF.Body.Select(l => l.Replace('\t', '|'))); + results.Add(string.Empty); + results.AddRange(processDataStandardFormat.InputPDSF.Footer.Select(l => l.Replace('\t', '|'))); + results.Add(string.Empty); + results.Add("EOF"); + results.Add(string.Empty); + string json = GetJson(processDataStandardFormat); + results.Add(json); + } + File.WriteAllText(path, string.Join(Environment.NewLine, results)); + } + + internal static Dictionary> GetDictionary(ProcessDataStandardFormat processDataStandardFormat) + { + Dictionary> results = new(); + string[] segments; + foreach (string column in processDataStandardFormat.Columns) + results.Add(column, new List()); + foreach (string bodyLine in processDataStandardFormat.Body) + { + segments = bodyLine.Split('\t'); + for (int c = 1; c < segments.Length; c++) + { + if (c >= processDataStandardFormat.Columns.Count) + continue; + results[processDataStandardFormat.Columns[c]].Add(segments[c]); + } + } + return results; + } + + internal static JsonElement[] GetArray(ProcessDataStandardFormat processDataStandardFormat, bool lookForNumbers = false) + { + JsonElement[] results; + if (processDataStandardFormat.Body.Count == 0 || !processDataStandardFormat.Body[0].Contains('\t')) + results = JsonSerializer.Deserialize("[]", JsonElementCollectionSourceGenerationContext.Default.JsonElementArray) ?? throw new Exception(); + else + { + string value; + string[] segments; + List lines = new(); + StringBuilder stringBuilder = new(); + foreach (string bodyLine in processDataStandardFormat.Body) + { + _ = stringBuilder.Clear(); + _ = stringBuilder.Append('{'); + segments = bodyLine.Trim().Split('\t'); + if (!lookForNumbers) + { + for (int c = 1; c < segments.Length; c++) + { + value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":\"").Append(value).Append("\","); + } + } + else + { + for (int c = 1; c < segments.Length; c++) + { + value = segments[c].Replace("\"", "\\\"").Replace("\\", "\\\\"); + if (string.IsNullOrEmpty(value)) + _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":").Append(value).Append("null,"); + else if (value.All(char.IsDigit)) + _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":").Append(value).Append(','); + else + _ = stringBuilder.Append('"').Append(processDataStandardFormat.Columns[c]).Append("\":\"").Append(value).Append("\","); + } + } + _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); + _ = stringBuilder.AppendLine("}"); + lines.Add(stringBuilder.ToString()); + } + string json = $"[{string.Join(",", lines)}]"; + results = JsonSerializer.Deserialize(json) ?? throw new Exception(); + } + return results; + } + + internal static string GetPDSFText(IFileRead fileRead, Logistics logistics, JsonElement[] jsonElements, string logisticsText) + { + string result; + if (jsonElements.Length == 0) + result = string.Empty; + else + { + int columns = 0; + List lines; + string endOffset = "E#######T"; + string dataOffset = "D#######T"; + string headerOffset = "H#######T"; + string format = "MM/dd/yyyy HH:mm:ss"; + StringBuilder stringBuilder = new(); + lines = new string[] { "HEADER_TAG\tHEADER_VALUE", "FORMAT\t2.00", "NUMBER_PASSES\t0001", string.Concat("HEADER_OFFSET\t", headerOffset), string.Concat("DATA_OFFSET\t", dataOffset), string.Concat("END_OFFSET\t", endOffset) }.ToList(); + _ = stringBuilder.Append("\"Time\"").Append('\t'); + _ = stringBuilder.Append("\"A_LOGISTICS\"").Append('\t'); + _ = stringBuilder.Append("\"B_LOGISTICS\"").Append('\t'); + for (int i = 0; i < jsonElements.Length;) + { + foreach (JsonProperty jsonProperty in jsonElements[0].EnumerateObject()) + { + columns += 1; + _ = stringBuilder.Append('"').Append(jsonProperty.Name).Append('"').Append('\t'); + } + break; + } + _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); + lines.Add(stringBuilder.ToString()); + for (int i = 0; i < jsonElements.Length; i++) + { + _ = stringBuilder.Clear(); + _ = stringBuilder.Append("0.1").Append('\t'); + _ = stringBuilder.Append('1').Append('\t'); + _ = stringBuilder.Append('2').Append('\t'); + foreach (JsonProperty jsonProperty in jsonElements[i].EnumerateObject()) + _ = stringBuilder.Append(jsonProperty.Value).Append('\t'); + _ = stringBuilder.Remove(stringBuilder.Length - 1, 1); + lines.Add(stringBuilder.ToString()); + } + lines.Add(string.Concat("NUM_DATA_ROWS ", jsonElements.Length.ToString().PadLeft(9, '0'))); + lines.Add(string.Concat("NUM_DATA_COLUMNS ", (columns + 3).ToString().PadLeft(9, '0'))); + lines.Add("DELIMITER ;"); + lines.Add(string.Concat("START_TIME_FORMAT ", format)); + lines.Add(string.Concat("START_TIME ", logistics.DateTimeFromSequence.ToString(format))); //12/26/2019 15:22:44 + lines.Add(string.Concat("LOGISTICS_COLUMN", '\t', "A_LOGISTICS")); + lines.Add(string.Concat("LOGISTICS_COLUMN", '\t', "B_LOGISTICS")); + if (!string.IsNullOrEmpty(logisticsText)) + lines.Add(logisticsText); + else + { + lines.Add(string.Concat("LOGISTICS_1", '\t', "A_CHAMBER=;A_INFO=", fileRead.EventName, ";A_INFO2=", fileRead.EquipmentType, ";A_JOBID=", fileRead.CellInstanceName, ";A_MES_ENTITY=", fileRead.MesEntity, ";A_MID=", logistics.MID, ";A_NULL_DATA=", fileRead.NullData, ";A_PPID=NO_PPID;A_PROCESS_JOBID=", logistics.ProcessJobID, ";A_PRODUCT=;A_SEQUENCE=", logistics.Sequence, ";A_WAFER_ID=;")); + lines.Add(string.Concat("LOGISTICS_2", '\t', "B_CHAMBER=;B_INFO=", fileRead.EventName, ";B_INFO2=", fileRead.EquipmentType, ";B_JOBID=", fileRead.CellInstanceName, ";B_MES_ENTITY=", fileRead.MesEntity, ";B_MID=", logistics.MID, ";B_NULL_DATA=", fileRead.NullData, ";B_PPID=NO_PPID;B_PROCESS_JOBID=", logistics.ProcessJobID, ";B_PRODUCT=;B_SEQUENCE=", logistics.Sequence, ";B_WAFER_ID=;")); + lines.Add("END_HEADER"); + } + _ = stringBuilder.Clear(); + foreach (string line in lines) + _ = stringBuilder.AppendLine(line); + result = stringBuilder.ToString(); + result = result.Replace(headerOffset, result.IndexOf("NUM_DATA_ROWS").ToString().PadLeft(9, '0')). + Replace(dataOffset, result.IndexOf('"').ToString().PadLeft(9, '0')). + Replace(endOffset, result.Length.ToString().PadLeft(9, '0')); + } + return result; + } + + internal static Tuple>>> GetTestDictionary(ProcessDataStandardFormat processDataStandardFormat) + { + Dictionary>> results = new(); + List? collection; + string testColumn = nameof(Test); + Dictionary> keyValuePairs = GetDictionary(processDataStandardFormat); + if (!keyValuePairs.TryGetValue(testColumn, out collection)) + throw new Exception(); + int min; + int max; + Test testKey; + List vs; + string columnKey; + Dictionary> tests = new(); + for (int i = 0; i < collection.Count; i++) + { + if (Enum.TryParse(collection[i], out Test test)) + { + if (!results.ContainsKey(test)) + { + tests.Add(test, new List()); + results.Add(test, new Dictionary>()); + } + tests[test].Add(i); + } + } + foreach (KeyValuePair> testKeyValuePair in tests) + { + testKey = testKeyValuePair.Key; + min = testKeyValuePair.Value.Min(); + max = testKeyValuePair.Value.Max() + 1; + foreach (KeyValuePair> keyValuePair in keyValuePairs) + results[testKey].Add(keyValuePair.Key, new List()); + foreach (KeyValuePair> keyValuePair in keyValuePairs) + { + vs = keyValuePair.Value; + columnKey = keyValuePair.Key; + for (int i = min; i < max; i++) + { + if (vs.Count > i) + results[testKey][columnKey].Add(vs[i]); + else + results[testKey][columnKey].Add(string.Empty); + } + } + } + return new Tuple>>>(processDataStandardFormat.Logistics[0], results); + } + + internal static string GetLines(Logistics logistics, Properties.IScopeInfo scopeInfo, List names, Dictionary> keyValuePairs, string dateFormat, string timeFormat, List pairedParameterNames, bool useDateTimeFromSequence = true, string format = "", List? ignoreParameterNames = null) + { + StringBuilder result = new(); + ignoreParameterNames ??= new List(); + if (useDateTimeFromSequence && !string.IsNullOrEmpty(format)) + throw new Exception(); + else if (!useDateTimeFromSequence && string.IsNullOrEmpty(format)) + throw new Exception(); + string? nullData; + const string columnDate = "Date"; + const string columnTime = "Time"; + const string firstDuplicate = "_1"; + _ = result.AppendLine(scopeInfo.Header); + StringBuilder line = new(); + if (logistics.NullData is null) + nullData = string.Empty; + else + nullData = logistics.NullData.ToString(); + int count = (from l in keyValuePairs select l.Value.Count).Min(); + for (int r = 0; r < count; r++) + { + _ = line.Clear(); + _ = line.Append('!'); + foreach (KeyValuePair> keyValuePair in keyValuePairs) + { + if (!names.Contains(keyValuePair.Key)) + continue; + if (ignoreParameterNames.Contains(keyValuePair.Key)) + continue; + if (pairedParameterNames.Contains(keyValuePair.Key)) + { + if (string.IsNullOrEmpty(keyValuePair.Value[r]) || keyValuePair.Value[r] == nullData) + continue; + else + _ = result.Append(line).Append(keyValuePair.Key).Append(';').AppendLine(keyValuePair.Value[r]); + } + else + { + if (useDateTimeFromSequence && keyValuePair.Key == columnDate) + _ = line.Append(logistics.DateTimeFromSequence.ToString(dateFormat)); + else if (useDateTimeFromSequence && keyValuePair.Key == columnTime) + _ = line.Append(logistics.DateTimeFromSequence.ToString(timeFormat)); + else if (!useDateTimeFromSequence && keyValuePair.Key == columnDate && keyValuePair.Value[r].Length == format.Length) + _ = line.Append(DateTime.ParseExact(keyValuePair.Value[r], format, CultureInfo.InvariantCulture).ToString(dateFormat)); + else if (!useDateTimeFromSequence && keyValuePair.Key == columnTime && keyValuePairs.ContainsKey(string.Concat(keyValuePair.Key, firstDuplicate)) && keyValuePairs[string.Concat(keyValuePair.Key, firstDuplicate)][r].Length == format.Length) + _ = line.Append(DateTime.ParseExact(keyValuePairs[string.Concat(keyValuePair.Key, firstDuplicate)][r], format, CultureInfo.InvariantCulture).ToString(timeFormat)); + else if (string.IsNullOrEmpty(keyValuePair.Value[r]) || keyValuePair.Value[r] == nullData) + _ = line.Append(nullData); + else + _ = line.Append(keyValuePair.Value[r]); + _ = line.Append(';'); + } + } + if (pairedParameterNames.Count == 0) + { + _ = line.Remove(line.Length - 1, 1); + _ = result.AppendLine(line.ToString()); + } + } + return result.ToString(); + } + + private static string GetString(SearchFor searchFor, bool addSpaces, char separator = ' ') + { + if (!addSpaces) + return string.Concat(((int)searchFor).ToString().PadLeft(2, '0'), searchFor); + else + return string.Concat(((int)searchFor).ToString().PadLeft(2, '0'), separator, searchFor.ToString().Replace("In", string.Concat(separator, "In")).Replace("Ex", string.Concat(separator, "Ex"))); + } + + private static int? TryGetPropertyIndex(JsonProperty[] jsonProperties, string propertyName) + { + int? result = null; + for (int i = 0; i < jsonProperties.Length; i++) + { + if (jsonProperties[i].Name != propertyName) + continue; + result = i; + break; + } + if (result is null) + { + for (int i = 0; i < jsonProperties.Length; i++) + { + if (jsonProperties[i].Name[0] != propertyName[0]) + continue; + if (jsonProperties[i].Name.Length != propertyName.Length) + continue; + if (jsonProperties[i].Name != propertyName) + continue; + result = i; + break; + } + } + return result; + } + +} + +[JsonSourceGenerationOptions(WriteIndented = true)] +[JsonSerializable(typeof(JsonElement[]))] +internal partial class JsonElementCollectionSourceGenerationContext : JsonSerializerContext +{ } \ No newline at end of file diff --git a/Adaptation/Shared/ProcessDataStandardFormatMapping.cs b/Adaptation/Shared/ProcessDataStandardFormatMapping.cs new file mode 100644 index 0000000..c5a75ec --- /dev/null +++ b/Adaptation/Shared/ProcessDataStandardFormatMapping.cs @@ -0,0 +1,33 @@ +using System.Collections.ObjectModel; + +namespace Adaptation.Shared; + +public class ProcessDataStandardFormatMapping +{ + + public ReadOnlyCollection BackfillColumns { get; private set; } + public ReadOnlyCollection ColumnIndices { get; private set; } + public ReadOnlyCollection IgnoreColumns { get; private set; } + public ReadOnlyCollection IndexOnlyColumns { get; private set; } + public ReadOnlyDictionary KeyValuePairs { get; private set; } + public ReadOnlyCollection NewColumnNames { get; private set; } + public ReadOnlyCollection OldColumnNames { get; private set; } + + public ProcessDataStandardFormatMapping(ReadOnlyCollection backfillColumns, + ReadOnlyCollection columnIndices, + ReadOnlyCollection ignoreColumns, + ReadOnlyCollection indexOnlyColumns, + ReadOnlyDictionary keyValuePairs, + ReadOnlyCollection newColumnNames, + ReadOnlyCollection oldColumnNames) + { + BackfillColumns = backfillColumns; + ColumnIndices = columnIndices; + IgnoreColumns = ignoreColumns; + IndexOnlyColumns = indexOnlyColumns; + KeyValuePairs = keyValuePairs; + NewColumnNames = newColumnNames; + OldColumnNames = oldColumnNames; + } + +} \ No newline at end of file diff --git a/Adaptation/_Tests/Shared/AdaptationTesting.cs b/Adaptation/_Tests/Shared/AdaptationTesting.cs index 0771b8b..8c0bc93 100644 --- a/Adaptation/_Tests/Shared/AdaptationTesting.cs +++ b/Adaptation/_Tests/Shared/AdaptationTesting.cs @@ -56,11 +56,33 @@ public class AdaptationTesting : ISMTP public Dictionary ParameterizedModelObjectDefinitionTypes => _ParameterizedModelObjectDefinitionTypes; public Dictionary>> EquipmentDictionaryEventDescriptions => _EquipmentDictionaryEventDescriptions; - void ISMTP.SendLowPriorityEmailMessage(string subject, string body) => throw new NotImplementedException(); + void ISMTP.SendLowPriorityEmailMessage(string subject, string body) => + throw new NotImplementedException(); - void ISMTP.SendHighPriorityEmailMessage(string subject, string body) => throw new NotImplementedException(); + void ISMTP.SendHighPriorityEmailMessage(string subject, string body) => + throw new NotImplementedException(); - void ISMTP.SendNormalPriorityEmailMessage(string subject, string body) => throw new NotImplementedException(); + void ISMTP.SendNormalPriorityEmailMessage(string subject, string body) => + throw new NotImplementedException(); + + internal static T ParseXML(string @this, bool throwExceptions) where T : class + { + object result = null; + try + { + Stream stream = ToStream(@this.Trim()); + XmlReader xmlReader = XmlReader.Create(stream, new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document }); + XmlSerializer xmlSerializer = new(typeof(T), typeof(T).GetNestedTypes()); + result = xmlSerializer.Deserialize(xmlReader); + stream.Dispose(); + } + catch (Exception) + { + if (throwExceptions) + throw; + } + return result as T; + } public AdaptationTesting(string dummyRoot, TestContext testContext, bool skipEquipmentDictionary, string testContextPropertiesAsJson, bool hasWaitForProperty) { @@ -105,93 +127,6 @@ public class AdaptationTesting : ISMTP return result; } - public static string GetTestResultsDirectory(string testContextTestResultsDirectory, bool hasWaitForProperty) - { - string result = string.Empty; - string testResults = "05_TestResults"; - string checkDirectory = testContextTestResultsDirectory; - if (hasWaitForProperty && (string.IsNullOrEmpty(checkDirectory) || !checkDirectory.Contains(testResults))) - throw new Exception($"A:{checkDirectory}; B:{testResults};"); - else if (!hasWaitForProperty && (string.IsNullOrEmpty(checkDirectory) || !checkDirectory.Contains(testResults))) - result = testContextTestResultsDirectory; - else - { - string rootDirectory = Path.GetPathRoot(checkDirectory); - for (int i = 0; i < int.MaxValue; i++) - { - checkDirectory = Path.GetDirectoryName(checkDirectory); - if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == rootDirectory) - break; - if (checkDirectory.EndsWith(testResults) && Directory.Exists(checkDirectory)) - { - result = checkDirectory; - break; - } - } - } - if (string.IsNullOrEmpty(result)) - throw new Exception(); - return result; - } - - private string GetTestResultsDirectory(bool hasWaitForProperty) - { - string result = GetTestResultsDirectory(_TestContext.TestResultsDirectory, hasWaitForProperty); - return result; - } - - protected static string GetCellInstanceConnectionName(string cellInstanceConnectionName) - { - string result; - if (string.IsNullOrEmpty(cellInstanceConnectionName) || cellInstanceConnectionName[cellInstanceConnectionName.Length - 1] != '_') - result = cellInstanceConnectionName; - else - { - bool check = false; - List chars = new(); - StringBuilder stringBuilder = new(); - for (int i = cellInstanceConnectionName.Length - 1; i > -1; i--) - { - if (!check && cellInstanceConnectionName[i] != '_') - check = true; - else if (!check && cellInstanceConnectionName[i] == '_') - chars.Add('-'); - if (check) - chars.Add(cellInstanceConnectionName[i]); - } - for (int i = chars.Count - 1; i > -1; i--) - _ = stringBuilder.Append(chars[i]); - result = stringBuilder.ToString(); - } - return result; - } - - private static string GetMethodBaseNameWithActualCICN(string methodBaseName, string cellInstanceName, string cellInstanceConnectionNameFromMethodBaseName, string cellInstanceConnectionName, string ticks) - { - string results; - if (string.IsNullOrEmpty(cellInstanceConnectionNameFromMethodBaseName) || string.IsNullOrEmpty(cellInstanceConnectionName)) - results = methodBaseName; - else if (cellInstanceConnectionNameFromMethodBaseName.Length != cellInstanceConnectionName.Length) - throw new Exception(); - else - { - string[] segments = methodBaseName.Split(new string[] { cellInstanceName }, StringSplitOptions.None); - if (segments.Length == 2) - results = methodBaseName.Replace(cellInstanceConnectionNameFromMethodBaseName, cellInstanceConnectionName); - else if (segments.Length != 3) - throw new Exception(); - else if (string.IsNullOrEmpty(ticks)) - results = string.Concat(segments[0], cellInstanceName, segments[1], cellInstanceConnectionName); - else if (!segments[2].Contains(ticks)) - throw new Exception(); - else - results = string.Concat(segments[0], cellInstanceName, segments[1], cellInstanceConnectionName, ticks, segments[2].Split(new string[] { ticks }, StringSplitOptions.None)[1]); - } - if (methodBaseName.Length != results.Length) - throw new Exception(); - return results; - } - public static MethodBaseName GetMethodBaseName(string dummyRoot, string environment, bool hasWaitForProperty, string methodBaseName, string testResultsDirectory) { MethodBaseName result; @@ -275,74 +210,58 @@ public class AdaptationTesting : ISMTP return result; } - private MethodBaseName GetMethodBaseName(MethodBase methodBase) + protected static string GetCellInstanceConnectionName(string cellInstanceConnectionName) { - MethodBaseName result; - string testResultsDirectory = GetTestResultsDirectory(_HasWaitForProperty); - result = GetMethodBaseName(_DummyRoot, _Environment, _HasWaitForProperty, methodBase.Name, testResultsDirectory); + string result; + if (string.IsNullOrEmpty(cellInstanceConnectionName) || cellInstanceConnectionName[cellInstanceConnectionName.Length - 1] != '_') + result = cellInstanceConnectionName; + else + { + bool check = false; + List chars = new(); + StringBuilder stringBuilder = new(); + for (int i = cellInstanceConnectionName.Length - 1; i > -1; i--) + { + if (!check && cellInstanceConnectionName[i] != '_') + check = true; + else if (!check && cellInstanceConnectionName[i] == '_') + chars.Add('-'); + if (check) + chars.Add(cellInstanceConnectionName[i]); + } + for (int i = chars.Count - 1; i > -1; i--) + _ = stringBuilder.Append(chars[i]); + result = stringBuilder.ToString(); + } return result; } - private string[] GetTextFiles(MethodBaseName mbn) + private static string GetMethodBaseNameWithActualCICN(string methodBaseName, string cellInstanceName, string cellInstanceConnectionNameFromMethodBaseName, string cellInstanceConnectionName, string ticks) { - string[] results; - if (string.IsNullOrEmpty(mbn.TextFileDirectory)) - results = Array.Empty(); - else if (!Directory.Exists(mbn.TextFileDirectory)) - { - results = Array.Empty(); - if (!_HasWaitForProperty) - _ = Directory.CreateDirectory(mbn.TextFileDirectory); - else - { - string renameDirectory = Path.Combine(Path.GetDirectoryName(mbn.TextFileDirectory), $"_Rename - {Path.GetFileName(mbn.TextFileDirectory)}"); - _ = Directory.CreateDirectory(renameDirectory); - _ = Process.Start("explorer.exe", renameDirectory); - File.WriteAllText(Path.Combine(renameDirectory, $"{nameof(FileConnectorConfiguration.SourceFileFilter)}.txt"), string.Empty); - File.WriteAllText(Path.Combine(renameDirectory, $"{nameof(FileConnectorConfiguration.SourceFileLocation)}.txt"), string.Empty); - } - } + string results; + if (string.IsNullOrEmpty(cellInstanceConnectionNameFromMethodBaseName) || string.IsNullOrEmpty(cellInstanceConnectionName)) + results = methodBaseName; + else if (cellInstanceConnectionNameFromMethodBaseName.Length != cellInstanceConnectionName.Length) + throw new Exception(); else { - results = Directory.GetFiles(mbn.TextFileDirectory, "*.txt", SearchOption.TopDirectoryOnly); - if (!string.IsNullOrEmpty(mbn.Ticks) && _HasWaitForProperty && !results.Any()) - { - _ = Process.Start("explorer.exe", mbn.TextFileDirectory); - File.WriteAllText(Path.Combine(mbn.TextFileDirectory, "_ Why.why"), string.Empty); - } + string[] segments = methodBaseName.Split(new string[] { cellInstanceName }, StringSplitOptions.None); + if (segments.Length == 2) + results = methodBaseName.Replace(cellInstanceConnectionNameFromMethodBaseName, cellInstanceConnectionName); + else if (segments.Length != 3) + throw new Exception(); + else if (string.IsNullOrEmpty(ticks)) + results = string.Concat(segments[0], cellInstanceName, segments[1], cellInstanceConnectionName); + else if (!segments[2].Contains(ticks)) + throw new Exception(); + else + results = string.Concat(segments[0], cellInstanceName, segments[1], cellInstanceConnectionName, ticks, segments[2].Split(new string[] { ticks }, StringSplitOptions.None)[1]); } + if (methodBaseName.Length != results.Length) + throw new Exception(); return results; } - protected static Stream ToStream(string @this) - { - MemoryStream memoryStream = new(); - StreamWriter streamWriter = new(memoryStream); - streamWriter.Write(@this); - streamWriter.Flush(); - memoryStream.Position = 0; - return memoryStream; - } - - internal static T ParseXML(string @this, bool throwExceptions) where T : class - { - object result = null; - try - { - Stream stream = ToStream(@this.Trim()); - XmlReader xmlReader = XmlReader.Create(stream, new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Document }); - XmlSerializer xmlSerializer = new(typeof(T), typeof(T).GetNestedTypes()); - result = xmlSerializer.Deserialize(xmlReader); - stream.Dispose(); - } - catch (Exception) - { - if (throwExceptions) - throw; - } - return result as T; - } - public static CellInstanceVersion GetCellInstanceVersion(string url) { CellInstanceVersion result; @@ -368,14 +287,60 @@ public class AdaptationTesting : ISMTP return result; } + public static string GetTestResultsDirectory(string testContextTestResultsDirectory, bool hasWaitForProperty) + { + string result = string.Empty; + string testResults = "05_TestResults"; + string checkDirectory = testContextTestResultsDirectory; + if (hasWaitForProperty && (string.IsNullOrEmpty(checkDirectory) || !checkDirectory.Contains(testResults))) + throw new Exception($"A:{checkDirectory}; B:{testResults};"); + else if (!hasWaitForProperty && (string.IsNullOrEmpty(checkDirectory) || !checkDirectory.Contains(testResults))) + result = testContextTestResultsDirectory; + else + { + string rootDirectory = Path.GetPathRoot(checkDirectory); + for (int i = 0; i < int.MaxValue; i++) + { + checkDirectory = Path.GetDirectoryName(checkDirectory); + if (string.IsNullOrEmpty(checkDirectory) || checkDirectory == rootDirectory) + break; + if (checkDirectory.EndsWith(testResults) && Directory.Exists(checkDirectory)) + { + result = checkDirectory; + break; + } + } + } + if (string.IsNullOrEmpty(result)) + throw new Exception(); + return result; + } + + public string[] GetCSharpText(string testName) + { + string[] results; + string testResultsDirectory = GetTestResultsDirectory(_HasWaitForProperty); + MethodBaseName mbn = GetMethodBaseName(_DummyRoot, _Environment, _HasWaitForProperty, testName, testResultsDirectory); + FileInfo fileInfo = new(mbn.FileFullName); + if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) + _ = Directory.CreateDirectory(fileInfo.Directory.FullName); + Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); + results = GetCSharpTextB(fileInfo, mbn.CellInstanceName, mbn.CellInstanceVersionName, cellInstanceVersionTuple.Item2); + return results; + } + + private string GetTestResultsDirectory(bool hasWaitForProperty) + { + string result = GetTestResultsDirectory(_TestContext.TestResultsDirectory, hasWaitForProperty); + return result; + } + protected Tuple GetCellInstanceVersionTuple(string cellInstanceName, string cellInstanceVersionName) { Tuple result; CellInstanceVersion cellInstanceVersion; string cellInstanceServiceV2 = string.Concat("http://", _HostNameAndPort, "/CellInstanceServiceV2/", cellInstanceName, "/", cellInstanceVersionName, "/configuration"); - if (_CellInstanceVersions.ContainsKey(cellInstanceServiceV2)) - cellInstanceVersion = _CellInstanceVersions[cellInstanceServiceV2]; - else + if (!_CellInstanceVersions.TryGetValue(cellInstanceServiceV2, out cellInstanceVersion)) { cellInstanceVersion = GetCellInstanceVersion(cellInstanceServiceV2); _CellInstanceVersions.Add(cellInstanceServiceV2, cellInstanceVersion); @@ -384,42 +349,6 @@ public class AdaptationTesting : ISMTP return result; } - protected static Dictionary GetComponentModelComponentsIndexes(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) - { - Dictionary results = new(); - ComponentsCellComponent componentsCellComponent; - if (cellInstanceVersion.ComponentModel.Components is not null) - { - for (int i = 0; i < cellInstanceVersion.ComponentModel.Components.Length; i++) - { - componentsCellComponent = cellInstanceVersion.ComponentModel.Components[i]; - for (int j = 0; j < componentsCellComponent.Children.Length; j++) - { - if (string.IsNullOrEmpty(componentsCellComponent.Children[j].Equipment.Name)) - continue; - results.Add(componentsCellComponent.Children[j].Name, new int[] { i, j }); - } - } - } - if (!results.Any() || (!string.IsNullOrEmpty(cellInstanceConnectionName) && !results.ContainsKey(cellInstanceConnectionName))) - throw new Exception("Match not found (check test method name matches Mango)!"); - return results; - } - - protected static int[] GetCellInstanceConnectionNameIndexes(string cellInstanceConnectionName, Dictionary componentModelComponentsIndexes) - { - int[] result; - if (string.IsNullOrEmpty(cellInstanceConnectionName)) - result = componentModelComponentsIndexes.ElementAt(0).Value; - else - { - if (componentModelComponentsIndexes is null || !componentModelComponentsIndexes.ContainsKey(cellInstanceConnectionName)) - throw new Exception(); - result = componentModelComponentsIndexes[cellInstanceConnectionName]; - } - return result; - } - protected string[] GetCSharpTextB(FileInfo fileInfo, string cellInstanceName, string cellInstanceVersionName, CellInstanceVersion cellInstanceVersion) { List results = new(); @@ -565,7 +494,7 @@ public class AdaptationTesting : ISMTP else if (i == 1) { if (componentsCellComponentCellComponent.Equipment.EquipmentType.Version != cellInstanceVersionName) - throw new Exception("Versions should match!"); + throw new Exception($"Versions should match! {componentsCellComponentCellComponent.Equipment.EquipmentType.Version} != {cellInstanceVersionName}"); equipmentTypeName = componentsCellComponentCellComponent.Equipment.EquipmentType.Name; _ = stringBuilder. AppendLine("#if true"). @@ -596,7 +525,7 @@ public class AdaptationTesting : ISMTP throw new Exception(); _ = stringBuilder.Clear(); } - if (componentsCellComponentCellComponentEquipmentDictionaryNames.Any() && string.IsNullOrEmpty(cellInstanceVersion.FrozenBy)) + if (componentsCellComponentCellComponentEquipmentDictionaryNames.Count != 0 && string.IsNullOrEmpty(cellInstanceVersion.FrozenBy)) { if (!cellInstanceVersion.CellCommunicatingRule.EndsWith(".Communicating") || !(from l in componentsCellComponentCellComponentEquipmentNames where l == cellInstanceVersion.CellCommunicatingRule.Split('.')[0] select true).Any()) throw new Exception($"{methodName} - CellCommunicatingRule not correct in Mango!"); @@ -611,6 +540,62 @@ public class AdaptationTesting : ISMTP return results.ToArray(); } + public string[] GetConfiguration(MethodBase methodBase) + { + string[] results; + MethodBaseName mbn = GetMethodBaseName(methodBase); + FileInfo fileInfo = new(mbn.FileFullName); + if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) + _ = Directory.CreateDirectory(fileInfo.Directory.FullName); + Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); + Tuple fileConnectorConfigurationTuple = GetFileConnectorConfigurationTuple(cellInstanceVersionTuple, mbn.CellInstanceConnectionName); + if (string.IsNullOrEmpty(mbn.Ticks) && fileConnectorConfigurationTuple.Item2?.FileScanningIntervalInSeconds is not null) + { + string fileScanningIntervalInSecondsLine; + string versionDirectory = Path.GetDirectoryName(fileInfo.DirectoryName); + if (fileConnectorConfigurationTuple.Item2.FileScanningIntervalInSeconds.Value < 0) + fileScanningIntervalInSecondsLine = $"-\t{fileConnectorConfigurationTuple.Item2.FileScanningIntervalInSeconds.Value:0000}\t{Path.GetFileName(fileInfo.DirectoryName)}"; + else + fileScanningIntervalInSecondsLine = $"+\t{fileConnectorConfigurationTuple.Item2.FileScanningIntervalInSeconds.Value:+0000}\t{Path.GetFileName(fileInfo.DirectoryName)}"; + File.AppendAllLines(Path.Combine(versionDirectory, "FileScanningIntervalInSeconds.txt"), new string[] { fileScanningIntervalInSecondsLine }); + } + Tuple equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); + Tuple parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); + Tuple> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); + Tuple equipmentDictionaryVersionTuple = GetEquipmentDictionaryVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName, equipmentTypeVersionTuple.Item4); + Tuple>> equipmentDictionaryIsAlwaysEnabledEventsTuple = GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(equipmentDictionaryVersionTuple); + Dictionary objects = GetKeyValuePairs(mbn.CellInstanceName, mbn.CellInstanceVersionName, mbn.CellInstanceConnectionName, fileConnectorConfigurationTuple.Item2, equipmentTypeVersionTuple.Item2, parameterizedModelObjectDefinitionTypeTuple.Item2, modelObjectParametersTuple.Item2, equipmentDictionaryVersionTuple.Item2, equipmentDictionaryIsAlwaysEnabledEventsTuple.Item2, cellInstanceVersionTuple.Item2.EdaConnection.PortNumber); + string json = JsonSerializer.Serialize(objects, new JsonSerializerOptions { WriteIndented = true }); + results = new string[] { fileInfo.FullName, json }; + return results; + } + + private MethodBaseName GetMethodBaseName(MethodBase methodBase) + { + MethodBaseName result; + string testResultsDirectory = GetTestResultsDirectory(_HasWaitForProperty); + result = GetMethodBaseName(_DummyRoot, _Environment, _HasWaitForProperty, methodBase.Name, testResultsDirectory); + return result; + } + + protected Tuple GetFileConnectorConfigurationTuple(Tuple cellInstanceVersionTuple, string cellInstanceConnectionName) + { + Tuple result; + FileConnectorConfiguration fileConnectorConfiguration; + string cellInstanceServiceV2With = string.Concat(cellInstanceVersionTuple.Item1, '/', cellInstanceConnectionName); + if (!_FileConnectorConfigurations.TryGetValue(cellInstanceServiceV2With, out fileConnectorConfiguration)) + { + Dictionary componentModelComponentsIndexes = GetComponentModelComponentsIndexes(cellInstanceVersionTuple.Item2, cellInstanceConnectionName); + int[] cellInstanceConnectionNameIndexes = GetCellInstanceConnectionNameIndexes(cellInstanceConnectionName, componentModelComponentsIndexes); + ComponentsCellComponentCellComponent componentsCellComponentCellComponent = cellInstanceVersionTuple.Item2.ComponentModel.Components[cellInstanceConnectionNameIndexes[0]].Children[cellInstanceConnectionNameIndexes[1]]; + string json = JsonSerializer.Serialize(componentsCellComponentCellComponent.Equipment, new JsonSerializerOptions { WriteIndented = true }); + fileConnectorConfiguration = GetFileConnectorConfiguration(json, componentsCellComponentCellComponent); + _FileConnectorConfigurations.Add(cellInstanceServiceV2With, fileConnectorConfiguration); + } + result = new Tuple(cellInstanceServiceV2With, fileConnectorConfiguration); + return result; + } + protected static FileConnectorConfiguration GetFileConnectorConfiguration(string json, ComponentsCellComponentCellComponent componentsCellComponentCellComponent) { FileConnectorConfiguration result; @@ -643,23 +628,55 @@ public class AdaptationTesting : ISMTP return result; } - protected Tuple GetFileConnectorConfigurationTuple(Tuple cellInstanceVersionTuple, string cellInstanceConnectionName) + protected Tuple GetEquipmentTypeVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) { - Tuple result; - FileConnectorConfiguration fileConnectorConfiguration; - string cellInstanceServiceV2With = string.Concat(cellInstanceVersionTuple.Item1, '/', cellInstanceConnectionName); - if (_FileConnectorConfigurations.ContainsKey(cellInstanceServiceV2With)) - fileConnectorConfiguration = _FileConnectorConfigurations[cellInstanceServiceV2With]; + Tuple result; + EquipmentTypeVersion equipmentTypeVersion; + Dictionary componentModelComponentsIndexes = GetComponentModelComponentsIndexes(cellInstanceVersion, cellInstanceConnectionName); + int[] cellInstanceConnectionNameIndexes = GetCellInstanceConnectionNameIndexes(cellInstanceConnectionName, componentModelComponentsIndexes); + ComponentsCellComponentCellComponent componentsCellComponentCellComponent = cellInstanceVersion.ComponentModel.Components[cellInstanceConnectionNameIndexes[0]].Children[cellInstanceConnectionNameIndexes[1]]; + string equipmentTypeServiceV2 = string.Concat("http://", _HostNameAndPort, "/EquipmentTypeServiceV2/", componentsCellComponentCellComponent.Equipment.EquipmentType.Name, "/", componentsCellComponentCellComponent.Equipment.EquipmentType.Version, "/configuration"); + if (!_EquipmentTypeVersions.TryGetValue(equipmentTypeServiceV2, out equipmentTypeVersion)) + { + equipmentTypeVersion = GetEquipmentTypeVersion(equipmentTypeServiceV2); + _EquipmentTypeVersions.Add(equipmentTypeServiceV2, equipmentTypeVersion); + } + result = new Tuple(equipmentTypeServiceV2, componentsCellComponentCellComponent.Equipment.EquipmentType.Name, componentsCellComponentCellComponent.Equipment.EquipmentType.Version, equipmentTypeVersion); + return result; + } + + protected static Dictionary GetComponentModelComponentsIndexes(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) + { + Dictionary results = new(); + ComponentsCellComponent componentsCellComponent; + if (cellInstanceVersion.ComponentModel.Components is not null) + { + for (int i = 0; i < cellInstanceVersion.ComponentModel.Components.Length; i++) + { + componentsCellComponent = cellInstanceVersion.ComponentModel.Components[i]; + for (int j = 0; j < componentsCellComponent.Children.Length; j++) + { + if (string.IsNullOrEmpty(componentsCellComponent.Children[j].Equipment.Name)) + continue; + results.Add(componentsCellComponent.Children[j].Name, new int[] { i, j }); + } + } + } + if (results.Count == 0 || (!string.IsNullOrEmpty(cellInstanceConnectionName) && !results.ContainsKey(cellInstanceConnectionName))) + throw new Exception("Match not found (check test method name matches Mango)!"); + return results; + } + + protected static int[] GetCellInstanceConnectionNameIndexes(string cellInstanceConnectionName, Dictionary componentModelComponentsIndexes) + { + int[] result; + if (string.IsNullOrEmpty(cellInstanceConnectionName)) + result = componentModelComponentsIndexes.ElementAt(0).Value; else { - Dictionary componentModelComponentsIndexes = GetComponentModelComponentsIndexes(cellInstanceVersionTuple.Item2, cellInstanceConnectionName); - int[] cellInstanceConnectionNameIndexes = GetCellInstanceConnectionNameIndexes(cellInstanceConnectionName, componentModelComponentsIndexes); - ComponentsCellComponentCellComponent componentsCellComponentCellComponent = cellInstanceVersionTuple.Item2.ComponentModel.Components[cellInstanceConnectionNameIndexes[0]].Children[cellInstanceConnectionNameIndexes[1]]; - string json = JsonSerializer.Serialize(componentsCellComponentCellComponent.Equipment, new JsonSerializerOptions { WriteIndented = true }); - fileConnectorConfiguration = GetFileConnectorConfiguration(json, componentsCellComponentCellComponent); - _FileConnectorConfigurations.Add(cellInstanceServiceV2With, fileConnectorConfiguration); + if (componentModelComponentsIndexes is null || !componentModelComponentsIndexes.TryGetValue(cellInstanceConnectionName, out result)) + throw new Exception(); } - result = new Tuple(cellInstanceServiceV2With, fileConnectorConfiguration); return result; } @@ -688,37 +705,6 @@ public class AdaptationTesting : ISMTP return result; } - protected Tuple GetEquipmentTypeVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) - { - Tuple result; - EquipmentTypeVersion equipmentTypeVersion; - Dictionary componentModelComponentsIndexes = GetComponentModelComponentsIndexes(cellInstanceVersion, cellInstanceConnectionName); - int[] cellInstanceConnectionNameIndexes = GetCellInstanceConnectionNameIndexes(cellInstanceConnectionName, componentModelComponentsIndexes); - ComponentsCellComponentCellComponent componentsCellComponentCellComponent = cellInstanceVersion.ComponentModel.Components[cellInstanceConnectionNameIndexes[0]].Children[cellInstanceConnectionNameIndexes[1]]; - string equipmentTypeServiceV2 = string.Concat("http://", _HostNameAndPort, "/EquipmentTypeServiceV2/", componentsCellComponentCellComponent.Equipment.EquipmentType.Name, "/", componentsCellComponentCellComponent.Equipment.EquipmentType.Version, "/configuration"); - if (_EquipmentTypeVersions.ContainsKey(equipmentTypeServiceV2)) - equipmentTypeVersion = _EquipmentTypeVersions[equipmentTypeServiceV2]; - else - { - equipmentTypeVersion = GetEquipmentTypeVersion(equipmentTypeServiceV2); - _EquipmentTypeVersions.Add(equipmentTypeServiceV2, equipmentTypeVersion); - } - result = new Tuple(equipmentTypeServiceV2, componentsCellComponentCellComponent.Equipment.EquipmentType.Name, componentsCellComponentCellComponent.Equipment.EquipmentType.Version, equipmentTypeVersion); - return result; - } - - protected Tuple GetParameterizedModelObjectDefinitionTypeTuple(Tuple equipmentTypeVersionTuple) - { - Tuple result; - string parameterizedModelObjectDefinitionType; - if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) - parameterizedModelObjectDefinitionType = _ParameterizedModelObjectDefinitionTypes[equipmentTypeVersionTuple.Item1]; - else - parameterizedModelObjectDefinitionType = equipmentTypeVersionTuple.Item4.FileHandlerObjectTypes.ParameterizedModelObjectDefinition.Type; - result = new Tuple(equipmentTypeVersionTuple.Item1, parameterizedModelObjectDefinitionType); - return result; - } - protected IList GetModelObjectParameters(string json) { IList results; @@ -743,18 +729,38 @@ public class AdaptationTesting : ISMTP return results; } - protected Tuple> GetModelObjectParameters(Tuple equipmentTypeVersionTuple) + protected Tuple GetEquipmentDictionaryVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName, EquipmentTypeVersion equipmentTypeVersion) { - Tuple> result; - IList modelObjectParameters; - if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) - modelObjectParameters = _ModelObjectParameters[equipmentTypeVersionTuple.Item1]; + Tuple result; + string equipmentDictionaryName; + string equipmentDictionaryVersionName; + EquipmentDictionaryVersion equipmentDictionaryVersion; + Dictionary componentModelComponentsIndexes = GetComponentModelComponentsIndexes(cellInstanceVersion, cellInstanceConnectionName); + int[] cellInstanceConnectionNameIndexes = GetCellInstanceConnectionNameIndexes(cellInstanceConnectionName, componentModelComponentsIndexes); + ComponentsCellComponentCellComponent componentsCellComponentCellComponent = cellInstanceVersion.ComponentModel.Components[cellInstanceConnectionNameIndexes[0]].Children[cellInstanceConnectionNameIndexes[1]]; + string[] segments = GetEquipmentDictionaryStrings(componentsCellComponentCellComponent.Equipment, equipmentTypeVersion); + if (_SkipEquipmentDictionary || segments is null || segments.Length != 2 || string.IsNullOrEmpty(segments[0]) || string.IsNullOrEmpty(segments[1])) + { + equipmentDictionaryName = string.Empty; + equipmentDictionaryVersionName = string.Empty; + } else { - string json = JsonSerializer.Serialize(equipmentTypeVersionTuple.Item4, new JsonSerializerOptions { WriteIndented = true }); - modelObjectParameters = GetModelObjectParameters(json); + equipmentDictionaryName = segments[0]; + equipmentDictionaryVersionName = segments[1]; } - result = new Tuple>(equipmentTypeVersionTuple.Item1, modelObjectParameters); + string equipmentDictionaryServiceV2 = string.Concat("http://", _HostNameAndPort, "/EquipmentDictionaryServiceV2/", equipmentDictionaryName, "/", equipmentDictionaryVersionName, "/configuration"); + if (string.IsNullOrEmpty(equipmentDictionaryName) || string.IsNullOrEmpty(equipmentDictionaryVersionName)) + equipmentDictionaryVersion = null; + else + { + if (!_EquipmentDictionaryVersions.TryGetValue(equipmentDictionaryServiceV2, out equipmentDictionaryVersion)) + { + equipmentDictionaryVersion = GetEquipmentDictionaryVersion(equipmentDictionaryServiceV2); + _EquipmentDictionaryVersions.Add(equipmentDictionaryServiceV2, equipmentDictionaryVersion); + } + } + result = new Tuple(equipmentDictionaryServiceV2, equipmentDictionaryName, equipmentDictionaryVersionName, equipmentDictionaryVersion); return result; } @@ -763,7 +769,7 @@ public class AdaptationTesting : ISMTP string[] results; string equipmentDictionaryName; string equipmentDictionaryVersionName; - if (_SkipEquipmentDictionary || equipmentTypeVersion?.EventActionSequences is null || !equipmentTypeVersion.EventActionSequences.Any() || !(from l in equipmentTypeVersion.EventActionSequences where l.HandledEvent.StartsWith("Equipment.FileRead") select 1).Any()) + if (_SkipEquipmentDictionary || equipmentTypeVersion?.EventActionSequences is null || equipmentTypeVersion.EventActionSequences.Length == 0 || !(from l in equipmentTypeVersion.EventActionSequences where l.HandledEvent.StartsWith("Equipment.FileRead") select 1).Any()) { equipmentDictionaryName = string.Empty; equipmentDictionaryVersionName = string.Empty; @@ -809,71 +815,6 @@ public class AdaptationTesting : ISMTP return result; } - protected Tuple GetEquipmentDictionaryVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName, EquipmentTypeVersion equipmentTypeVersion) - { - Tuple result; - string equipmentDictionaryName; - string equipmentDictionaryVersionName; - EquipmentDictionaryVersion equipmentDictionaryVersion; - Dictionary componentModelComponentsIndexes = GetComponentModelComponentsIndexes(cellInstanceVersion, cellInstanceConnectionName); - int[] cellInstanceConnectionNameIndexes = GetCellInstanceConnectionNameIndexes(cellInstanceConnectionName, componentModelComponentsIndexes); - ComponentsCellComponentCellComponent componentsCellComponentCellComponent = cellInstanceVersion.ComponentModel.Components[cellInstanceConnectionNameIndexes[0]].Children[cellInstanceConnectionNameIndexes[1]]; - string[] segments = GetEquipmentDictionaryStrings(componentsCellComponentCellComponent.Equipment, equipmentTypeVersion); - if (_SkipEquipmentDictionary || segments is null || segments.Length != 2 || string.IsNullOrEmpty(segments[0]) || string.IsNullOrEmpty(segments[1])) - { - equipmentDictionaryName = string.Empty; - equipmentDictionaryVersionName = string.Empty; - } - else - { - equipmentDictionaryName = segments[0]; - equipmentDictionaryVersionName = segments[1]; - } - string equipmentDictionaryServiceV2 = string.Concat("http://", _HostNameAndPort, "/EquipmentDictionaryServiceV2/", equipmentDictionaryName, "/", equipmentDictionaryVersionName, "/configuration"); - if (string.IsNullOrEmpty(equipmentDictionaryName) || string.IsNullOrEmpty(equipmentDictionaryVersionName)) - equipmentDictionaryVersion = null; - else - { - if (_EquipmentDictionaryVersions.ContainsKey(equipmentDictionaryServiceV2)) - equipmentDictionaryVersion = _EquipmentDictionaryVersions[equipmentDictionaryServiceV2]; - else - { - equipmentDictionaryVersion = GetEquipmentDictionaryVersion(equipmentDictionaryServiceV2); - _EquipmentDictionaryVersions.Add(equipmentDictionaryServiceV2, equipmentDictionaryVersion); - } - } - result = new Tuple(equipmentDictionaryServiceV2, equipmentDictionaryName, equipmentDictionaryVersionName, equipmentDictionaryVersion); - return result; - } - - protected Tuple>> GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(Tuple equipmentDictionaryVersionTuple) - { - Tuple>> result; - List> results; - if (_SkipEquipmentDictionary) - results = new List>(); - else if (string.IsNullOrEmpty(equipmentDictionaryVersionTuple.Item1)) - throw new Exception(); - else if (equipmentDictionaryVersionTuple?.Item4?.Events?.Event is null) - results = new List>(); - else if (_EquipmentDictionaryEventDescriptions.ContainsKey(equipmentDictionaryVersionTuple.Item1)) - results = _EquipmentDictionaryEventDescriptions[equipmentDictionaryVersionTuple.Item1]; - else - { - results = new List>(); - foreach (EquipmentDictionaryVersionEventsEvent equipmentDictionaryVersionEventsEvent in equipmentDictionaryVersionTuple.Item4.Events.Event) - { - if (string.IsNullOrEmpty(equipmentDictionaryVersionEventsEvent.Description)) - continue; - if (!equipmentDictionaryVersionEventsEvent.IsAlwaysEnabled) - continue; - results.Add(new Tuple(equipmentDictionaryVersionEventsEvent.Name, equipmentDictionaryVersionEventsEvent.Description)); - } - } - result = new Tuple>>(equipmentDictionaryVersionTuple.Item1, results); - return result; - } - protected Dictionary GetKeyValuePairs(string cellInstanceName, string cellInstanceVersionName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList modelObjectParameters, string equipmentDictionaryName, List> equipmentDictionaryIsAlwaysEnabledEvents, int edaConnectionPortNumber) { Dictionary results = new() @@ -894,100 +835,6 @@ public class AdaptationTesting : ISMTP return results; } - public string[] GetCSharpText(string testName) - { - string[] results; - string testResultsDirectory = GetTestResultsDirectory(_HasWaitForProperty); - MethodBaseName mbn = GetMethodBaseName(_DummyRoot, _Environment, _HasWaitForProperty, testName, testResultsDirectory); - FileInfo fileInfo = new(mbn.FileFullName); - if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) - _ = Directory.CreateDirectory(fileInfo.Directory.FullName); - Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); - results = GetCSharpTextB(fileInfo, mbn.CellInstanceName, mbn.CellInstanceVersionName, cellInstanceVersionTuple.Item2); - return results; - } - - public string[] GetConfiguration(MethodBase methodBase) - { - string[] results; - MethodBaseName mbn = GetMethodBaseName(methodBase); - FileInfo fileInfo = new(mbn.FileFullName); - if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) - _ = Directory.CreateDirectory(fileInfo.Directory.FullName); - Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); - Tuple fileConnectorConfigurationTuple = GetFileConnectorConfigurationTuple(cellInstanceVersionTuple, mbn.CellInstanceConnectionName); - if (string.IsNullOrEmpty(mbn.Ticks) && fileConnectorConfigurationTuple.Item2?.FileScanningIntervalInSeconds is not null) - { - string fileScanningIntervalInSecondsLine; - string versionDirectory = Path.GetDirectoryName(fileInfo.DirectoryName); - if (fileConnectorConfigurationTuple.Item2.FileScanningIntervalInSeconds.Value < 0) - fileScanningIntervalInSecondsLine = $"-\t{fileConnectorConfigurationTuple.Item2.FileScanningIntervalInSeconds.Value:0000}\t{Path.GetFileName(fileInfo.DirectoryName)}"; - else - fileScanningIntervalInSecondsLine = $"+\t{fileConnectorConfigurationTuple.Item2.FileScanningIntervalInSeconds.Value:+0000}\t{Path.GetFileName(fileInfo.DirectoryName)}"; - File.AppendAllLines(Path.Combine(versionDirectory, "FileScanningIntervalInSeconds.txt"), new string[] { fileScanningIntervalInSecondsLine }); - } - Tuple equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); - Tuple parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); - Tuple> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); - Tuple equipmentDictionaryVersionTuple = GetEquipmentDictionaryVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName, equipmentTypeVersionTuple.Item4); - Tuple>> equipmentDictionaryIsAlwaysEnabledEventsTuple = GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(equipmentDictionaryVersionTuple); - Dictionary objects = GetKeyValuePairs(mbn.CellInstanceName, mbn.CellInstanceVersionName, mbn.CellInstanceConnectionName, fileConnectorConfigurationTuple.Item2, equipmentTypeVersionTuple.Item2, parameterizedModelObjectDefinitionTypeTuple.Item2, modelObjectParametersTuple.Item2, equipmentDictionaryVersionTuple.Item2, equipmentDictionaryIsAlwaysEnabledEventsTuple.Item2, cellInstanceVersionTuple.Item2.EdaConnection.PortNumber); - string json = JsonSerializer.Serialize(objects, new JsonSerializerOptions { WriteIndented = true }); - results = new string[] { fileInfo.FullName, json }; - return results; - } - - public IFileRead Get(MethodBase methodBase, string sourceFileLocation, string sourceFileFilter, bool useCyclicalForDescription) - { - IFileRead result; - MethodBaseName mbn = GetMethodBaseName(methodBase); - FileInfo fileInfo = new(mbn.FileFullName); - Dictionary fileParameter = new(); - if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) - _ = Directory.CreateDirectory(fileInfo.Directory.FullName); - Dictionary> dummyRuns = new(); - Dictionary> staticRuns = new(); - Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); - Tuple fileConnectorConfigurationTuple = GetFileConnectorConfigurationTuple(cellInstanceVersionTuple, mbn.CellInstanceConnectionName); - Tuple equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); - Tuple parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); - Tuple> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); - Tuple equipmentDictionaryVersionTuple = GetEquipmentDictionaryVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName, equipmentTypeVersionTuple.Item4); - _ = GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(equipmentDictionaryVersionTuple); - if (!string.IsNullOrEmpty(sourceFileLocation) && sourceFileLocation != fileConnectorConfigurationTuple.Item2.SourceFileLocation) - fileConnectorConfigurationTuple.Item2.SourceFileLocation = sourceFileLocation; - if (!string.IsNullOrEmpty(sourceFileFilter) && sourceFileFilter != fileConnectorConfigurationTuple.Item2.SourceFileFilter) - { - fileConnectorConfigurationTuple.Item2.SourceFileFilter = sourceFileFilter; - fileConnectorConfigurationTuple.Item2.SourceFileFilters = sourceFileFilter.Split('|').ToList(); - } - if (_TestContext.FullyQualifiedTestClassName.Contains(nameof(Extract))) - { - if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.ErrorTargetFileLocation)) - { - if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.ErrorTargetFileLocation)) - _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.ErrorTargetFileLocation); - } - if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.SourceFileLocation)) - { - if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.SourceFileLocation)) - _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.SourceFileLocation); - } - if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.TargetFileLocation)) - { - if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.TargetFileLocation)) - _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.TargetFileLocation); - } - if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.AlternateTargetFolder)) - { - if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.AlternateTargetFolder)) - _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.AlternateTargetFolder); - } - } - result = FileHandlers.CellInstanceConnectionName.Get(this, fileParameter, mbn.CellInstanceName, mbn.CellInstanceConnectionName, fileConnectorConfigurationTuple.Item2, equipmentTypeVersionTuple.Item2, parameterizedModelObjectDefinitionTypeTuple.Item2, modelObjectParametersTuple.Item2, equipmentDictionaryVersionTuple.Item2, dummyRuns, staticRuns, useCyclicalForDescription, connectionCount: cellInstanceVersionTuple.Item2.EquipmentConnections.Length); - return result; - } - public string[] GetVariables(MethodBase methodBase, string check, bool validatePDSF = true) { string[] results; @@ -1001,7 +848,7 @@ public class AdaptationTesting : ISMTP string sourceFileLocation = string.Empty; MethodBaseName mbn = GetMethodBaseName(methodBase); string[] textFiles = GetTextFiles(mbn); - if (!textFiles.Any()) + if (textFiles.Length == 0) { if (_HasWaitForProperty) throw new Exception("Set text file!"); @@ -1065,7 +912,7 @@ public class AdaptationTesting : ISMTP else { string[] files = Directory.GetFiles(ipdsfDirectory, searchPattern, SearchOption.TopDirectoryOnly); - if (files.Any()) + if (files.Length != 0) ipdsfFile = files[0]; else ipdsfFile = searchPattern; @@ -1090,80 +937,118 @@ public class AdaptationTesting : ISMTP return results; } - internal static Tuple GetLogisticsColumnsAndBody(string fileFullName) + private string[] GetTextFiles(MethodBaseName mbn) { - Tuple results; - results = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(fileFullName); - Assert.IsFalse(string.IsNullOrEmpty(results.Item1)); - Assert.IsTrue(results.Item2.Length > 0, "Column check"); - Assert.IsTrue(results.Item3.Length > 0, "Body check"); - return results; - } - - internal static Tuple GetLogisticsColumnsAndBody(string searchDirectory, string searchPattern) - { - Tuple results; - if (searchPattern.Length > 3 && !searchPattern.Contains('*') && File.Exists(searchPattern)) - results = GetLogisticsColumnsAndBody(searchPattern); + string[] results; + if (string.IsNullOrEmpty(mbn.TextFileDirectory)) + results = Array.Empty(); + else if (!Directory.Exists(mbn.TextFileDirectory)) + { + results = Array.Empty(); + if (!_HasWaitForProperty) + _ = Directory.CreateDirectory(mbn.TextFileDirectory); + else + { + string renameDirectory = Path.Combine(Path.GetDirectoryName(mbn.TextFileDirectory), $"_Rename - {Path.GetFileName(mbn.TextFileDirectory)}"); + _ = Directory.CreateDirectory(renameDirectory); + _ = Process.Start("explorer.exe", renameDirectory); + File.WriteAllText(Path.Combine(renameDirectory, $"{nameof(FileConnectorConfiguration.SourceFileFilter)}.txt"), string.Empty); + File.WriteAllText(Path.Combine(renameDirectory, $"{nameof(FileConnectorConfiguration.SourceFileLocation)}.txt"), string.Empty); + } + } else { - string[] pdsfFiles; - pdsfFiles = Directory.GetFiles(searchDirectory, searchPattern, SearchOption.TopDirectoryOnly); - if (!pdsfFiles.Any()) - _ = Process.Start("explorer.exe", searchDirectory); - Assert.IsTrue(pdsfFiles.Any(), "GetFiles check"); - results = GetLogisticsColumnsAndBody(pdsfFiles[0]); + results = Directory.GetFiles(mbn.TextFileDirectory, "*.txt", SearchOption.TopDirectoryOnly); + if (!string.IsNullOrEmpty(mbn.Ticks) && _HasWaitForProperty && results.Length == 0) + { + _ = Process.Start("explorer.exe", mbn.TextFileDirectory); + File.WriteAllText(Path.Combine(mbn.TextFileDirectory, "_ Why.why"), string.Empty); + } } - Assert.IsFalse(string.IsNullOrEmpty(results.Item1)); - Assert.IsTrue(results.Item2.Length > 0, "Column check"); - Assert.IsTrue(results.Item3.Length > 0, "Body check"); return results; } - internal static Tuple GetLogisticsColumnsAndBody(IFileRead fileRead, Logistics logistics, Tuple> extractResult, Tuple pdsf) + public IFileRead Get(MethodBase methodBase, string sourceFileLocation, string sourceFileFilter, bool useCyclicalForDescription) { - Tuple results; - string text = ProcessDataStandardFormat.GetPDSFText(fileRead, logistics, extractResult.Item3, logisticsText: pdsf.Item1); - string[] lines = text.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); - results = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(logistics.ReportFullPath, lines); - Assert.IsFalse(string.IsNullOrEmpty(results.Item1)); - Assert.IsTrue(results.Item2.Length > 0, "Column check"); - Assert.IsTrue(results.Item3.Length > 0, "Body check"); - return results; - } - - internal static string[] GetItem2(Tuple pdsf, Tuple pdsfNew) - { - JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; - string jsonOld = JsonSerializer.Serialize(pdsf.Item2, pdsf.Item2.GetType(), jsonSerializerOptions); - string jsonNew = JsonSerializer.Serialize(pdsfNew.Item2, pdsfNew.Item2.GetType(), jsonSerializerOptions); - return new string[] { jsonOld, jsonNew }; - } - - internal static string[] GetItem3(Tuple pdsf, Tuple pdsfNew) - { - string joinOld = string.Join(System.Environment.NewLine, from l in pdsf.Item3 select string.Join('\t', from t in l.Split('\t') where !t.Contains(@"\\") select t)); - string joinNew = string.Join(System.Environment.NewLine, from l in pdsfNew.Item3 select string.Join('\t', from t in l.Split('\t') where !t.Contains(@"\\") select t)); - return new string[] { joinOld, joinNew }; - } - - internal static void UpdatePassDirectory(string searchDirectory) - { - DateTime dateTime = DateTime.Now; - try - { Directory.SetLastWriteTime(searchDirectory, dateTime); } - catch (Exception) { } - string ticksDirectory = Path.GetDirectoryName(searchDirectory); - try - { Directory.SetLastWriteTime(ticksDirectory, dateTime); } - catch (Exception) { } - string[] directories = Directory.GetDirectories(searchDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string directory in directories) + IFileRead result; + MethodBaseName mbn = GetMethodBaseName(methodBase); + FileInfo fileInfo = new(mbn.FileFullName); + Dictionary fileParameter = new(); + if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) + _ = Directory.CreateDirectory(fileInfo.Directory.FullName); + Dictionary> dummyRuns = new(); + Dictionary> staticRuns = new(); + Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); + Tuple fileConnectorConfigurationTuple = GetFileConnectorConfigurationTuple(cellInstanceVersionTuple, mbn.CellInstanceConnectionName); + Tuple equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); + Tuple parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); + Tuple> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); + Tuple equipmentDictionaryVersionTuple = GetEquipmentDictionaryVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName, equipmentTypeVersionTuple.Item4); + _ = GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(equipmentDictionaryVersionTuple); + if (!string.IsNullOrEmpty(sourceFileLocation) && sourceFileLocation != fileConnectorConfigurationTuple.Item2.SourceFileLocation) + fileConnectorConfigurationTuple.Item2.SourceFileLocation = sourceFileLocation; + if (!string.IsNullOrEmpty(sourceFileFilter) && sourceFileFilter != fileConnectorConfigurationTuple.Item2.SourceFileFilter) + { + fileConnectorConfigurationTuple.Item2.SourceFileFilter = sourceFileFilter; + fileConnectorConfigurationTuple.Item2.SourceFileFilters = sourceFileFilter.Split('|').ToList(); + } + if (_TestContext.FullyQualifiedTestClassName.Contains(nameof(Extract))) { try - { Directory.SetLastWriteTime(directory, dateTime); } - catch (Exception) { } + { + if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.ErrorTargetFileLocation)) + { + if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.ErrorTargetFileLocation)) + _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.ErrorTargetFileLocation); + } + if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.SourceFileLocation)) + { + if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.SourceFileLocation)) + _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.SourceFileLocation); + } + if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.TargetFileLocation)) + { + if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.TargetFileLocation)) + _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.TargetFileLocation); + } + if (!string.IsNullOrEmpty(fileConnectorConfigurationTuple.Item2.AlternateTargetFolder)) + { + if (!Directory.Exists(fileConnectorConfigurationTuple.Item2.AlternateTargetFolder.Split('|')[0])) + _ = Directory.CreateDirectory(fileConnectorConfigurationTuple.Item2.AlternateTargetFolder.Split('|')[0]); + } + } + catch (IOException ex) + { + if (!ex.Message.Contains("SMB1")) + throw; + } } + result = FileHandlers.CellInstanceConnectionName.Get(this, fileParameter, mbn.CellInstanceName, mbn.CellInstanceConnectionName, fileConnectorConfigurationTuple.Item2, equipmentTypeVersionTuple.Item2, parameterizedModelObjectDefinitionTypeTuple.Item2, modelObjectParametersTuple.Item2, equipmentDictionaryVersionTuple.Item2, dummyRuns, staticRuns, useCyclicalForDescription, connectionCount: cellInstanceVersionTuple.Item2.EquipmentConnections.Length); + return result; + } + + internal static ProcessDataStandardFormat GetProcessDataStandardFormat(string fileFullName) + { + ProcessDataStandardFormat result; + result = ProcessDataStandardFormat.GetProcessDataStandardFormat(fileFullName); + Assert.IsTrue(result.Logistics.Count > 0, "Logistics check"); + Assert.IsFalse(string.IsNullOrEmpty(result.Logistics[0])); + Assert.IsTrue(result.Columns.Count > 0, "Column check"); + Assert.IsTrue(result.Body.Count > 0, "Body check"); + return result; + } + + internal static ProcessDataStandardFormat GetProcessDataStandardFormat(IFileRead fileRead, Logistics logistics, Tuple> extractResult, ProcessDataStandardFormat processDataStandardFormat) + { + ProcessDataStandardFormat result; + string text = ProcessDataStandardFormat.GetPDSFText(fileRead, logistics, extractResult.Item3, logisticsText: processDataStandardFormat.Logistics[0]); + string[] lines = text.Split(new string[] { System.Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); + result = ProcessDataStandardFormat.GetProcessDataStandardFormat(logistics.ReportFullPath, lines); + Assert.IsTrue(result.Logistics.Count > 0, "Logistics check"); + Assert.IsFalse(string.IsNullOrEmpty(result.Logistics[0])); + Assert.IsTrue(result.Columns.Count > 0, "Column check"); + Assert.IsTrue(result.Body.Count > 0, "Body check"); + return result; } internal static string GetFileName(MethodBase methodBase) @@ -1199,6 +1084,25 @@ public class AdaptationTesting : ISMTP return result; } + internal static void UpdatePassDirectory(string searchDirectory) + { + DateTime dateTime = DateTime.Now; + try + { Directory.SetLastWriteTime(searchDirectory, dateTime); } + catch (Exception) { } + string ticksDirectory = Path.GetDirectoryName(searchDirectory); + try + { Directory.SetLastWriteTime(ticksDirectory, dateTime); } + catch (Exception) { } + string[] directories = Directory.GetDirectories(searchDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string directory in directories) + { + try + { Directory.SetLastWriteTime(directory, dateTime); } + catch (Exception) { } + } + } + internal static void CompareSaveTSV(string textFileDirectory, string[] join) { if (join[0] != join[1]) @@ -1219,14 +1123,25 @@ public class AdaptationTesting : ISMTP } } - internal static void CompareSave(string textFileDirectory, Tuple pdsf, Tuple pdsfNew) + internal static ProcessDataStandardFormat GetProcessDataStandardFormat(string searchDirectory, string searchPattern) { - if (pdsf.Item1 != pdsfNew.Item1) + ProcessDataStandardFormat result; + if (searchPattern.Length > 3 && !searchPattern.Contains('*') && File.Exists(searchPattern)) + result = GetProcessDataStandardFormat(searchPattern); + else { - _ = Process.Start("explorer.exe", textFileDirectory); - File.WriteAllText(Path.Combine(textFileDirectory, "0.dat"), pdsf.Item1); - File.WriteAllText(Path.Combine(textFileDirectory, "1.dat"), pdsfNew.Item1); + string[] pdsfFiles; + pdsfFiles = Directory.GetFiles(searchDirectory, searchPattern, SearchOption.TopDirectoryOnly); + if (pdsfFiles.Length == 0) + _ = Process.Start("explorer.exe", searchDirectory); + Assert.AreNotEqual(0, pdsfFiles.Length, "GetFiles check"); + result = GetProcessDataStandardFormat(pdsfFiles[0]); } + Assert.IsTrue(result.Logistics.Count > 0, "Logistics check"); + Assert.IsFalse(string.IsNullOrEmpty(result.Logistics[0])); + Assert.IsTrue(result.Columns.Count > 0, "Column check"); + Assert.IsTrue(result.Body.Count > 0, "Body check"); + return result; } internal static IFileRead GetWriteConfigurationGetFileRead(MethodBase methodBase, string check, AdaptationTesting adaptationTesting) @@ -1240,30 +1155,47 @@ public class AdaptationTesting : ISMTP return result; } + internal static string[] GetItem2(ProcessDataStandardFormat processDataStandardFormat, ProcessDataStandardFormat processDataStandardFormatNew) + { + JsonSerializerOptions jsonSerializerOptions = new() { WriteIndented = true }; + string jsonOld = JsonSerializer.Serialize(processDataStandardFormat.Columns, processDataStandardFormat.Columns.GetType(), jsonSerializerOptions); + string jsonNew = JsonSerializer.Serialize(processDataStandardFormatNew.Columns, processDataStandardFormatNew.Columns.GetType(), jsonSerializerOptions); + return new string[] { jsonOld, jsonNew }; + } + + internal static string[] GetItem3(ProcessDataStandardFormat processDataStandardFormat, ProcessDataStandardFormat processDataStandardFormatNew) + { + string joinOld = string.Join(System.Environment.NewLine, from l in processDataStandardFormat.Body select string.Join('\t', from t in l.Split('\t') where !t.Contains(@"\\") select t)); + string joinNew = string.Join(System.Environment.NewLine, from l in processDataStandardFormatNew.Body select string.Join('\t', from t in l.Split('\t') where !t.Contains(@"\\") select t)); + return new string[] { joinOld, joinNew }; + } + internal static string ReExtractCompareUpdatePassDirectory(string[] variables, IFileRead fileRead, Logistics logistics, bool validatePDSF = true) { string result; Tuple> extractResult = fileRead.ReExtract(); + if (extractResult is null) + throw new Exception($"Using pattern {variables[4]} no file was found <{variables[2]}>"); if (!fileRead.IsDuplicator) { Assert.IsFalse(string.IsNullOrEmpty(extractResult?.Item1)); Assert.IsNotNull(extractResult.Item3); Assert.IsNotNull(extractResult.Item4); if (!validatePDSF) - _ = GetLogisticsColumnsAndBody(fileRead, logistics, extractResult, new(string.Empty, Array.Empty(), Array.Empty())); + _ = GetProcessDataStandardFormat(fileRead, logistics, extractResult, ProcessDataStandardFormat.GetEmpty(logistics)); else { Assert.IsTrue(extractResult.Item3.Length > 0, "extractResult Array Length check!"); - Tuple pdsf = GetLogisticsColumnsAndBody(variables[2], variables[4]); - Tuple pdsfNew = GetLogisticsColumnsAndBody(fileRead, logistics, extractResult, pdsf); - CompareSave(variables[5], pdsf, pdsfNew); - Assert.IsTrue(pdsf.Item1 == pdsfNew.Item1, "Item1 check!"); - string[] json = GetItem2(pdsf, pdsfNew); + ProcessDataStandardFormat processDataStandardFormat = GetProcessDataStandardFormat(variables[2], variables[4]); + ProcessDataStandardFormat processDataStandardFormatNew = GetProcessDataStandardFormat(fileRead, logistics, extractResult, processDataStandardFormat); + CompareSave(variables[5], processDataStandardFormat, processDataStandardFormatNew); + Assert.AreEqual(processDataStandardFormatNew.Logistics, processDataStandardFormat.Logistics, "Item1 check!"); + string[] json = GetItem2(processDataStandardFormat, processDataStandardFormatNew); CompareSaveJSON(variables[5], json); - Assert.IsTrue(json[0] == json[1], "Item2 check!"); - string[] join = GetItem3(pdsf, pdsfNew); + Assert.AreEqual(json[1], json[0], "Item2 check!"); + string[] join = GetItem3(processDataStandardFormat, processDataStandardFormatNew); CompareSaveTSV(variables[5], join); - Assert.IsTrue(join[0] == join[1], "Item3 (Join) check!"); + Assert.AreEqual(join[1], join[0], "Item3 (Join) check!"); } UpdatePassDirectory(variables[2]); } @@ -1271,6 +1203,89 @@ public class AdaptationTesting : ISMTP return result; } -} -// namespace Adaptation._Tests.Helpers { public class AdaptationTesting { } } -// 2022-08-05 -> AdaptationTesting \ No newline at end of file + internal static void CompareSave(string textFileDirectory, ProcessDataStandardFormat processDataStandardFormat, ProcessDataStandardFormat processDataStandardFormatNew) + { + if (processDataStandardFormat.Logistics[0] != processDataStandardFormatNew.Logistics[0]) + { + _ = Process.Start("explorer.exe", textFileDirectory); + File.WriteAllText(Path.Combine(textFileDirectory, "0.dat"), processDataStandardFormat.Logistics[0]); + File.WriteAllText(Path.Combine(textFileDirectory, "1.dat"), processDataStandardFormatNew.Logistics[0]); + } + } + + protected static Stream ToStream(string @this) + { + MemoryStream memoryStream = new(); + StreamWriter streamWriter = new(memoryStream); + streamWriter.Write(@this); + streamWriter.Flush(); + memoryStream.Position = 0; + return memoryStream; + } + + protected Tuple GetParameterizedModelObjectDefinitionTypeTuple(Tuple equipmentTypeVersionTuple) + { + Tuple result; + string parameterizedModelObjectDefinitionType; + if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) + parameterizedModelObjectDefinitionType = _ParameterizedModelObjectDefinitionTypes[equipmentTypeVersionTuple.Item1]; + else + parameterizedModelObjectDefinitionType = equipmentTypeVersionTuple.Item4.FileHandlerObjectTypes.ParameterizedModelObjectDefinition.Type; + result = new Tuple(equipmentTypeVersionTuple.Item1, parameterizedModelObjectDefinitionType); + return result; + } + + protected Tuple> GetModelObjectParameters(Tuple equipmentTypeVersionTuple) + { + Tuple> result; + IList modelObjectParameters; + if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) + modelObjectParameters = _ModelObjectParameters[equipmentTypeVersionTuple.Item1]; + else + { + string json = JsonSerializer.Serialize(equipmentTypeVersionTuple.Item4, new JsonSerializerOptions { WriteIndented = true }); + modelObjectParameters = GetModelObjectParameters(json); + } + result = new Tuple>(equipmentTypeVersionTuple.Item1, modelObjectParameters); + return result; + } + + protected Tuple>> GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(Tuple equipmentDictionaryVersionTuple) + { + Tuple>> result; + List> results; + List> collection; + if (_SkipEquipmentDictionary) + results = new List>(); + else if (string.IsNullOrEmpty(equipmentDictionaryVersionTuple.Item1)) + throw new Exception(); + else if (equipmentDictionaryVersionTuple?.Item4?.Events?.Event is null) + results = new List>(); + else if (_EquipmentDictionaryEventDescriptions.TryGetValue(equipmentDictionaryVersionTuple.Item1, out collection)) + results = collection; + else + { + results = new List>(); + foreach (EquipmentDictionaryVersionEventsEvent equipmentDictionaryVersionEventsEvent in equipmentDictionaryVersionTuple.Item4.Events.Event) + { + if (string.IsNullOrEmpty(equipmentDictionaryVersionEventsEvent.Description)) + continue; + if (!equipmentDictionaryVersionEventsEvent.IsAlwaysEnabled) + continue; + results.Add(new Tuple(equipmentDictionaryVersionEventsEvent.Name, equipmentDictionaryVersionEventsEvent.Description)); + } + } + result = new Tuple>>(equipmentDictionaryVersionTuple.Item1, results); + return result; + } + + public (string i, string v, string c, string n, int p, string f) GetCellInstanceVersionCore(string testName) + { + (string, string, string, string, int, string) results; + MethodBaseName mbn = GetMethodBaseName(_DummyRoot, _Environment, _HasWaitForProperty, testName, @"D:\Tmp\Phares"); + Tuple cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); + results = new(mbn.CellInstanceName, mbn.CellInstanceVersionName, cellInstanceVersionTuple.Item2.CellCommunicatingRule, cellInstanceVersionTuple.Item2.CellNotCommunicatingRule, cellInstanceVersionTuple.Item2.EdaConnection.PortNumber, cellInstanceVersionTuple.Item2.FrozenBy); + return results; + } + +} \ No newline at end of file diff --git a/EC.csproj b/EC.csproj index c0c870e..87c2edb 100644 --- a/EC.csproj +++ b/EC.csproj @@ -140,6 +140,7 @@ + diff --git a/FileHandlers/FileRead.cs b/FileHandlers/FileRead.cs index d5e2b15..367b768 100644 --- a/FileHandlers/FileRead.cs +++ b/FileHandlers/FileRead.cs @@ -37,7 +37,7 @@ public partial class FileRead : FileReaderHandler, ISMTP private FilePathGenerator _FilePathGeneratorForTarget; private readonly List _EquipmentParameters; private static readonly Dictionary> _DummyRuns; - private static readonly Dictionary> _StaticRuns; + private static readonly Dictionary> _StaticRuns; static FileRead() {