diff --git a/Adaptation/.editorconfig b/Adaptation/.editorconfig index 69ecc38..d117dc5 100644 --- a/Adaptation/.editorconfig +++ b/Adaptation/.editorconfig @@ -121,6 +121,7 @@ dotnet_diagnostic.IDE0290.severity = none # Use primary constructor [Distance]cs dotnet_diagnostic.IDE0300.severity = none # IDE0300: Collection initialization can be simplified dotnet_diagnostic.IDE0301.severity = none #IDE0301: Collection initialization can be simplified dotnet_diagnostic.IDE0305.severity = none # IDE0305: Collection initialization can be simplified +dotnet_diagnostic.MSTEST0037.severity = error # MSTEST0037: Use proper 'Assert' methods dotnet_diagnostic.SYSLIB1045.severity = none # SYSLIB1045: diagnostics for regex source generation dotnet_naming_rule.abstract_method_should_be_pascal_case.severity = warning dotnet_naming_rule.abstract_method_should_be_pascal_case.style = pascal_case diff --git a/Adaptation/.vscode/tasks.json b/Adaptation/.vscode/tasks.json index 48512b9..b25bef5 100644 --- a/Adaptation/.vscode/tasks.json +++ b/Adaptation/.vscode/tasks.json @@ -82,6 +82,26 @@ "command": "code ../METCLIMATEC.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/METCLIMATEC", + "Day-Helper-2025-03-20", + "false", + "4" + ], + "problemMatcher": [] + }, { "label": "Git Config", "type": "shell", diff --git a/Adaptation/FileHandlers/APC/FileRead.cs b/Adaptation/FileHandlers/APC/FileRead.cs index 5e2ab67..a9ed0b0 100644 --- a/Adaptation/FileHandlers/APC/FileRead.cs +++ b/Adaptation/FileHandlers/APC/FileRead.cs @@ -14,7 +14,7 @@ namespace Adaptation.FileHandlers.APC; public class FileRead : Shared.FileRead, IFileRead { - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; @@ -120,15 +120,15 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple<string, Test[], JsonElement[], List<FileInfo>> results; - Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath); - _Logistics = new Logistics(reportFullPath, pdsf.Item1); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(pdsf); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); List<Shared.Properties.IDescription> descriptions = GetDuplicatorDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) FileCopy(reportFullPath, dateTime, descriptions); - results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(pdsf.Item1, tests, jsonElements, new List<FileInfo>()); + results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List<FileInfo>()); return results; } diff --git a/Adaptation/FileHandlers/Archive/FileRead.cs b/Adaptation/FileHandlers/Archive/FileRead.cs index 0e79541..26fc9fd 100644 --- a/Adaptation/FileHandlers/Archive/FileRead.cs +++ b/Adaptation/FileHandlers/Archive/FileRead.cs @@ -18,7 +18,7 @@ public class FileRead : Shared.FileRead, IFileRead private readonly string _JobIdParentDirectory; private readonly string _JobIdArchiveParentDirectory; - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; @@ -144,15 +144,15 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple<string, Test[], JsonElement[], List<FileInfo>> results; - Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath); - _Logistics = new Logistics(reportFullPath, pdsf.Item1); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(pdsf); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); List<Shared.Properties.IDescription> descriptions = GetDuplicatorDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) MoveArchive(reportFullPath, dateTime); - results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(pdsf.Item1, tests, jsonElements, new List<FileInfo>()); + results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List<FileInfo>()); return results; } diff --git a/Adaptation/FileHandlers/CellInstanceConnectionName.cs b/Adaptation/FileHandlers/CellInstanceConnectionName.cs index 67cb69e..1275155 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<string, string> fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, int? connectionCount) + internal static IFileRead Get(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, int? connectionCount) { IFileRead result = cellInstanceConnectionName switch { diff --git a/Adaptation/FileHandlers/Dummy/FileRead.cs b/Adaptation/FileHandlers/Dummy/FileRead.cs index 916f5d7..3b777eb 100644 --- a/Adaptation/FileHandlers/Dummy/FileRead.cs +++ b/Adaptation/FileHandlers/Dummy/FileRead.cs @@ -23,7 +23,7 @@ public class FileRead : Shared.FileRead, IFileRead private int _LastDummyRunIndex; private readonly string[] _CellNames; - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; diff --git a/Adaptation/FileHandlers/IQSSi/FileRead.cs b/Adaptation/FileHandlers/IQSSi/FileRead.cs index 12bc214..a60ec91 100644 --- a/Adaptation/FileHandlers/IQSSi/FileRead.cs +++ b/Adaptation/FileHandlers/IQSSi/FileRead.cs @@ -14,7 +14,7 @@ namespace Adaptation.FileHandlers.IQSSi; public class FileRead : Shared.FileRead, IFileRead { - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; @@ -119,15 +119,15 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple<string, Test[], JsonElement[], List<FileInfo>> results; - Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath); - _Logistics = new Logistics(reportFullPath, pdsf.Item1); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(pdsf); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); List<Shared.Properties.IDescription> descriptions = GetDuplicatorDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) FileCopy(reportFullPath, dateTime, descriptions); - results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(pdsf.Item1, tests, jsonElements, new List<FileInfo>()); + results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List<FileInfo>()); return results; } diff --git a/Adaptation/FileHandlers/MoveMatchingFiles/FileRead.cs b/Adaptation/FileHandlers/MoveMatchingFiles/FileRead.cs index 02c5520..7d120eb 100644 --- a/Adaptation/FileHandlers/MoveMatchingFiles/FileRead.cs +++ b/Adaptation/FileHandlers/MoveMatchingFiles/FileRead.cs @@ -5,17 +5,75 @@ using Adaptation.Shared.Duplicator; using Adaptation.Shared.Methods; using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.IO; +using System.Linq; using System.Text; using System.Text.Json; using System.Threading; namespace Adaptation.FileHandlers.MoveMatchingFiles; +#nullable enable + public class FileRead : Shared.FileRead, IFileRead { - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + internal class PreWith + { + + internal string ErrFile { get; private set; } + internal string CheckFile { get; private set; } + internal string MatchingFile { get; private set; } + internal string CheckDirectory { get; private set; } + internal string NoWaitDirectory { get; private set; } + + internal PreWith(string checkDirectory, + string checkFile, + string errFile, + string matchingFile, + string noWaitDirectory) + { + ErrFile = errFile; + CheckFile = checkFile; + MatchingFile = matchingFile; + CheckDirectory = checkDirectory; + NoWaitDirectory = noWaitDirectory; + } + + } + + internal class Pre + { + + internal string MatchingFile { get; private set; } + internal string CheckFile { get; private set; } + + internal Pre(string matchingFile, string checkFile) + { + MatchingFile = matchingFile; + CheckFile = checkFile; + } + + } + + internal class Post + { + + internal string ErrFile { get; private set; } + internal string CheckFile { get; private set; } + + internal Post(string checkFile, string errFile) + { + ErrFile = errFile; + CheckFile = checkFile; + } + + } + + private readonly ProcessDataStandardFormatMapping _ProcessDataStandardFormatMapping; + + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; @@ -27,6 +85,12 @@ public class FileRead : Shared.FileRead, IFileRead throw new Exception(cellInstanceConnectionName); if (!_IsDuplicator) throw new Exception(cellInstanceConnectionName); + string processDataStandardFormatMappingOldColumnNames = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "Process.Data.Standard.Format.Mapping.Old.Column.Names"); + string processDataStandardFormatMappingNewColumnNames = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "Process.Data.Standard.Format.Mapping.New.Column.Names"); + string processDataStandardFormatMappingColumnIndices = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "Process.Data.Standard.Format.Mapping.Column.Indices"); + _ProcessDataStandardFormatMapping = GetProcessDataStandardFormatMapping(processDataStandardFormatMappingOldColumnNames, + processDataStandardFormatMappingNewColumnNames, + processDataStandardFormatMappingColumnIndices); } void IFileRead.Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, Exception exception) @@ -41,7 +105,8 @@ public class FileRead : Shared.FileRead, IFileRead Move(extractResults); } - void IFileRead.WaitForThread() => WaitForThread(thread: null, threadExceptions: null); + void IFileRead.WaitForThread() => + WaitForThread(thread: null, threadExceptions: null); string IFileRead.GetEventDescription() { @@ -88,7 +153,7 @@ public class FileRead : Shared.FileRead, IFileRead DateTime dateTime = DateTime.Now; results = GetExtractResult(reportFullPath, dateTime); if (results.Item3 is null) - results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(results.Item1, Array.Empty<Test>(), JsonSerializer.Deserialize<JsonElement[]>("[]"), results.Item4); + results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(results.Item1, Array.Empty<Test>(), JsonSerializer.Deserialize<JsonElement[]>("[]") ?? throw new Exception(), results.Item4); if (results.Item3.Length > 0 && _IsEAFHosted) WritePDSF(this, results.Item3); UpdateLastTicksDuration(DateTime.Now.Ticks - dateTime.Ticks); @@ -104,7 +169,73 @@ public class FileRead : Shared.FileRead, IFileRead return results; } - private static List<string> GetSearchDirectories(int numberLength, string parentDirectory) + private static ProcessDataStandardFormatMapping GetProcessDataStandardFormatMapping(string processDataStandardFormatMappingOldColumnNames, string processDataStandardFormatMappingNewColumnNames, string processDataStandardFormatMappingColumnIndices) + { + ProcessDataStandardFormatMapping result; + string[] segmentsB; + List<string> distinct = new(); + Dictionary<string, string> keyValuePairs = new(); + string args4 = "Time,Test,Count,MesEntity,HeaderUniqueId,UniqueId,Id,Recipe,Date,AreaDeltaFromLastRun,GLimit,HGCV1"; + string args5 = "Nine10mmEdgeMean,Nine4mmEdgeMean,NineCriticalPointsAverage,NineCriticalPointsPhaseAngleAverage,NineCriticalPointsStdDev,NineEdgeMeanDelta,NineMean,NineResRangePercent,AreaDeltaFromLastRun,Variation,Percentage HgCV 4PP Delta,HGCV1"; + string args6 = "RhoAvg01,RhoAvg02,RhoAvg03,RhoAvg04,RhoAvg05,RhoAvg06,RhoAvg07,RhoAvg08,RhoAvg09,HGCV1"; + string args7 = "FlatZMean|MeanFlatZ,GradeMean|MeanGrade,NAvgMean|MeanNAvg,NslMean|MeanNsl,PhaseMean|MeanPhase,RhoAvgMean|MeanRhoAvg,RhoslMean|MeanRhosl,RsMean|MeanRs,VdMean|MeanVd,FlatZRadialGradient|RadialGradientFlatZ,GradeRadialGradient|RadialGradientGrade,NAvgRadialGradient|RadialGradientNAvg,NslRadialGradient|RadialGradientNsl,PhaseRadialGradient|RadialGradientPhase,RhoAvgRadialGradient|RadialGradientRhoAvg,RhoslRadialGradient|RadialGradientRhosl,RsRadialGradient|RadialGradientRs,VdRadialGradient|RadialGradientVd,FlatZStdDev|StandardDeviationPercentageFlatZ,GradeStdDev|StandardDeviationPercentageGrade,NAvgStdDev|StandardDeviationPercentageNAvg,NslStdDev|StandardDeviationPercentageNsl,PhaseStdDev|StandardDeviationPercentagePhase,RhoAvgStdDev|StandardDeviationPercentageRhoAvg,RhoslStdDev|StandardDeviationPercentageRhosl,RsStdDev|StandardDeviationPercentageRs,VdStdDev|StandardDeviationPercentageVd,|HGCV1"; + // string args8 = "Time,A_LOGISTICS,B_LOGISTICS,Test,Count,Index,MesEntity,Date,Employee,Lot,PSN,Reactor,Recipe,Area,Folder,HeaderUniqueId,Id,Layer,Model,Pattern,Phase,Plan,RampRate,RDS,SetupFile,StartVoltage,StopVoltage,UniqueId,Wafer,WaferSize,Zone,Ccomp,CondType,FlatZ,FlatZMean,FlatZRadialGradient,FlatZStdDev,GLimit,Grade,GradeMean,GradeRadialGradient,GradeStdDev,NAvg,NAvgMean,NAvgRadialGradient,NAvgStdDev,Nsl,NslMean,NslRadialGradient,NslStdDev,PhaseMean,PhaseRadialGradient,PhaseStdDev,RhoAvg,RhoAvgMean,RhoAvgRadialGradient,RhoAvgStdDev,RhoMethod,Rhosl,RhoslMean,RhoslRadialGradient,RhoslStdDev,RsMean,RsRadialGradient,RsStdDev,Vd,VdMean,VdRadialGradient,VdStdDev,Variation,AreaDeltaFromLastRun,Nine10mmEdgeMean,Nine4mmEdgeMean,NineCriticalPointsAverage,NineCriticalPointsPhaseAngleAverage,NineCriticalPointsStdDev,NineEdgeMeanDelta,NineMean,NineResRangePercent,RhoAvg01,RhoAvg02,RhoAvg03,RhoAvg04,RhoAvg05,RhoAvg06,RhoAvg07,RhoAvg08,RhoAvg09"; + // string args9 = "Time,A_LOGISTICS,B_LOGISTICS,Index,Operator,StartVoltage,Wafer,StopVoltage,Lot,RampRate,Plan,GLimit,Date,Time,SetupFile,WaferSize,Folder,Ccomp,Pattern,Area,CondType,RhoMethod,Model,MeanNAvg,MeanNsl,MeanVd,MeanFlatZ,MeanRhoAvg,MeanRhosl,MeanPhase,MeanGrade,MeanRs,StandardDeviationPercentageNAvg,StandardDeviationPercentageNsl,StandardDeviationPercentageVd,StandardDeviationPercentageFlatZ,StandardDeviationPercentageRhoAvg,StandardDeviationPercentageRhosl,StandardDeviationPercentagePhase,StandardDeviationPercentageGrade,StandardDeviationPercentageRs,RadialGradientNAvg,RadialGradientNsl,RadialGradientVd,RadialGradientFlatZ,RadialGradientRhoAvg,RadialGradientRhosl,RadialGradientPhase,RadialGradientGrade,RadialGradientRs,Site,X,Y,NAvg,RhoAvg,Nsl,Rhosl,Vd,Phase,FlatZ,Grade,XLeft,XRight,BottomY,TopY,RDS,PSN,Reactor,Layer,Zone,Employee,InferredLot,Nine10mmEdgeMean,Nine4mmEdgeMean,NineCriticalPointsAverage,NineCriticalPointsPhaseAngleAverage,NineCriticalPointsStdDev,NineEdgeMeanDelta,NineMean,NineResRangePercent,AreaDeltaFromLastRun,Variation,Percentage HgCV 4PP Delta,RhoAvg01,RhoAvg02,RhoAvg03,RhoAvg04,RhoAvg05,RhoAvg06,RhoAvg07,RhoAvg08,RhoAvg09"; + // string args10 = "0,1,2,-1,-1,3,-1,12,70,8,66,67,-1,19,16,-1,-1,68,22,18,58,10,9,65,14,5,7,-1,6,15,69,17,20,59,26,44,35,11,60,30,48,39,53,23,41,32,55,24,42,33,29,47,38,54,27,45,36,21,56,28,46,37,31,49,40,57,25,43,34,81,80,72,73,74,75,76,77,78,79,83,84,85,86,87,88,89,90,91"; + string[] segments = args7.Split(','); + ReadOnlyCollection<string> ignoreColumns = new(args4.Split(',')); + ReadOnlyCollection<string> backfillColumns = new(args5.Split(',')); + ReadOnlyCollection<string> indexOnlyColumns = new(args6.Split(',')); + ReadOnlyCollection<string> newColumnNames = new(processDataStandardFormatMappingNewColumnNames.Split(',')); + ReadOnlyCollection<string> oldColumnNames = new(processDataStandardFormatMappingOldColumnNames.Split(',')); + ReadOnlyCollection<int> columnIndices = new(processDataStandardFormatMappingColumnIndices.Split(',').Select(int.Parse).ToArray()); + foreach (string segment in segments) + { + segmentsB = segment.Split('|'); + if (segmentsB.Length != 2) + continue; + if (distinct.Contains(segmentsB[0])) + continue; + distinct.Add(segmentsB[0]); + keyValuePairs.Add(segmentsB[0], segmentsB[1]); + } + result = new(backfillColumns: backfillColumns, + columnIndices: columnIndices, + newColumnNames: newColumnNames, + ignoreColumns: ignoreColumns, + indexOnlyColumns: indexOnlyColumns, + keyValuePairs: new(keyValuePairs), + oldColumnNames: oldColumnNames); + return result; + } + + private static ReadOnlyCollection<PreWith> GetPreWithCollection(ReadOnlyCollection<Pre> preCollection) + { + List<PreWith> results = new(); + string errFile; + PreWith preWith; + string? checkDirectory; + string noWaitDirectory; + foreach (Pre pre in preCollection) + { + errFile = string.Concat(pre.CheckFile, ".err"); + checkDirectory = Path.GetDirectoryName(pre.CheckFile); + if (string.IsNullOrEmpty(checkDirectory)) + continue; + if (!Directory.Exists(checkDirectory)) + _ = Directory.CreateDirectory(checkDirectory); + noWaitDirectory = Path.Combine(checkDirectory, "NoWaitDirectory"); + preWith = new(checkDirectory: checkDirectory, + checkFile: pre.CheckFile, + errFile: errFile, + matchingFile: pre.MatchingFile, + noWaitDirectory: noWaitDirectory); + results.Add(preWith); + } + return results.AsReadOnly(); + } + + private static ReadOnlyCollection<string> GetSearchDirectories(int numberLength, string parentDirectory) { List<string> results = new(); string[] directories = Directory.GetDirectories(parentDirectory, "*", SearchOption.TopDirectoryOnly); @@ -115,10 +246,133 @@ public class FileRead : Shared.FileRead, IFileRead results.Add(directory); } results.Sort(); + return results.AsReadOnly(); + } + + private static void CreatePointerFile(int numberLength, string parentDirectory, ReadOnlyCollection<string> matchingFiles) + { + string checkFile; + string writeFile; + string? directoryName; + int parentDirectoryLength = parentDirectory.Length; + foreach (string matchingFile in matchingFiles) + { + directoryName = Path.GetDirectoryName(matchingFile); + if (directoryName is null) + continue; + checkFile = $"{matchingFile[0]}{directoryName.Substring(parentDirectoryLength + numberLength + 1)}"; + writeFile = Path.Combine(parentDirectory, $"{directoryName.Substring(parentDirectory.Length + 1, numberLength)}.txt"); + if (File.Exists(writeFile)) + continue; + File.AppendAllLines(writeFile, new string[] { parentDirectory, matchingFile, directoryName, checkFile }); + } + } + + private static ReadOnlyCollection<Pre> GetPreCollection(int numberLength, string parentDirectory, ReadOnlyCollection<string> matchingFiles) + { + List<Pre> results = new(); + Pre pre; + string checkFile; + int parentDirectoryLength = parentDirectory.Length; + foreach (string matchingFile in matchingFiles) + { + checkFile = $"{matchingFile[0]}{matchingFile.Substring(parentDirectoryLength + numberLength + 1)}"; + pre = new(matchingFile, checkFile); + results.Add(pre); + } + return results.AsReadOnly(); + } + + private void MoveCollection(DateTime dateTime, ProcessDataStandardFormat processDataStandardFormat, ReadOnlyCollection<PreWith> preWithCollection) + { + ReadOnlyCollection<Post> postCollection = GetPostCollection(dateTime, processDataStandardFormat, preWithCollection); + if (postCollection.Count != 0) + { + Thread.Sleep(500); + StringBuilder stringBuilder = new(); + foreach (Post post in postCollection) + { + if (File.Exists(post.ErrFile)) + _ = stringBuilder.AppendLine(File.ReadAllText(post.ErrFile)); + if (File.Exists(post.CheckFile)) + _ = stringBuilder.AppendLine($"<{post.CheckFile}> was not consumed by the end!"); + } + if (stringBuilder.Length > 0) + throw new Exception(stringBuilder.ToString()); + } + } + + private ReadOnlyCollection<Post> GetPostCollection(DateTime dateTime, ProcessDataStandardFormat processDataStandardFormat, ReadOnlyCollection<PreWith> preWithCollection) + { + List<Post> results = new(); + Post post; + long preWait; + foreach (PreWith preWith in preWithCollection) + { + if (!_IsEAFHosted) + continue; + if (!_StaticRuns.TryGetValue(_Logistics.Sequence, out List<Shared.Metrology.WS.Results>? wsResults)) + wsResults = null; + ProcessDataStandardFormat.Write(preWith.CheckFile, processDataStandardFormat, wsResults); + File.Delete(preWith.MatchingFile); + if (Directory.Exists(preWith.NoWaitDirectory)) + { + post = new(preWith.CheckFile, preWith.ErrFile); + results.Add(post); + continue; + } + if (_FileConnectorConfiguration?.FileHandleWaitTime is null) + preWait = DateTime.Now.AddMilliseconds(1234).Ticks; + else + preWait = DateTime.Now.AddMilliseconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; + for (short i = 0; i < short.MaxValue; i++) + { + if (DateTime.Now.Ticks > preWait) + break; + Thread.Sleep(500); + } + for (int i = 0; i < int.MaxValue; i++) + { + if (File.Exists(preWith.ErrFile)) + throw new Exception(File.ReadAllText(preWith.ErrFile)); + if (!File.Exists(preWith.CheckFile)) + break; + if (new TimeSpan(DateTime.Now.Ticks - dateTime.Ticks).TotalSeconds > _BreakAfterSeconds) + throw new Exception($"Not all files were consumed after {_BreakAfterSeconds} second(s)!"); + Thread.Sleep(500); + } + } + return results.AsReadOnly(); + } + + private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) + { + Tuple<string, Test[], JsonElement[], List<FileInfo>> results = new(string.Empty, Array.Empty<Test>(), Array.Empty<JsonElement>(), new List<FileInfo>()); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath, _ProcessDataStandardFormatMapping); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); + if (!_IsEAFHosted) + ProcessDataStandardFormat.Write("../../.pdsf", processDataStandardFormat, wsResults: null); + SetFileParameterLotIDToLogisticsMID(); + int numberLength = 2; + long ticks = dateTime.Ticks; + string parentParentDirectory = GetParentParent(reportFullPath); + ReadOnlyCollection<string> searchDirectories = GetSearchDirectories(numberLength, parentParentDirectory); + ReadOnlyCollection<string> matchingFiles = GetMatchingFiles(ticks, reportFullPath, searchDirectories); + if (matchingFiles.Count != searchDirectories.Count) + throw new Exception($"Didn't find all files after {_BreakAfterSeconds} second(s)!"); + if (_IsEAFHosted) + { + try + { CreatePointerFile(numberLength, parentParentDirectory, matchingFiles); } + catch (Exception) { } + } + ReadOnlyCollection<Pre> preCollection = GetPreCollection(numberLength, parentParentDirectory, matchingFiles); + ReadOnlyCollection<PreWith> preWithCollection = GetPreWithCollection(preCollection); + MoveCollection(dateTime, processDataStandardFormat, preWithCollection); return results; } - private List<string> GetMatchingFiles(long ticks, string reportFullPath, List<string> searchDirectories) + private ReadOnlyCollection<string> GetMatchingFiles(long ticks, string reportFullPath, ReadOnlyCollection<string> searchDirectories) { List<string> results = new(); string[] found; @@ -137,131 +391,7 @@ public class FileRead : Shared.FileRead, IFileRead break; } } - return results; - } - - private static List<(string matchingFile, string checkFile)> GetCollection(int numberLength, string parentDirectory, List<string> matchingFiles) - { - List<(string matchingFile, string checkFile)> results = new(); - string checkFile; - int parentDirectoryLength = parentDirectory.Length; - foreach (string matchingFile in matchingFiles) - { - checkFile = $"{matchingFile[0]}{matchingFile.Substring(parentDirectoryLength + numberLength + 1)}"; - results.Add(new(matchingFile, checkFile)); - } - return results; - } - - private static List<(string, string, string, string, string)> GetCollection(List<(string matchingFile, string checkFile)> collection) - { - List<(string, string, string, string, string)> results = new(); - string errFile; - string checkDirectory; - string noWaitDirectory; - foreach ((string matchingFile, string checkFile) in collection) - { - errFile = string.Concat(checkFile, ".err"); - checkDirectory = Path.GetDirectoryName(checkFile); - if (!Directory.Exists(checkDirectory)) - _ = Directory.CreateDirectory(checkDirectory); - noWaitDirectory = Path.Combine(checkDirectory, "NoWaitDirectory"); - results.Add(new(matchingFile, checkFile, errFile, checkDirectory, noWaitDirectory)); - } - return results; - } - - private void MoveCollection(DateTime dateTime, List<(string matchingFile, string checkFile)> collection) - { - long preWait; - List<(string checkFile, string errFile)> postCollection = new(); - foreach ((string matchingFile, string checkFile, string errFile, string checkDirectory, string noWaitDirectory) in GetCollection(collection)) - { - File.Move(matchingFile, checkFile); - if (Directory.Exists(noWaitDirectory)) - { - postCollection.Add(new(checkFile, errFile)); - continue; - } - if (_FileConnectorConfiguration?.FileHandleWaitTime is null) - preWait = DateTime.Now.AddMilliseconds(1234).Ticks; - else - preWait = DateTime.Now.AddMilliseconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; - for (short i = 0; i < short.MaxValue; i++) - { - if (DateTime.Now.Ticks > preWait) - break; - Thread.Sleep(500); - } - for (int i = 0; i < int.MaxValue; i++) - { - if (File.Exists(errFile)) - throw new Exception(File.ReadAllText(errFile)); - if (!File.Exists(checkFile)) - break; - if (new TimeSpan(DateTime.Now.Ticks - dateTime.Ticks).TotalSeconds > _BreakAfterSeconds) - throw new Exception($"Not all files were consumed after {_BreakAfterSeconds} second(s)!"); - Thread.Sleep(500); - } - } - if (postCollection.Count != 0) - { - Thread.Sleep(500); - StringBuilder stringBuilder = new(); - foreach ((string checkFile, string errFile) in postCollection) - { - if (File.Exists(errFile)) - _ = stringBuilder.AppendLine(File.ReadAllText(errFile)); - if (File.Exists(checkFile)) - _ = stringBuilder.AppendLine($"<{checkFile}> was not consumed by the end!"); - } - if (stringBuilder.Length > 0) - throw new Exception(stringBuilder.ToString()); - } - } - - private static void CreatePointerFile(int numberLength, string parentDirectory, List<string> matchingFiles) - { -#nullable enable - string checkFile; - string writeFile; - string? directoryName; - int parentDirectoryLength = parentDirectory.Length; - foreach (string matchingFile in matchingFiles) - { - directoryName = Path.GetDirectoryName(matchingFile); - if (directoryName is null) - continue; - checkFile = $"{matchingFile[0]}{directoryName.Substring(parentDirectoryLength + numberLength + 1)}"; - writeFile = Path.Combine(parentDirectory, $"{directoryName.Substring(parentDirectory.Length + 1, numberLength)}.txt"); - if (File.Exists(writeFile)) - continue; - File.AppendAllLines(writeFile, new string[] { parentDirectory, matchingFile, directoryName, checkFile }); - } -#nullable disable - } - - private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) - { - Tuple<string, Test[], JsonElement[], List<FileInfo>> results = new(string.Empty, null, null, new List<FileInfo>()); - Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath); - _Logistics = new Logistics(reportFullPath, pdsf.Item1); - SetFileParameterLotIDToLogisticsMID(); - if (string.IsNullOrEmpty(_Logistics.JobID) || _Logistics.JobID == "null") - throw new NotSupportedException("JobId is null! Please update Logistics."); - int numberLength = 2; - long ticks = dateTime.Ticks; - string parentParentDirectory = GetParentParent(reportFullPath); - List<string> searchDirectories = GetSearchDirectories(numberLength, parentParentDirectory); - List<string> matchingFiles = GetMatchingFiles(ticks, reportFullPath, searchDirectories); - if (matchingFiles.Count != searchDirectories.Count) - throw new Exception($"Didn't find all files after {_BreakAfterSeconds} second(s)!"); - try - { CreatePointerFile(numberLength, parentParentDirectory, matchingFiles); } - catch (Exception) { } - List<(string matchingFile, string checkFile)> collection = GetCollection(numberLength, parentParentDirectory, matchingFiles); - MoveCollection(dateTime, collection); - return results; + return results.AsReadOnly(); } } \ No newline at end of file diff --git a/Adaptation/FileHandlers/Processed/FileRead.cs b/Adaptation/FileHandlers/Processed/FileRead.cs index cf64e0a..32635a0 100644 --- a/Adaptation/FileHandlers/Processed/FileRead.cs +++ b/Adaptation/FileHandlers/Processed/FileRead.cs @@ -17,7 +17,7 @@ public class FileRead : Shared.FileRead, IFileRead private readonly string _JobIdParentDirectory; private readonly string _JobIdProcessParentDirectory; - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; @@ -129,6 +129,7 @@ public class FileRead : Shared.FileRead, IFileRead string destinationJobIdDirectory = Path.Combine(_JobIdProcessParentDirectory, _Logistics.JobID, directoryName); string sequenceDirectory = Path.Combine(destinationJobIdDirectory, logisticsSequence); // string jsonFileName = Path.Combine(sequenceDirectory, $"{Path.GetFileNameWithoutExtension(reportFullPath)}.json"); + MoveMatchingFile(jobIdDirectory, matchDirectories[0]); Directory.Move(matchDirectories[0], destinationJobIdDirectory); if (!Directory.Exists(sequenceDirectory)) _ = Directory.CreateDirectory(sequenceDirectory); @@ -136,16 +137,40 @@ public class FileRead : Shared.FileRead, IFileRead // File.WriteAllText(jsonFileName, json); } + private static void MoveMatchingFile(string jobIdDirectory, string matchDirectory) + { + string checkFile; + string jobIdDirectoryFileName; + string matchDirectoryFileName; + string[] jobIdDirectoryFiles = Directory.GetFiles(jobIdDirectory, "*", SearchOption.TopDirectoryOnly); + string[] matchDirectoryFiles = Directory.GetFiles(matchDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string jobIdDirectoryFile in jobIdDirectoryFiles) + { + jobIdDirectoryFileName = Path.GetFileName(jobIdDirectoryFile); + foreach (string matchDirectoryFile in matchDirectoryFiles) + { + matchDirectoryFileName = Path.GetFileName(matchDirectoryFile); + if (jobIdDirectoryFileName.StartsWith(matchDirectoryFileName)) + { + checkFile = Path.Combine(matchDirectory, jobIdDirectoryFileName); + if (File.Exists(checkFile)) + continue; + File.Move(jobIdDirectoryFile, checkFile); + } + } + } + } + private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple<string, Test[], JsonElement[], List<FileInfo>> results; - Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath); - _Logistics = new Logistics(reportFullPath, pdsf.Item1); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(pdsf); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); List<csv.Description> descriptions = csv.ProcessData.GetDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); - results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(pdsf.Item1, tests, jsonElements, new List<FileInfo>()); + results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List<FileInfo>()); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) DirectoryMove(reportFullPath, dateTime, descriptions); else if (!_IsEAFHosted) diff --git a/Adaptation/FileHandlers/SPaCe/FileRead.cs b/Adaptation/FileHandlers/SPaCe/FileRead.cs index a8155b6..2e0f55a 100644 --- a/Adaptation/FileHandlers/SPaCe/FileRead.cs +++ b/Adaptation/FileHandlers/SPaCe/FileRead.cs @@ -14,7 +14,7 @@ namespace Adaptation.FileHandlers.SPaCe; public class FileRead : Shared.FileRead, IFileRead { - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : base(new Description(), false, smtp, fileParameter, cellInstanceName, connectionCount, cellInstanceConnectionName, fileConnectorConfiguration, equipmentTypeName, parameterizedModelObjectDefinitionType, modelObjectParameters, equipmentDictionaryName, dummyRuns, staticRuns, useCyclicalForDescription, isEAFHosted: connectionCount is null) { _MinFileLength = 10; @@ -117,15 +117,15 @@ public class FileRead : Shared.FileRead, IFileRead private Tuple<string, Test[], JsonElement[], List<FileInfo>> GetExtractResult(string reportFullPath, DateTime dateTime) { Tuple<string, Test[], JsonElement[], List<FileInfo>> results; - Tuple<string, string[], string[]> pdsf = ProcessDataStandardFormat.GetLogisticsColumnsAndBody(reportFullPath); - _Logistics = new Logistics(reportFullPath, pdsf.Item1); + ProcessDataStandardFormat processDataStandardFormat = ProcessDataStandardFormat.GetProcessDataStandardFormat(reportFullPath); + _Logistics = new Logistics(reportFullPath, processDataStandardFormat); SetFileParameterLotIDToLogisticsMID(); - JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(pdsf); + JsonElement[] jsonElements = ProcessDataStandardFormat.GetArray(processDataStandardFormat); List<Shared.Properties.IDescription> descriptions = GetDuplicatorDescriptions(jsonElements); Test[] tests = (from l in descriptions select (Test)l.Test).ToArray(); if (_IsEAFHosted && _FileConnectorConfiguration.FileScanningIntervalInSeconds > 0) FileCopy(reportFullPath, dateTime, descriptions); - results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(pdsf.Item1, tests, jsonElements, new List<FileInfo>()); + results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(string.Join(Environment.NewLine, processDataStandardFormat.Logistics[0]), tests, jsonElements, new List<FileInfo>()); return results; } diff --git a/Adaptation/FileHandlers/csv/Description.cs b/Adaptation/FileHandlers/csv/Description.cs index 6aa5505..5382a8c 100644 --- a/Adaptation/FileHandlers/csv/Description.cs +++ b/Adaptation/FileHandlers/csv/Description.cs @@ -24,7 +24,7 @@ public class Description : IDescription, Shared.Properties.IDescription public string MID { get; set; } // public string Date { get; set; } - public string Lot { get; set; } + public string RDS { get; set; } public string Part { get; set; } public string Process { get; set; } public string Recipe { get; set; } @@ -65,7 +65,7 @@ public class Description : IDescription, Shared.Properties.IDescription List<string> results = new() { nameof(Date), - nameof(Lot), + nameof(RDS), nameof(Part), nameof(Process), nameof(Recipe) @@ -165,7 +165,7 @@ public class Description : IDescription, Shared.Properties.IDescription MID = logistics.MID, // Date = detail.Date, - Lot = processData.MetaData.Date, + RDS = processData.MetaData.Date, Part = $"{processData.MetaData.DeviceId}-{processData.MetaData.DeviceType}-{processData.MetaData.DeviceNumber}", Process = $"{processData.MetaData.DescriptionName}", Recipe = processData.MetaData.Frequency, @@ -204,7 +204,7 @@ public class Description : IDescription, Shared.Properties.IDescription MID = logistics.MID, // Date = nameof(Date), - Lot = nameof(Lot), + RDS = nameof(RDS), Part = nameof(Part), Process = nameof(Process), Recipe = nameof(Recipe), diff --git a/Adaptation/FileHandlers/csv/FileRead.cs b/Adaptation/FileHandlers/csv/FileRead.cs index a0e0526..e75e215 100644 --- a/Adaptation/FileHandlers/csv/FileRead.cs +++ b/Adaptation/FileHandlers/csv/FileRead.cs @@ -15,7 +15,7 @@ public class FileRead : Shared.FileRead, IFileRead private long? _TickOffset; private readonly CommaSeparatedValuesConfiguration _CommaSeparatedValuesConfiguration; - public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) : + public FileRead(ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> 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 = 1000; diff --git a/Adaptation/FileHandlers/csv/ProcessData.cs b/Adaptation/FileHandlers/csv/ProcessData.cs index bcc727e..f4c7763 100644 --- a/Adaptation/FileHandlers/csv/ProcessData.cs +++ b/Adaptation/FileHandlers/csv/ProcessData.cs @@ -25,7 +25,6 @@ public class ProcessData : IProcessData public ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, CommaSeparatedValuesConfiguration commaSeparatedValuesConfiguration, MetaData metaData) { JobID = logistics.JobID; - fileInfoCollection.Clear(); _Details = new List<object>(); MesEntity = logistics.MesEntity; Parse(fileRead, logistics, fileInfoCollection, commaSeparatedValuesConfiguration, metaData); @@ -49,9 +48,13 @@ public class ProcessData : IProcessData if (description.Test != (int)tests[i]) throw new Exception(); } + FileInfo fileInfo = new($"{logistics.ReportFullPath}.descriptions.json"); List<Description> fileReadDescriptions = (from l in descriptions select (Description)l).ToList(); string json = JsonSerializer.Serialize(fileReadDescriptions, fileReadDescriptions.GetType()); - JsonElement[] jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json); + File.WriteAllText(fileInfo.FullName, json); + File.SetLastWriteTime(fileInfo.FullName, logistics.DateTimeFromSequence); + fileInfoCollection.Add(fileInfo); + JsonElement[] jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json) ?? throw new Exception(); results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(logistics.Logistics1[0], tests.ToArray(), jsonElements, fileInfoCollection); return results; } diff --git a/Adaptation/METCLIMATEC.Tests.csproj b/Adaptation/METCLIMATEC.Tests.csproj index ff36bdc..5d76a08 100644 --- a/Adaptation/METCLIMATEC.Tests.csproj +++ b/Adaptation/METCLIMATEC.Tests.csproj @@ -69,7 +69,7 @@ <PackageReference Include="System.Text.Json" Version="9.0.0" /> </ItemGroup> <ItemGroup> - <PackageReference Include="Infineon.Mesa.PDF.Text.Stripper" Version="4.8.0.1"><NoWarn>NU1701</NoWarn></PackageReference> + <PackageReference Include="Infineon.Mesa.PDF.Text.Stripper" Version="4.8.0.2"><NoWarn>NU1701</NoWarn></PackageReference> </ItemGroup> <ItemGroup> <PackageReference Include="Infineon.Yoda.DotNetCore" Version="5.4.3" /> diff --git a/Adaptation/Shared/Duplicator/Description.cs b/Adaptation/Shared/Duplicator/Description.cs index f725b29..964612e 100644 --- a/Adaptation/Shared/Duplicator/Description.cs +++ b/Adaptation/Shared/Duplicator/Description.cs @@ -12,7 +12,7 @@ public class Description : IDescription, Properties.IDescription public int Test { get; set; } public int Count { get; set; } public int Index { get; set; } - public string Lot { get; set; } + public string RDS { get; set; } // public string EventName { get; set; } public string NullData { get; set; } @@ -141,7 +141,7 @@ public class Description : IDescription, Properties.IDescription MID = logistics.MID, // Date = DateTime.Now.ToString(GetDateFormat()), - Lot = string.Empty, + RDS = string.Empty, }; results.Add(description); } diff --git a/Adaptation/Shared/FileRead.cs b/Adaptation/Shared/FileRead.cs index 464ef0b..96dcd56 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<string, List<long>> _DummyRuns; protected readonly Dictionary<string, string> _FileParameter; - protected readonly Dictionary<long, List<string>> _StaticRuns; protected readonly string _ParameterizedModelObjectDefinitionType; protected readonly FileConnectorConfiguration _FileConnectorConfiguration; + protected readonly Dictionary<long, List<Metrology.WS.Results>> _StaticRuns; protected readonly IList<ModelObjectParameterDefinition> _ModelObjectParameterDefinitions; bool Properties.IFileRead.IsEvent => _IsEvent; @@ -63,203 +63,6 @@ public class FileRead : Properties.IFileRead string Properties.IFileRead.CellInstanceConnectionName => _CellInstanceConnectionName; string Properties.IFileRead.ParameterizedModelObjectDefinitionType => _ParameterizedModelObjectDefinitionType; - public FileRead(IDescription description, bool isEvent, ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<string>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) - { - _SMTP = smtp; - _IsEvent = isEvent; - _DummyRuns = dummyRuns; - _LastTicksDuration = 0; - _StaticRuns = staticRuns; - _IsEAFHosted = isEAFHosted; - _Description = description; - _FileParameter = fileParameter; - _ReportFullPath = string.Empty; - _CellInstanceName = cellInstanceName; - _Calendar = new CultureInfo("en-US").Calendar; - _Log = LogManager.GetLogger(typeof(FileRead)); - _UseCyclicalForDescription = useCyclicalForDescription; - _CellInstanceConnectionName = cellInstanceConnectionName; - _ModelObjectParameterDefinitions = modelObjectParameters; - _FileConnectorConfiguration = fileConnectorConfiguration; - _ParameterizedModelObjectDefinitionType = parameterizedModelObjectDefinitionType; - _IsSourceTimer = fileConnectorConfiguration.SourceFileFilter.StartsWith("*Timer.txt"); - string cellInstanceConnectionNameBase = cellInstanceConnectionName.Replace("-", string.Empty); - _Hyphens = cellInstanceConnectionName.Length - cellInstanceConnectionNameBase.Length; - _TracePath = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "Path.Trace"); - _ExceptionSubject = string.Concat("Exception:", _CellInstanceConnectionName, _FileConnectorConfiguration?.SourceDirectoryCloaking); - string suffix; - string[] segments = _ParameterizedModelObjectDefinitionType.Split('.'); - string @namespace = segments[0]; - string eventNameFileRead = "FileRead"; - string eventName = segments[segments.Length - 1]; - bool isDuplicator = segments[0] == cellInstanceName; - _IsDuplicator = isDuplicator; - _CellInstanceConnectionNameBase = cellInstanceConnectionNameBase; - if (eventName == eventNameFileRead) - suffix = string.Empty; - else - suffix = string.Concat('_', eventName.Split(new string[] { eventNameFileRead }, StringSplitOptions.RemoveEmptyEntries)[1]); - string parameterizedModelObjectDefinitionTypeAppended = string.Concat(@namespace, suffix); - if (!isEAFHosted) - { - if (string.IsNullOrEmpty(equipmentTypeName) || equipmentTypeName != parameterizedModelObjectDefinitionTypeAppended) - throw new Exception(cellInstanceConnectionName); - if (string.IsNullOrEmpty(equipmentDictionaryName) && isEvent) - throw new Exception(cellInstanceConnectionName); - if (!string.IsNullOrEmpty(equipmentDictionaryName) && !isEvent && connectionCount > 1) - throw new Exception(cellInstanceConnectionName); - // if (string.IsNullOrEmpty(equipmentDictionaryName) && !isEvent) - // throw new Exception(cellInstanceConnectionName); - // if (!string.IsNullOrEmpty(equipmentDictionaryName) && isEvent) - // throw new Exception(cellInstanceConnectionName); - } - if (isDuplicator) - _MesEntity = string.Empty; - else - _MesEntity = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, string.Concat("CellInstance.", cellInstanceName, ".Alias")); - _EventName = eventName; - _EventNameFileRead = eventNameFileRead; - _EquipmentType = parameterizedModelObjectDefinitionTypeAppended; - long breakAfterSeconds; - if (_FileConnectorConfiguration is null) - breakAfterSeconds = 360; - else - { - if (_FileConnectorConfiguration.FileScanningOption == FileConnectorConfiguration.FileScanningOptionEnum.TimeBased) - breakAfterSeconds = Math.Abs(_FileConnectorConfiguration.FileHandleTimeout.Value); - else if (_FileConnectorConfiguration.FileScanningOption == FileConnectorConfiguration.FileScanningOptionEnum.FileWatcher) - breakAfterSeconds = Math.Abs(_FileConnectorConfiguration.FileScanningIntervalInSeconds.Value); - else - throw new Exception(); - } - _BreakAfterSeconds = breakAfterSeconds; - UpdateLastTicksDuration(breakAfterSeconds * 10000000); - if (_IsDuplicator) - { - if (string.IsNullOrEmpty(_FileConnectorConfiguration.TargetFileLocation) || string.IsNullOrEmpty(_FileConnectorConfiguration.ErrorTargetFileLocation)) - throw new Exception("_Configuration is empty?"); - if (_FileConnectorConfiguration.TargetFileLocation.Contains('%') || _FileConnectorConfiguration.ErrorTargetFileLocation.Contains('%')) - throw new Exception("_Configuration is incorrect for a duplicator!"); - // if (_FileConnectorConfiguration is not null) - // { - // if (string.IsNullOrEmpty(_FileConnectorConfiguration.SourceDirectoryCloaking)) - // throw new Exception("SourceDirectoryCloaking is empty?"); - // if (!_FileConnectorConfiguration.SourceDirectoryCloaking.StartsWith("~")) - // throw new Exception("SourceDirectoryCloaking is incorrect for a duplicator!"); - // } - } - } - - protected static string GetPropertyValue(string cellInstanceConnectionName, IList<ModelObjectParameterDefinition> modelObjectParameters, string propertyName) - { - string result; - List<string> results = (from l in modelObjectParameters where l.Name == propertyName select l.Value).ToList(); - if (results.Count != 1) - throw new Exception(cellInstanceConnectionName); - result = results[0]; - return result; - } - - protected static ModelObjectParameterDefinition[] GetProperties(string cellInstanceConnectionName, IList<ModelObjectParameterDefinition> modelObjectParameters, string propertyNamePrefix) - { - ModelObjectParameterDefinition[] results = (from l in modelObjectParameters where l.Name.StartsWith(propertyNamePrefix) select l).ToArray(); - if (results.Length == 0) - throw new Exception(cellInstanceConnectionName); - return results; - } - - protected static ModelObjectParameterDefinition[] GetProperties(string cellInstanceConnectionName, IList<ModelObjectParameterDefinition> 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.Length == 0) - throw new Exception(cellInstanceConnectionName); - return results; - } - - 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}>"); - } - - protected void WaitForThread(Thread thread, List<Exception> threadExceptions) - { - if (thread is not null) - { - ThreadState threadState; - for (short i = 0; i < short.MaxValue; i++) - { - if (thread is null) - break; - else - { - threadState = thread.ThreadState; - if (threadState is not ThreadState.Running and not ThreadState.WaitSleepJoin) - break; - } - Thread.Sleep(500); - } - lock (threadExceptions) - { - if (threadExceptions.Count != 0) - { - foreach (Exception item in threadExceptions) - _Log.Error(string.Concat(item.Message, Environment.NewLine, Environment.NewLine, item.StackTrace)); - Exception exception = threadExceptions[0]; - threadExceptions.Clear(); - throw exception; - } - } - } - } - - 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<string, Test[], JsonElement[], List<FileInfo>> 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<string>(); - 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.Count != 0) - { - string itemFile; - List<string> 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<T>(Logistics logistics, List<T> descriptions, Properties.IScopeInfo scopeInfo, string duplicateDirectory, string duplicateFile) where T : Properties.IDescription { string result; @@ -268,10 +71,10 @@ public class FileRead : Properties.IFileRead string dateValue; string rdsPlaceholder = "%RDS%"; string mesEntityPlaceholder = "%MesEntity%"; - if (descriptions.Count == 0 || string.IsNullOrEmpty(descriptions[0].Lot)) + if (descriptions.Count == 0 || string.IsNullOrEmpty(descriptions[0].RDS)) rds = logistics.MID; else - rds = descriptions[0].Lot; + 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)); @@ -384,191 +187,131 @@ public class FileRead : Properties.IFileRead } } - protected void SetFileParameter(string key, string value) + protected void WaitForFileConsumption<T>(DateTime dateTime, List<T> descriptions, bool isDummyRun, string successDirectory, string duplicateDirectory, List<(Properties.IScopeInfo, string)> collection, string duplicateFile) where T : Properties.IDescription { - 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"; + if (!isDummyRun && _IsEAFHosted) + WaitForFileConsumption(_FileConnectorConfiguration.SourceDirectoryCloaking, _Logistics, dateTime, descriptions, successDirectory, duplicateDirectory, duplicateFile, collection); 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; - string weekOfYear = _Calendar.GetWeekOfYear(_Logistics.DateTimeFromSequence, CalendarWeekRule.FirstDay, DayOfWeek.Sunday).ToString("00"); - string weekDirectory = $"{_Logistics.DateTimeFromSequence:yyyy}_Week_{weekOfYear}{@"\"}{_Logistics.DateTimeFromSequence:yyyy-MM-dd}"; - if (!_CellInstanceConnectionName.StartsWith(_CellInstanceName) && _CellInstanceConnectionNameBase == _EquipmentType) - directory = Path.Combine(_TracePath, _EquipmentType, "Target", weekDirectory, _CellInstanceName, _CellInstanceConnectionName); - else - directory = Path.Combine(_TracePath, _EquipmentType, "Source", weekDirectory, _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<string, Test[], JsonElement[], List<FileInfo>> extractResults) - { - if (!_IsEAFHosted) - { - string to; - if (!_FileConnectorConfiguration.TargetFileLocation.EndsWith(Path.DirectorySeparatorChar.ToString())) - to = _FileConnectorConfiguration.TargetFileLocation; - else - to = Path.GetDirectoryName(_FileConnectorConfiguration.TargetFileLocation); - foreach (KeyValuePair<string, string> keyValuePair in _FileParameter) - to = to.Replace(string.Concat('%', keyValuePair.Key, '%'), keyValuePair.Value); - if (to.Contains('%')) - _Log.Debug("Can't debug without EAF Hosting"); - else - _ = Move(extractResults, to, _FileConnectorConfiguration.SourceFileLocation, resolvedFileLocation: string.Empty, exception: null); - } - } - - protected void TriggerEvents(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults, List<string> headerNames, Dictionary<string, string> keyValuePairs) - { - object value; - string segments; - string description; - List<object[]> 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()) + long breakAfter = DateTime.Now.AddSeconds(_FileConnectorConfiguration.FileHandleWaitTime.Value).Ticks; + for (short i = 0; i < short.MaxValue; i++) { - 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<object[]>(); - 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<string, Test[], JsonElement[], List<FileInfo>> ReExtract(IFileRead fileRead, List<string> headerNames, Dictionary<string, string> keyValuePairs) - { - Tuple<string, Test[], JsonElement[], List<FileInfo>> results; - if (!Directory.Exists(_FileConnectorConfiguration.SourceFileLocation)) - results = null; - else - { - string[] segments; - string[] matches = null; - foreach (string subSourceFileFilter in _FileConnectorConfiguration.SourceFileFilters) - { - 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.Length != 0) + if (!_IsEAFHosted || DateTime.Now.Ticks > breakAfter) break; - } - if (matches is null || matches.Length == 0) - results = null; - else - { - _ReportFullPath = matches[0]; - results = fileRead.GetExtractResult(_ReportFullPath, _EventName); - if (!_IsEAFHosted) - TriggerEvents(results, headerNames, keyValuePairs); + Thread.Sleep(500); } } - return results; } - protected static List<Properties.IDescription> GetDuplicatorDescriptions(JsonElement[] jsonElements) + public FileRead(IDescription description, bool isEvent, ISMTP smtp, Dictionary<string, string> fileParameter, string cellInstanceName, int? connectionCount, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, Dictionary<string, List<long>> dummyRuns, Dictionary<long, List<Shared.Metrology.WS.Results>> staticRuns, bool useCyclicalForDescription, bool isEAFHosted) { - List<Properties.IDescription> results = new(); - Duplicator.Description description; - JsonSerializerOptions jsonSerializerOptions = new() { NumberHandling = JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString }; - foreach (JsonElement jsonElement in jsonElements) + _SMTP = smtp; + _IsEvent = isEvent; + _DummyRuns = dummyRuns; + _LastTicksDuration = 0; + _StaticRuns = staticRuns; + _IsEAFHosted = isEAFHosted; + _Description = description; + _FileParameter = fileParameter; + _ReportFullPath = string.Empty; + _CellInstanceName = cellInstanceName; + _Calendar = new CultureInfo("en-US").Calendar; + _Log = LogManager.GetLogger(typeof(FileRead)); + _UseCyclicalForDescription = useCyclicalForDescription; + _CellInstanceConnectionName = cellInstanceConnectionName; + _ModelObjectParameterDefinitions = modelObjectParameters; + _FileConnectorConfiguration = fileConnectorConfiguration; + _ParameterizedModelObjectDefinitionType = parameterizedModelObjectDefinitionType; + _IsSourceTimer = fileConnectorConfiguration.SourceFileFilter.StartsWith("*Timer.txt"); + string cellInstanceConnectionNameBase = cellInstanceConnectionName.Replace("-", string.Empty); + _Hyphens = cellInstanceConnectionName.Length - cellInstanceConnectionNameBase.Length; + _TracePath = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, "Path.Trace"); + _ExceptionSubject = string.Concat("Exception:", _CellInstanceConnectionName, _FileConnectorConfiguration?.SourceDirectoryCloaking); + string suffix; + string[] segments = _ParameterizedModelObjectDefinitionType.Split('.'); + string @namespace = segments[0]; + string eventNameFileRead = "FileRead"; + string eventName = segments[segments.Length - 1]; + bool isDuplicator = segments[0] == cellInstanceName; + _IsDuplicator = isDuplicator; + _CellInstanceConnectionNameBase = cellInstanceConnectionNameBase; + if (eventName == eventNameFileRead) + suffix = string.Empty; + else + suffix = string.Concat('_', eventName.Split(new string[] { eventNameFileRead }, StringSplitOptions.RemoveEmptyEntries)[1]); + string parameterizedModelObjectDefinitionTypeAppended = string.Concat(@namespace, suffix); + if (!isEAFHosted) { - if (jsonElement.ValueKind != JsonValueKind.Object) + if (string.IsNullOrEmpty(equipmentTypeName) || equipmentTypeName != parameterizedModelObjectDefinitionTypeAppended) + throw new Exception(cellInstanceConnectionName); + if (string.IsNullOrEmpty(equipmentDictionaryName) && isEvent) + throw new Exception(cellInstanceConnectionName); + if (!string.IsNullOrEmpty(equipmentDictionaryName) && !isEvent && connectionCount > 1) + throw new Exception(cellInstanceConnectionName); + // if (string.IsNullOrEmpty(equipmentDictionaryName) && !isEvent) + // throw new Exception(cellInstanceConnectionName); + // if (!string.IsNullOrEmpty(equipmentDictionaryName) && isEvent) + // throw new Exception(cellInstanceConnectionName); + } + if (isDuplicator) + _MesEntity = string.Empty; + else + _MesEntity = GetPropertyValue(cellInstanceConnectionName, modelObjectParameters, string.Concat("CellInstance.", cellInstanceName, ".Alias")); + _EventName = eventName; + _EventNameFileRead = eventNameFileRead; + _EquipmentType = parameterizedModelObjectDefinitionTypeAppended; + long breakAfterSeconds; + if (_FileConnectorConfiguration is null) + breakAfterSeconds = 360; + else + { + if (_FileConnectorConfiguration.FileScanningOption == FileConnectorConfiguration.FileScanningOptionEnum.TimeBased) + breakAfterSeconds = Math.Abs(_FileConnectorConfiguration.FileHandleTimeout.Value); + else if (_FileConnectorConfiguration.FileScanningOption == FileConnectorConfiguration.FileScanningOptionEnum.FileWatcher) + breakAfterSeconds = Math.Abs(_FileConnectorConfiguration.FileScanningIntervalInSeconds.Value); + else throw new Exception(); - description = JsonSerializer.Deserialize<Duplicator.Description>(jsonElement.ToString(), jsonSerializerOptions); - results.Add(description); } - return results; + _BreakAfterSeconds = breakAfterSeconds; + UpdateLastTicksDuration(breakAfterSeconds * 10000000); + if (_IsDuplicator) + { + if (string.IsNullOrEmpty(_FileConnectorConfiguration.TargetFileLocation) || string.IsNullOrEmpty(_FileConnectorConfiguration.ErrorTargetFileLocation)) + throw new Exception("_Configuration is empty?"); + if (_FileConnectorConfiguration.TargetFileLocation.Contains('%') || _FileConnectorConfiguration.ErrorTargetFileLocation.Contains('%')) + throw new Exception("_Configuration is incorrect for a duplicator!"); + // if (_FileConnectorConfiguration is not null) + // { + // if (string.IsNullOrEmpty(_FileConnectorConfiguration.SourceDirectoryCloaking)) + // throw new Exception("SourceDirectoryCloaking is empty?"); + // if (!_FileConnectorConfiguration.SourceDirectoryCloaking.StartsWith("~")) + // throw new Exception("SourceDirectoryCloaking is incorrect for a duplicator!"); + // } + } } - private void Shared1880(string itemFile, List<string> directories, FileInfo sourceFile, bool isErrorFile) + protected static string GetPropertyValue(string cellInstanceConnectionName, IList<ModelObjectParameterDefinition> modelObjectParameters, string propertyName) { - string itemDirectory; - directories.Add(Path.GetDirectoryName(sourceFile.FullName)); - itemDirectory = Path.GetDirectoryName(itemFile); - FileConnectorConfiguration.PostProcessingModeEnum processingModeEnum; - if (!isErrorFile) - processingModeEnum = _FileConnectorConfiguration.PostProcessingMode.Value; - else - processingModeEnum = _FileConnectorConfiguration.ErrorPostProcessingMode.Value; - if (processingModeEnum != FileConnectorConfiguration.PostProcessingModeEnum.Delete && !Directory.Exists(itemDirectory)) - { - _ = Directory.CreateDirectory(itemDirectory); - FileInfo fileInfo = new(_Logistics.ReportFullPath); - Directory.SetCreationTime(itemDirectory, fileInfo.LastWriteTime); - } - if (_IsEAFHosted) - { - switch (processingModeEnum) - { - case FileConnectorConfiguration.PostProcessingModeEnum.Move: - File.Move(sourceFile.FullName, itemFile); - break; - case FileConnectorConfiguration.PostProcessingModeEnum.Copy: - File.Copy(sourceFile.FullName, itemFile); - break; - case FileConnectorConfiguration.PostProcessingModeEnum.Delete: - File.Delete(sourceFile.FullName); - break; - default: - throw new Exception(); - } - } + string result; + List<string> results = (from l in modelObjectParameters where l.Name == propertyName select l.Value).ToList(); + if (results.Count != 1) + throw new Exception(cellInstanceConnectionName); + result = results[0]; + 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<string> GetDirectoryNames(string directory) @@ -609,6 +352,326 @@ public class FileRead : Properties.IFileRead #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<string> 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<Properties.IDescription> GetDuplicatorDescriptions(JsonElement[] jsonElements) + { + List<Properties.IDescription> 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<Duplicator.Description>(jsonElement.ToString(), jsonSerializerOptions); + results.Add(description); + } + return results; + } + + protected static ModelObjectParameterDefinition[] GetProperties(string cellInstanceConnectionName, IList<ModelObjectParameterDefinition> modelObjectParameters, string propertyNamePrefix) + { + ModelObjectParameterDefinition[] results = (from l in modelObjectParameters where l.Name.StartsWith(propertyNamePrefix) select l).ToArray(); + if (results.Length == 0) + throw new Exception(cellInstanceConnectionName); + return results; + } + + protected static ModelObjectParameterDefinition[] GetProperties(string cellInstanceConnectionName, IList<ModelObjectParameterDefinition> 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.Length == 0) + throw new Exception(cellInstanceConnectionName); + return results; + } + + 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 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<Exception> threadExceptions) + { + if (thread is not null) + { + ThreadState threadState; + for (short i = 0; i < short.MaxValue; i++) + { + if (thread is null) + break; + else + { + threadState = thread.ThreadState; + if (threadState is not ThreadState.Running and not ThreadState.WaitSleepJoin) + break; + } + Thread.Sleep(500); + } + lock (threadExceptions) + { + if (threadExceptions.Count != 0) + { + foreach (Exception item in threadExceptions) + _Log.Error(string.Concat(item.Message, Environment.NewLine, Environment.NewLine, item.StackTrace)); + Exception exception = threadExceptions[0]; + threadExceptions.Clear(); + throw exception; + } + } + } + } + + protected void Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResults) + { + if (!_IsEAFHosted) + { + string to; + if (!_FileConnectorConfiguration.TargetFileLocation.EndsWith(Path.DirectorySeparatorChar.ToString())) + to = _FileConnectorConfiguration.TargetFileLocation; + else + to = Path.GetDirectoryName(_FileConnectorConfiguration.TargetFileLocation); + foreach (KeyValuePair<string, string> keyValuePair in _FileParameter) + to = to.Replace(string.Concat('%', keyValuePair.Key, '%'), keyValuePair.Value); + if (to.Contains('%')) + _Log.Debug("Can't debug without EAF Hosting"); + else + _ = Move(extractResults, to, _FileConnectorConfiguration.SourceFileLocation, resolvedFileLocation: string.Empty, exception: null); + } + } + + protected string[] Move(Tuple<string, Test[], JsonElement[], List<FileInfo>> 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<string>(); + 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.Count != 0) + { + string itemFile; + List<string> 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; + } + + 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); } + } + + private void Shared1880(string itemFile, List<string> directories, FileInfo sourceFile, bool isErrorFile) + { + string itemDirectory; + directories.Add(Path.GetDirectoryName(sourceFile.FullName)); + itemDirectory = Path.GetDirectoryName(itemFile); + FileConnectorConfiguration.PostProcessingModeEnum processingModeEnum; + if (!isErrorFile) + processingModeEnum = _FileConnectorConfiguration.PostProcessingMode.Value; + else + processingModeEnum = _FileConnectorConfiguration.ErrorPostProcessingMode.Value; + if (processingModeEnum != FileConnectorConfiguration.PostProcessingModeEnum.Delete && !Directory.Exists(itemDirectory)) + { + _ = Directory.CreateDirectory(itemDirectory); + FileInfo fileInfo = new(_Logistics.ReportFullPath); + Directory.SetCreationTime(itemDirectory, fileInfo.LastWriteTime); + } + if (_IsEAFHosted) + { + switch (processingModeEnum) + { + case FileConnectorConfiguration.PostProcessingModeEnum.Move: + File.Move(sourceFile.FullName, itemFile); + break; + case FileConnectorConfiguration.PostProcessingModeEnum.Copy: + File.Copy(sourceFile.FullName, itemFile); + break; + case FileConnectorConfiguration.PostProcessingModeEnum.Delete: + File.Delete(sourceFile.FullName); + break; + case FileConnectorConfiguration.PostProcessingModeEnum.None: + File.Move(sourceFile.FullName, itemFile); + break; + default: + throw new Exception(); + } + } + } + + private void Shared1811(string to, FileInfo sourceFile) + { + if (!_IsDuplicator && _FileConnectorConfiguration.SourceFileFilter != "*" && sourceFile.Exists && sourceFile.Length < _MinFileLength) + { + string directoryName = Path.GetFileName(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}"; + 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)); + try + { + string[] checkDirectories = Directory.GetDirectories(jobIdDirectory, "*", SearchOption.TopDirectoryOnly); + foreach (string checkDirectory in checkDirectories) + { + if (!checkDirectory.Contains('_')) + continue; + if (Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly).Length != 0) + continue; + if (Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly).Length != 0) + continue; + if (Directory.GetDirectories(checkDirectory, "*", SearchOption.AllDirectories).Length != 0) + continue; + if (Directory.GetFiles(checkDirectory, "*", SearchOption.AllDirectories).Length != 0) + continue; + if (new DirectoryInfo(checkDirectory).CreationTime > dateTime) + continue; + Directory.Delete(checkDirectory, recursive: false); + } + } + catch (Exception) { throw; } + DeleteEmptyTopDirectories(jobIdDirectory); + } + } + private string GetJobIdDirectory(string path) { string result; @@ -654,44 +717,6 @@ public class FileRead : Properties.IFileRead } } - private void Shared1811(string to, FileInfo sourceFile) - { - if (!_IsDuplicator && _FileConnectorConfiguration.SourceFileFilter != "*" && sourceFile.Exists && sourceFile.Length < _MinFileLength) - { - string directoryName = Path.GetFileName(to); - string jobIdDirectory = GetJobIdDirectory(to); - DateTime dateTime = DateTime.Now.AddMinutes(-15); - 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 = Path.Combine(jobIdDirectory, "_ Ignore 100 bytes", weekDirectory, directoryName); - if (!Directory.Exists(destinationDirectory)) - _ = Directory.CreateDirectory(destinationDirectory); - File.Move(sourceFile.FullName, string.Concat(destinationDirectory, @"\", sourceFile.Name)); - try - { - string[] checkDirectories = Directory.GetDirectories(jobIdDirectory, "*", SearchOption.TopDirectoryOnly); - foreach (string checkDirectory in checkDirectories) - { - if (!checkDirectory.Contains('_')) - continue; - if (Directory.GetDirectories(checkDirectory, "*", SearchOption.TopDirectoryOnly).Length != 0) - continue; - if (Directory.GetFiles(checkDirectory, "*", SearchOption.TopDirectoryOnly).Length != 0) - continue; - if (Directory.GetDirectories(checkDirectory, "*", SearchOption.AllDirectories).Length != 0) - continue; - if (Directory.GetFiles(checkDirectory, "*", SearchOption.AllDirectories).Length != 0) - continue; - if (new DirectoryInfo(checkDirectory).CreationTime > dateTime) - continue; - Directory.Delete(checkDirectory, recursive: false); - } - } - catch (Exception) { throw; } - DeleteEmptyTopDirectories(jobIdDirectory); - } - } - private void Shared0231(List<string> directories) { if (_FileConnectorConfiguration.PostProcessingMode != FileConnectorConfiguration.PostProcessingModeEnum.Copy) @@ -704,66 +729,81 @@ public class FileRead : Properties.IFileRead } } - protected void WaitForFileConsumption<T>(DateTime dateTime, List<T> 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<string, Test[], JsonElement[], List<FileInfo>> ReExtract(IFileRead fileRead, List<string> headerNames, Dictionary<string, string> keyValuePairs) + { + Tuple<string, Test[], JsonElement[], List<FileInfo>> 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<string, Test[], JsonElement[], List<FileInfo>> extractResults, List<string> headerNames, Dictionary<string, string> 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<object[]> 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<object[]>(); + 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 cb1f805..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,13 +87,13 @@ public class Logistics : ILogistics _Logistics2 = new List<Logistics2>(); } - 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(); + _Logistics1 = processDataStandardFormat.Logistics.ToList(); if (Logistics1.Count == 0 || !Logistics1[0].StartsWith("LOGISTICS_1")) { _NullData = 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 8edb116..0a7950e 100644 --- a/Adaptation/Shared/Metrology/WS.Attachment.cs +++ b/Adaptation/Shared/Metrology/WS.Attachment.cs @@ -6,23 +6,25 @@ public partial class WS public class Attachment { - public string SubGroupId { get; set; } - public long HeaderId { get; set; } - public string HeaderIdDirectory { get; set; } - public string UniqueId { get; set; } - public string DestinationFileName { get; set; } - public string SourceFileName { get; set; } - public string AttachmentId { get; set; } +#nullable enable - public Attachment(string subGroupId, long headerId, string headerIdDirectory, 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) { - SubGroupId = subGroupId; - HeaderId = headerId; - HeaderIdDirectory = headerIdDirectory; 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<string> Errors { get; set; } + [JsonConstructor] + public Results(List<string>? errors, + long? headerId, + long? subgroupId, + bool? success, + List<string>? 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<string> Warnings { get; set; } + [JsonPropertyName("errors")] public List<string>? 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<string>? 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<string> 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 c49e61d..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 { +#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,29 +32,20 @@ public partial class WS }; HttpResponseMessage httpResponseMessage = httpClient.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseContentRead).Result; resultsJson = httpResponseMessage.Content.ReadAsStringAsync().Result; - results = JsonSerializer.Deserialize<Results>(resultsJson, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); - string checkDirectory = Path.Combine(directory, $"-{results.HeaderID}"); + 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<string>(); - results.Errors.Add(resultsJson); - results.Errors.Add(stringBuilder.ToString()); - } - return new(resultsJson, results); + { wsResults ??= Results.Get(resultsJson, e); } + return new(resultsJson, wsResults); } public static void AttachFile(string url, Attachment attachment, int timeoutSeconds = 60) @@ -69,16 +62,20 @@ public partial class WS } } - public static void AttachFiles(string url, List<Attachment> headerAttachments = null, List<Attachment> dataAttachments = null) + public static void AttachFiles(string url, List<Attachment>? headerAttachments = null, List<Attachment>? dataAttachments = null) { string directory; try { + string? directoryName; if (headerAttachments is not null) { foreach (Attachment attachment in headerAttachments) { - directory = Path.Combine(Path.GetDirectoryName(attachment.HeaderIdDirectory), attachment.AttachmentId) ?? throw new Exception(); + 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); @@ -88,7 +85,10 @@ public partial class WS { foreach (Attachment attachment in dataAttachments) { - directory = Path.Combine(Path.GetDirectoryName(attachment.HeaderIdDirectory.Replace("Header", "Data")), attachment.AttachmentId) ?? throw new Exception(); + 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); @@ -108,7 +108,7 @@ public partial class WS } 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 b2ca7b6..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,325 +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<string> Body { get; private set; } + internal ReadOnlyCollection<string> Footer { get; private set; } + internal ReadOnlyCollection<string> Header { get; private set; } + internal ReadOnlyCollection<string> Columns { get; private set; } + internal ProcessDataStandardFormat? InputPDSF { get; private set; } + internal ReadOnlyCollection<string> Logistics { get; private set; } + + internal ProcessDataStandardFormat(ReadOnlyCollection<string> body, + ReadOnlyCollection<string> columns, + ReadOnlyCollection<string> footer, + ReadOnlyCollection<string> header, + ProcessDataStandardFormat? inputPDSF, + ReadOnlyCollection<string> logistics, + long? sequence) { - string result; - if (jsonElements.Length == 0) - result = string.Empty; - else - { - int columns = 0; - List<string> 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<string, string[], string[]> GetLogisticsColumnsAndBody(string reportFullPath, string[] lines = null) - { - string segment; - List<string> body = new(); - StringBuilder logistics = new(); - lines ??= File.ReadAllLines(reportFullPath); - string[] segments; - if (lines.Length < 7) - segments = Array.Empty<string>(); - else - segments = lines[6].Trim().Split('\t'); - List<string> 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<string, string[], string[]>(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<string, string[], string[]> pdsf, bool lookForNumbers = false) - { - JsonElement[] results; - string logistics = pdsf.Item1; - string[] columns = pdsf.Item2; - string[] bodyLines = pdsf.Item3; - if (bodyLines.Length == 0 || !bodyLines[0].Contains('\t')) - results = JsonSerializer.Deserialize<JsonElement[]>("[]"); - else - { - string value; - string[] segments; - List<string> 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<JsonElement[]>(json); - } - return results; - } + internal static string BusinessIntegration(bool addSpaces = true, char separator = ' ') => + GetString(SearchFor.BusinessIntegration, addSpaces, separator); - public static Dictionary<string, List<string>> GetDictionary(Tuple<string, string[], string[]> pdsf) - { - Dictionary<string, List<string>> results = new(); - string[] segments; - string[] columns = pdsf.Item2; - string[] bodyLines = pdsf.Item3; - foreach (string column in columns) - results.Add(column, new List<string>()); - 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<string, Dictionary<Test, Dictionary<string, List<string>>>> GetTestDictionary(Tuple<string, string[], string[]> pdsf) - { - Dictionary<Test, Dictionary<string, List<string>>> results = new(); - List<string> collection; - string testColumn = nameof(Test); - Dictionary<string, List<string>> keyValuePairs = GetDictionary(pdsf); - if (!keyValuePairs.TryGetValue(testColumn, out collection)) - throw new Exception(); - int min; - int max; - Test testKey; - List<string> vs; - string columnKey; - Dictionary<Test, List<int>> 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<int>()); - results.Add(test, new Dictionary<string, List<string>>()); - } - tests[test].Add(i); - } - } - foreach (KeyValuePair<Test, List<int>> testKeyValuePair in tests) - { - testKey = testKeyValuePair.Key; - min = testKeyValuePair.Value.Min(); - max = testKeyValuePair.Value.Max() + 1; - foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs) - results[testKey].Add(keyValuePair.Key, new List<string>()); - foreach (KeyValuePair<string, List<string>> 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<string, Dictionary<Test, Dictionary<string, List<string>>>>(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<string>()), new(Array.Empty<string>()), new(Array.Empty<string>()), new(Array.Empty<string>()), 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<string> names, Dictionary<string, List<string>> keyValuePairs, string dateFormat, string timeFormat, List<string> pairedParameterNames, bool useDateTimeFromSequence = true, string format = "", List<string> ignoreParameterNames = null) - { - StringBuilder result = new(); - ignoreParameterNames ??= new List<string>(); - 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<string, List<string>> 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(); - } - - public static List<string> PDSFToFixedWidth(string reportFullPath) + internal static List<string> PDSFToFixedWidth(string reportFullPath) { List<string> results = new(); if (!File.Exists(reportFullPath)) @@ -407,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<string> body = new(); + List<string> header = new(); + List<string> footer = new(); + List<string> columns = new(); + ReadOnlyCollection<string> logistics; + lines ??= File.ReadAllLines(reportFullPath); + if (lines.Length < columnsLine + 1) + segments = Array.Empty<string>(); + 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<string> GetLogistics(List<string> footer, string? linesOne) + { + List<string> 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<string> body = new(); + List<string> header = new(); + List<string> footer = new(); + ReadOnlyCollection<string> logistics; + lines ??= File.ReadAllLines(path); + if (lines.Length <= columnsLine) + segments = Array.Empty<string>(); + 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<string> segments; + List<string> 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<string> values = new(); + List<string> results = new(); + JsonProperty[] jsonProperties; + List<string> 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<string> 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<Metrology.WS.Results>? wsResults) + { + List<string> 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<char> 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<string, List<string>> GetDictionary(ProcessDataStandardFormat processDataStandardFormat) + { + Dictionary<string, List<string>> results = new(); + string[] segments; + foreach (string column in processDataStandardFormat.Columns) + results.Add(column, new List<string>()); + 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<string> 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<JsonElement[]>(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<string> 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<string, Dictionary<Test, Dictionary<string, List<string>>>> GetTestDictionary(ProcessDataStandardFormat processDataStandardFormat) + { + Dictionary<Test, Dictionary<string, List<string>>> results = new(); + List<string>? collection; + string testColumn = nameof(Test); + Dictionary<string, List<string>> keyValuePairs = GetDictionary(processDataStandardFormat); + if (!keyValuePairs.TryGetValue(testColumn, out collection)) + throw new Exception(); + int min; + int max; + Test testKey; + List<string> vs; + string columnKey; + Dictionary<Test, List<int>> 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<int>()); + results.Add(test, new Dictionary<string, List<string>>()); + } + tests[test].Add(i); + } + } + foreach (KeyValuePair<Test, List<int>> testKeyValuePair in tests) + { + testKey = testKeyValuePair.Key; + min = testKeyValuePair.Value.Min(); + max = testKeyValuePair.Value.Max() + 1; + foreach (KeyValuePair<string, List<string>> keyValuePair in keyValuePairs) + results[testKey].Add(keyValuePair.Key, new List<string>()); + foreach (KeyValuePair<string, List<string>> 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<string, Dictionary<Test, Dictionary<string, List<string>>>>(processDataStandardFormat.Logistics[0], results); + } + + internal static string GetLines(Logistics logistics, Properties.IScopeInfo scopeInfo, List<string> names, Dictionary<string, List<string>> keyValuePairs, string dateFormat, string timeFormat, List<string> pairedParameterNames, bool useDateTimeFromSequence = true, string format = "", List<string>? ignoreParameterNames = null) + { + StringBuilder result = new(); + ignoreParameterNames ??= new List<string>(); + 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<string, List<string>> 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<string> BackfillColumns { get; private set; } + public ReadOnlyCollection<int> ColumnIndices { get; private set; } + public ReadOnlyCollection<string> IgnoreColumns { get; private set; } + public ReadOnlyCollection<string> IndexOnlyColumns { get; private set; } + public ReadOnlyDictionary<string, string> KeyValuePairs { get; private set; } + public ReadOnlyCollection<string> NewColumnNames { get; private set; } + public ReadOnlyCollection<string> OldColumnNames { get; private set; } + + public ProcessDataStandardFormatMapping(ReadOnlyCollection<string> backfillColumns, + ReadOnlyCollection<int> columnIndices, + ReadOnlyCollection<string> ignoreColumns, + ReadOnlyCollection<string> indexOnlyColumns, + ReadOnlyDictionary<string, string> keyValuePairs, + ReadOnlyCollection<string> newColumnNames, + ReadOnlyCollection<string> 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/Shared/Properties/IDescription.cs b/Adaptation/Shared/Properties/IDescription.cs index 34b92af..1166e17 100644 --- a/Adaptation/Shared/Properties/IDescription.cs +++ b/Adaptation/Shared/Properties/IDescription.cs @@ -6,6 +6,6 @@ public interface IDescription int Test { get; } int Count { get; } int Index { get; } - string Lot { get; } + string RDS { get; } } \ No newline at end of file diff --git a/Adaptation/_Tests/Shared/AdaptationTesting.cs b/Adaptation/_Tests/Shared/AdaptationTesting.cs index dad8ffe..8c0bc93 100644 --- a/Adaptation/_Tests/Shared/AdaptationTesting.cs +++ b/Adaptation/_Tests/Shared/AdaptationTesting.cs @@ -56,11 +56,33 @@ public class AdaptationTesting : ISMTP public Dictionary<string, string> ParameterizedModelObjectDefinitionTypes => _ParameterizedModelObjectDefinitionTypes; public Dictionary<string, List<Tuple<string, string>>> 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<T>(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<char> 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<char> 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<string>(); - else if (!Directory.Exists(mbn.TextFileDirectory)) - { - results = Array.Empty<string>(); - 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.Length == 0) - { - _ = 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<T>(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,6 +287,54 @@ 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<string, CellInstanceVersion> 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<string, CellInstanceVersion> GetCellInstanceVersionTuple(string cellInstanceName, string cellInstanceVersionName) { Tuple<string, CellInstanceVersion> result; @@ -382,41 +349,6 @@ public class AdaptationTesting : ISMTP return result; } - protected static Dictionary<string, int[]> GetComponentModelComponentsIndexes(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) - { - Dictionary<string, int[]> 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<string, int[]> componentModelComponentsIndexes) - { - int[] result; - if (string.IsNullOrEmpty(cellInstanceConnectionName)) - result = componentModelComponentsIndexes.ElementAt(0).Value; - else - { - if (componentModelComponentsIndexes is null || !componentModelComponentsIndexes.TryGetValue(cellInstanceConnectionName, out result)) - throw new Exception(); - } - return result; - } - protected string[] GetCSharpTextB(FileInfo fileInfo, string cellInstanceName, string cellInstanceVersionName, CellInstanceVersion cellInstanceVersion) { List<string> results = new(); @@ -608,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<string, CellInstanceVersion> cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); + Tuple<string, FileConnectorConfiguration> 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<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); + Tuple<string, string> parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); + Tuple<string, IList<ModelObjectParameterDefinition>> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); + Tuple<string, string, string, EquipmentDictionaryVersion> equipmentDictionaryVersionTuple = GetEquipmentDictionaryVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName, equipmentTypeVersionTuple.Item4); + Tuple<string, List<Tuple<string, string>>> equipmentDictionaryIsAlwaysEnabledEventsTuple = GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(equipmentDictionaryVersionTuple); + Dictionary<string, object> 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<string, FileConnectorConfiguration> GetFileConnectorConfigurationTuple(Tuple<string, CellInstanceVersion> cellInstanceVersionTuple, string cellInstanceConnectionName) + { + Tuple<string, FileConnectorConfiguration> result; + FileConnectorConfiguration fileConnectorConfiguration; + string cellInstanceServiceV2With = string.Concat(cellInstanceVersionTuple.Item1, '/', cellInstanceConnectionName); + if (!_FileConnectorConfigurations.TryGetValue(cellInstanceServiceV2With, out fileConnectorConfiguration)) + { + Dictionary<string, int[]> 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<string, FileConnectorConfiguration>(cellInstanceServiceV2With, fileConnectorConfiguration); + return result; + } + protected static FileConnectorConfiguration GetFileConnectorConfiguration(string json, ComponentsCellComponentCellComponent componentsCellComponentCellComponent) { FileConnectorConfiguration result; @@ -640,21 +628,55 @@ public class AdaptationTesting : ISMTP return result; } - protected Tuple<string, FileConnectorConfiguration> GetFileConnectorConfigurationTuple(Tuple<string, CellInstanceVersion> cellInstanceVersionTuple, string cellInstanceConnectionName) + protected Tuple<string, string, string, EquipmentTypeVersion> GetEquipmentTypeVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) { - Tuple<string, FileConnectorConfiguration> result; - FileConnectorConfiguration fileConnectorConfiguration; - string cellInstanceServiceV2With = string.Concat(cellInstanceVersionTuple.Item1, '/', cellInstanceConnectionName); - if (!_FileConnectorConfigurations.TryGetValue(cellInstanceServiceV2With, out fileConnectorConfiguration)) + Tuple<string, string, string, EquipmentTypeVersion> result; + EquipmentTypeVersion equipmentTypeVersion; + Dictionary<string, int[]> 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)) { - Dictionary<string, int[]> 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); + equipmentTypeVersion = GetEquipmentTypeVersion(equipmentTypeServiceV2); + _EquipmentTypeVersions.Add(equipmentTypeServiceV2, equipmentTypeVersion); + } + result = new Tuple<string, string, string, EquipmentTypeVersion>(equipmentTypeServiceV2, componentsCellComponentCellComponent.Equipment.EquipmentType.Name, componentsCellComponentCellComponent.Equipment.EquipmentType.Version, equipmentTypeVersion); + return result; + } + + protected static Dictionary<string, int[]> GetComponentModelComponentsIndexes(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) + { + Dictionary<string, int[]> 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<string, int[]> componentModelComponentsIndexes) + { + int[] result; + if (string.IsNullOrEmpty(cellInstanceConnectionName)) + result = componentModelComponentsIndexes.ElementAt(0).Value; + else + { + if (componentModelComponentsIndexes is null || !componentModelComponentsIndexes.TryGetValue(cellInstanceConnectionName, out result)) + throw new Exception(); } - result = new Tuple<string, FileConnectorConfiguration>(cellInstanceServiceV2With, fileConnectorConfiguration); return result; } @@ -683,35 +705,6 @@ public class AdaptationTesting : ISMTP return result; } - protected Tuple<string, string, string, EquipmentTypeVersion> GetEquipmentTypeVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName) - { - Tuple<string, string, string, EquipmentTypeVersion> result; - EquipmentTypeVersion equipmentTypeVersion; - Dictionary<string, int[]> 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<string, string, string, EquipmentTypeVersion>(equipmentTypeServiceV2, componentsCellComponentCellComponent.Equipment.EquipmentType.Name, componentsCellComponentCellComponent.Equipment.EquipmentType.Version, equipmentTypeVersion); - return result; - } - - protected Tuple<string, string> GetParameterizedModelObjectDefinitionTypeTuple(Tuple<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple) - { - Tuple<string, string> result; - string parameterizedModelObjectDefinitionType; - if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) - parameterizedModelObjectDefinitionType = _ParameterizedModelObjectDefinitionTypes[equipmentTypeVersionTuple.Item1]; - else - parameterizedModelObjectDefinitionType = equipmentTypeVersionTuple.Item4.FileHandlerObjectTypes.ParameterizedModelObjectDefinition.Type; - result = new Tuple<string, string>(equipmentTypeVersionTuple.Item1, parameterizedModelObjectDefinitionType); - return result; - } - protected IList<ModelObjectParameterDefinition> GetModelObjectParameters(string json) { IList<ModelObjectParameterDefinition> results; @@ -736,18 +729,38 @@ public class AdaptationTesting : ISMTP return results; } - protected Tuple<string, IList<ModelObjectParameterDefinition>> GetModelObjectParameters(Tuple<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple) + protected Tuple<string, string, string, EquipmentDictionaryVersion> GetEquipmentDictionaryVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName, EquipmentTypeVersion equipmentTypeVersion) { - Tuple<string, IList<ModelObjectParameterDefinition>> result; - IList<ModelObjectParameterDefinition> modelObjectParameters; - if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) - modelObjectParameters = _ModelObjectParameters[equipmentTypeVersionTuple.Item1]; + Tuple<string, string, string, EquipmentDictionaryVersion> result; + string equipmentDictionaryName; + string equipmentDictionaryVersionName; + EquipmentDictionaryVersion equipmentDictionaryVersion; + Dictionary<string, int[]> 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<string, IList<ModelObjectParameterDefinition>>(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<string, string, string, EquipmentDictionaryVersion>(equipmentDictionaryServiceV2, equipmentDictionaryName, equipmentDictionaryVersionName, equipmentDictionaryVersion); return result; } @@ -802,70 +815,6 @@ public class AdaptationTesting : ISMTP return result; } - protected Tuple<string, string, string, EquipmentDictionaryVersion> GetEquipmentDictionaryVersionTuple(CellInstanceVersion cellInstanceVersion, string cellInstanceConnectionName, EquipmentTypeVersion equipmentTypeVersion) - { - Tuple<string, string, string, EquipmentDictionaryVersion> result; - string equipmentDictionaryName; - string equipmentDictionaryVersionName; - EquipmentDictionaryVersion equipmentDictionaryVersion; - Dictionary<string, int[]> 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.TryGetValue(equipmentDictionaryServiceV2, out equipmentDictionaryVersion)) - { - equipmentDictionaryVersion = GetEquipmentDictionaryVersion(equipmentDictionaryServiceV2); - _EquipmentDictionaryVersions.Add(equipmentDictionaryServiceV2, equipmentDictionaryVersion); - } - } - result = new Tuple<string, string, string, EquipmentDictionaryVersion>(equipmentDictionaryServiceV2, equipmentDictionaryName, equipmentDictionaryVersionName, equipmentDictionaryVersion); - return result; - } - - protected Tuple<string, List<Tuple<string, string>>> GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(Tuple<string, string, string, EquipmentDictionaryVersion> equipmentDictionaryVersionTuple) - { - Tuple<string, List<Tuple<string, string>>> result; - List<Tuple<string, string>> results; - List<Tuple<string, string>> collection; - if (_SkipEquipmentDictionary) - results = new List<Tuple<string, string>>(); - else if (string.IsNullOrEmpty(equipmentDictionaryVersionTuple.Item1)) - throw new Exception(); - else if (equipmentDictionaryVersionTuple?.Item4?.Events?.Event is null) - results = new List<Tuple<string, string>>(); - else if (_EquipmentDictionaryEventDescriptions.TryGetValue(equipmentDictionaryVersionTuple.Item1, out collection)) - results = collection; - else - { - results = new List<Tuple<string, string>>(); - foreach (EquipmentDictionaryVersionEventsEvent equipmentDictionaryVersionEventsEvent in equipmentDictionaryVersionTuple.Item4.Events.Event) - { - if (string.IsNullOrEmpty(equipmentDictionaryVersionEventsEvent.Description)) - continue; - if (!equipmentDictionaryVersionEventsEvent.IsAlwaysEnabled) - continue; - results.Add(new Tuple<string, string>(equipmentDictionaryVersionEventsEvent.Name, equipmentDictionaryVersionEventsEvent.Description)); - } - } - result = new Tuple<string, List<Tuple<string, string>>>(equipmentDictionaryVersionTuple.Item1, results); - return result; - } - protected Dictionary<string, object> GetKeyValuePairs(string cellInstanceName, string cellInstanceVersionName, string cellInstanceConnectionName, FileConnectorConfiguration fileConnectorConfiguration, string equipmentTypeName, string parameterizedModelObjectDefinitionType, IList<ModelObjectParameterDefinition> modelObjectParameters, string equipmentDictionaryName, List<Tuple<string, string>> equipmentDictionaryIsAlwaysEnabledEvents, int edaConnectionPortNumber) { Dictionary<string, object> results = new() @@ -886,108 +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<string, CellInstanceVersion> 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<string, CellInstanceVersion> cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); - Tuple<string, FileConnectorConfiguration> 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<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); - Tuple<string, string> parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); - Tuple<string, IList<ModelObjectParameterDefinition>> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); - Tuple<string, string, string, EquipmentDictionaryVersion> equipmentDictionaryVersionTuple = GetEquipmentDictionaryVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName, equipmentTypeVersionTuple.Item4); - Tuple<string, List<Tuple<string, string>>> equipmentDictionaryIsAlwaysEnabledEventsTuple = GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(equipmentDictionaryVersionTuple); - Dictionary<string, object> 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<string, string> fileParameter = new(); - if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) - _ = Directory.CreateDirectory(fileInfo.Directory.FullName); - Dictionary<string, List<long>> dummyRuns = new(); - Dictionary<long, List<string>> staticRuns = new(); - Tuple<string, CellInstanceVersion> cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); - Tuple<string, FileConnectorConfiguration> fileConnectorConfigurationTuple = GetFileConnectorConfigurationTuple(cellInstanceVersionTuple, mbn.CellInstanceConnectionName); - Tuple<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); - Tuple<string, string> parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); - Tuple<string, IList<ModelObjectParameterDefinition>> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); - Tuple<string, string, string, EquipmentDictionaryVersion> 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 - { - 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); - } - } - 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; - } - public string[] GetVariables(MethodBase methodBase, string check, bool validatePDSF = true) { string[] results; @@ -1090,80 +937,118 @@ public class AdaptationTesting : ISMTP return results; } - internal static Tuple<string, string[], string[]> GetLogisticsColumnsAndBody(string fileFullName) + private string[] GetTextFiles(MethodBaseName mbn) { - Tuple<string, string[], string[]> 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<string, string[], string[]> GetLogisticsColumnsAndBody(string searchDirectory, string searchPattern) - { - Tuple<string, string[], string[]> results; - if (searchPattern.Length > 3 && !searchPattern.Contains('*') && File.Exists(searchPattern)) - results = GetLogisticsColumnsAndBody(searchPattern); + string[] results; + if (string.IsNullOrEmpty(mbn.TextFileDirectory)) + results = Array.Empty<string>(); + else if (!Directory.Exists(mbn.TextFileDirectory)) + { + results = Array.Empty<string>(); + 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.Length == 0) - _ = Process.Start("explorer.exe", searchDirectory); - Assert.IsTrue(pdsfFiles.Length != 0, "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<string, string[], string[]> GetLogisticsColumnsAndBody(IFileRead fileRead, Logistics logistics, Tuple<string, Test[], JsonElement[], List<FileInfo>> extractResult, Tuple<string, string[], string[]> pdsf) + public IFileRead Get(MethodBase methodBase, string sourceFileLocation, string sourceFileFilter, bool useCyclicalForDescription) { - Tuple<string, string[], string[]> 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<string, string[], string[]> pdsf, Tuple<string, string[], string[]> 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<string, string[], string[]> pdsf, Tuple<string, string[], string[]> 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<string, string> fileParameter = new(); + if (!string.IsNullOrEmpty(mbn.CellInstanceConnectionName) && !Directory.Exists(fileInfo.DirectoryName)) + _ = Directory.CreateDirectory(fileInfo.Directory.FullName); + Dictionary<string, List<long>> dummyRuns = new(); + Dictionary<long, List<Adaptation.Shared.Metrology.WS.Results>> staticRuns = new(); + Tuple<string, CellInstanceVersion> cellInstanceVersionTuple = GetCellInstanceVersionTuple(mbn.CellInstanceName, mbn.CellInstanceVersionName); + Tuple<string, FileConnectorConfiguration> fileConnectorConfigurationTuple = GetFileConnectorConfigurationTuple(cellInstanceVersionTuple, mbn.CellInstanceConnectionName); + Tuple<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple = GetEquipmentTypeVersionTuple(cellInstanceVersionTuple.Item2, mbn.CellInstanceConnectionName); + Tuple<string, string> parameterizedModelObjectDefinitionTypeTuple = GetParameterizedModelObjectDefinitionTypeTuple(equipmentTypeVersionTuple); + Tuple<string, IList<ModelObjectParameterDefinition>> modelObjectParametersTuple = GetModelObjectParameters(equipmentTypeVersionTuple); + Tuple<string, string, string, EquipmentDictionaryVersion> 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<string, Test[], JsonElement[], List<FileInfo>> 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<string, string[], string[]> pdsf, Tuple<string, string[], string[]> 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,6 +1155,21 @@ 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; @@ -1252,20 +1182,20 @@ public class AdaptationTesting : ISMTP Assert.IsNotNull(extractResult.Item3); Assert.IsNotNull(extractResult.Item4); if (!validatePDSF) - _ = GetLogisticsColumnsAndBody(fileRead, logistics, extractResult, new(string.Empty, Array.Empty<string>(), Array.Empty<string>())); + _ = GetProcessDataStandardFormat(fileRead, logistics, extractResult, ProcessDataStandardFormat.GetEmpty(logistics)); else { Assert.IsTrue(extractResult.Item3.Length > 0, "extractResult Array Length check!"); - Tuple<string, string[], string[]> pdsf = GetLogisticsColumnsAndBody(variables[2], variables[4]); - Tuple<string, string[], string[]> 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]); } @@ -1273,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<string, string> GetParameterizedModelObjectDefinitionTypeTuple(Tuple<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple) + { + Tuple<string, string> result; + string parameterizedModelObjectDefinitionType; + if (_FileConnectorConfigurations.ContainsKey(equipmentTypeVersionTuple.Item1)) + parameterizedModelObjectDefinitionType = _ParameterizedModelObjectDefinitionTypes[equipmentTypeVersionTuple.Item1]; + else + parameterizedModelObjectDefinitionType = equipmentTypeVersionTuple.Item4.FileHandlerObjectTypes.ParameterizedModelObjectDefinition.Type; + result = new Tuple<string, string>(equipmentTypeVersionTuple.Item1, parameterizedModelObjectDefinitionType); + return result; + } + + protected Tuple<string, IList<ModelObjectParameterDefinition>> GetModelObjectParameters(Tuple<string, string, string, EquipmentTypeVersion> equipmentTypeVersionTuple) + { + Tuple<string, IList<ModelObjectParameterDefinition>> result; + IList<ModelObjectParameterDefinition> 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<string, IList<ModelObjectParameterDefinition>>(equipmentTypeVersionTuple.Item1, modelObjectParameters); + return result; + } + + protected Tuple<string, List<Tuple<string, string>>> GetEquipmentDictionaryIsAlwaysEnabledEventsTuple(Tuple<string, string, string, EquipmentDictionaryVersion> equipmentDictionaryVersionTuple) + { + Tuple<string, List<Tuple<string, string>>> result; + List<Tuple<string, string>> results; + List<Tuple<string, string>> collection; + if (_SkipEquipmentDictionary) + results = new List<Tuple<string, string>>(); + else if (string.IsNullOrEmpty(equipmentDictionaryVersionTuple.Item1)) + throw new Exception(); + else if (equipmentDictionaryVersionTuple?.Item4?.Events?.Event is null) + results = new List<Tuple<string, string>>(); + else if (_EquipmentDictionaryEventDescriptions.TryGetValue(equipmentDictionaryVersionTuple.Item1, out collection)) + results = collection; + else + { + results = new List<Tuple<string, string>>(); + foreach (EquipmentDictionaryVersionEventsEvent equipmentDictionaryVersionEventsEvent in equipmentDictionaryVersionTuple.Item4.Events.Event) + { + if (string.IsNullOrEmpty(equipmentDictionaryVersionEventsEvent.Description)) + continue; + if (!equipmentDictionaryVersionEventsEvent.IsAlwaysEnabled) + continue; + results.Add(new Tuple<string, string>(equipmentDictionaryVersionEventsEvent.Name, equipmentDictionaryVersionEventsEvent.Description)); + } + } + result = new Tuple<string, List<Tuple<string, string>>>(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<string, CellInstanceVersion> 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/Adaptation/_Tests/Static/METCLIMATEC.cs b/Adaptation/_Tests/Static/METCLIMATEC.cs index 2ac922e..5758e31 100644 --- a/Adaptation/_Tests/Static/METCLIMATEC.cs +++ b/Adaptation/_Tests/Static/METCLIMATEC.cs @@ -51,7 +51,7 @@ public class METCLIMATEC : LoggingUnitTesting, IDisposable public void TestDateTime() { DateTime dateTime = DateTime.Now; - Assert.IsTrue(dateTime.ToString("M/d/yyyy h:mm:ss tt") == dateTime.ToString()); + Assert.AreEqual(dateTime.ToString(), dateTime.ToString("M/d/yyyy h:mm:ss tt")); } #if DEBUG diff --git a/Adaptation/_Tests/Static/csv.cs b/Adaptation/_Tests/Static/csv.cs index e3a75b8..8073ef0 100644 --- a/Adaptation/_Tests/Static/csv.cs +++ b/Adaptation/_Tests/Static/csv.cs @@ -51,7 +51,7 @@ public class CSV : LoggingUnitTesting, IDisposable public void TestDateTime() { DateTime dateTime = DateTime.Now; - Assert.IsTrue(dateTime.ToString("M/d/yyyy h:mm:ss tt") == dateTime.ToString()); + Assert.AreEqual(dateTime.ToString(), dateTime.ToString("M/d/yyyy h:mm:ss tt")); } #if DEBUG diff --git a/FileHandlers/FileRead.cs b/FileHandlers/FileRead.cs index f556172..2a2e3d0 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<EquipmentParameter> _EquipmentParameters; private static readonly Dictionary<string, List<long>> _DummyRuns; - private static readonly Dictionary<long, List<string>> _StaticRuns; + private static readonly Dictionary<long, List<Adaptation.Shared.Metrology.WS.Results>> _StaticRuns; static FileRead() { diff --git a/METCLIMATEC.csproj b/METCLIMATEC.csproj index 77c684f..7fc8870 100644 --- a/METCLIMATEC.csproj +++ b/METCLIMATEC.csproj @@ -147,6 +147,7 @@ <Compile Include="Adaptation\Shared\Metrology\WS.Results.cs" /> <Compile Include="Adaptation\Shared\ParameterType.cs" /> <Compile Include="Adaptation\Shared\ProcessDataStandardFormat.cs" /> + <Compile Include="Adaptation\Shared\ProcessDataStandardFormatMapping.cs" /> <Compile Include="Adaptation\Shared\Properties\IDescription.cs" /> <Compile Include="Adaptation\Shared\Properties\IFileRead.cs" /> <Compile Include="Adaptation\Shared\Properties\ILogistics.cs" />