407 lines
16 KiB
C#

using Adaptation.Shared;
using Adaptation.Shared.Methods;
using log4net;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace Adaptation.FileHandlers.RsM;
public class ProcessData : IProcessData
{
private readonly List<object> _Details;
public string JobID { get; set; }
public string MesEntity { get; set; }
public string AutoOptimizeGain { get; set; }
public string AutoProbeHeightSet { get; set; }
public string Avg { get; set; }
public string DLRatio { get; set; }
public string DataReject { get; set; }
public DateTime Date { get; set; }
public string Employee { get; set; }
public string Engineer { get; set; }
public string EquipId { get; set; }
public string FileName { get; set; }
public string Layer { get; set; }
public string LogBody { get; set; }
public string Lot { get; set; }
public string PSN { get; set; }
public string Project { get; set; }
public string RDS { get; set; }
public string Reactor { get; set; }
public string Recipe { get; set; }
public string RecipeName { get; set; }
public string ResistivitySpec { get; set; }
public string Run { get; set; }
public string SemiRadial { get; set; }
public string StandardDeviation { get; set; }
public string StandardDeviationPercentage { get; set; }
public string Temp { get; set; }
public string Title { get; set; }
public string UniqueId { get; set; }
public string Zone { get; set; }
private readonly ILog _Log;
List<object> Shared.Properties.IProcessData.Details => _Details;
internal ProcessData(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, Run run)
{
JobID = logistics.JobID;
_Details = new List<object>();
MesEntity = logistics.MesEntity;
_Log = LogManager.GetLogger(typeof(ProcessData));
Parse(fileRead, logistics, fileInfoCollection, run);
}
string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary<string, string> reactors) => throw new Exception(string.Concat("See ", nameof(Parse)));
Tuple<string, Test[], JsonElement[], List<FileInfo>> IProcessData.GetResults(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection)
{
Tuple<string, Test[], JsonElement[], List<FileInfo>> results;
List<Test> tests = new();
foreach (object item in _Details)
tests.Add(Test.CDE);
List<IDescription> descriptions = fileRead.GetDescriptions(fileRead, tests, this);
if (tests.Count != descriptions.Count)
throw new Exception();
for (int i = 0; i < tests.Count; i++)
{
if (descriptions[i] is not Description description)
throw new Exception();
if (description.Test != (int)tests[i])
throw new Exception();
}
List<Description> fileReadDescriptions = (from l in descriptions select (Description)l).ToList();
string json = JsonSerializer.Serialize(fileReadDescriptions, fileReadDescriptions.GetType());
JsonElement[] jsonElements = JsonSerializer.Deserialize<JsonElement[]>(json);
results = new Tuple<string, Test[], JsonElement[], List<FileInfo>>(logistics.Logistics1[0], tests.ToArray(), jsonElements, fileInfoCollection);
return results;
}
private static (string, string) GetReactorAndRDS(string defaultReactor, string defaultRDS, string text, string formattedText, string[] segments)
{
string rds;
string reactor;
if (string.IsNullOrEmpty(text) || segments.Length == 0 || string.IsNullOrEmpty(formattedText))
reactor = defaultReactor;
else
reactor = segments[0];
if (segments.Length <= 1 || !int.TryParse(segments[1], out int rdsValue) || rdsValue < 99)
rds = defaultRDS;
else
rds = segments[1];
if (reactor.Length > 3)
{
rds = reactor;
reactor = defaultReactor;
}
return new(reactor, rds);
}
private static (string, string) GetLayerAndPSN(string defaultLayer, string defaultPSN, string[] segments)
{
string psn;
string layer;
if (segments.Length <= 2)
{
psn = defaultPSN;
layer = defaultLayer;
}
else
{
string[] segmentsB = segments[2].Split('.');
psn = segmentsB[0];
if (segmentsB.Length <= 1)
layer = defaultLayer;
else
{
layer = segmentsB[1];
if (layer.Length > 1 && layer[0] == '0')
layer = layer.Substring(1);
}
}
return (layer, psn);
}
private static string GetZone(string[] segments)
{
string result;
if (segments.Length <= 3)
result = string.Empty;
else
{
result = segments[3];
if (result.Length > 1 && result[0] == '0')
result = result.Substring(1);
}
return result;
}
public static Descriptor GetDescriptor(string text)
{
Descriptor result;
string psn;
string rds;
string run;
string zone;
string layer;
string title;
string reactor;
string employee;
string defaultPSN = string.Empty;
string defaultRDS = string.Empty;
string defaultZone = string.Empty;
string defaultLayer = string.Empty;
string defaultReactor = string.Empty;
string defaultEmployee = string.Empty;
if (Regex.IsMatch(text, @"^[a-zA-z][0-9]{2,4}$"))
{
run = text.ToUpper();
psn = defaultPSN;
rds = defaultRDS;
zone = defaultZone;
layer = defaultLayer;
reactor = defaultReactor;
employee = defaultEmployee;
}
else if (string.IsNullOrEmpty(text) || (text.Length is 2 or 3 && Regex.IsMatch(text, "^[a-zA-z]{2,3}")))
{
run = text;
employee = text;
psn = defaultPSN;
rds = defaultRDS;
zone = defaultZone;
layer = defaultLayer;
reactor = defaultReactor;
}
else if (Regex.IsMatch(text, @"^[0-9]{2}[.][0-9]{1}[.]?[0-9]{0,1}"))
{
string[] segments = text.Split('.');
run = text;
psn = defaultPSN;
rds = defaultRDS;
layer = segments[1];
reactor = segments[0];
employee = defaultEmployee;
if (segments.Length <= 2)
zone = defaultZone;
else
zone = segments[2];
}
else
{
// Remove illegal characters \/:*?"<>| found in the title.
title = Regex.Replace(text, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
if (title.Length > 2 && title[0] == '1' && (title[1] == 'T' || title[1] == 't'))
title = title.Substring(2);
run = title;
string[] segments = title.Split('-');
// bool hasRDS = Regex.IsMatch(title, "[-]?([QP][0-9]{4,}|[0-9]{5,})[-]?");
(reactor, rds) = GetReactorAndRDS(defaultReactor, defaultRDS, text, title, segments);
(layer, psn) = GetLayerAndPSN(defaultLayer, defaultPSN, segments);
zone = GetZone(segments);
employee = defaultEmployee;
}
result = new(employee, layer, psn, rds, reactor, run, zone);
return result;
}
private void SetTitleData(Logistics logistics, Run run)
{
string timeFormat = "yyyyMMddHHmmss";
Descriptor descriptor = GetDescriptor(run.Line1.Title);
PSN = descriptor.PSN;
RDS = descriptor.RDS;
Run = descriptor.Run;
Zone = descriptor.Zone;
Layer = descriptor.Layer;
Reactor = descriptor.Reactor;
Employee = descriptor.Employee;
UniqueId = string.Concat(logistics.JobID, "_", descriptor.Run, "_", logistics.DateTimeFromSequence.ToString(timeFormat));
}
private void SetFileNameData(string[] segments)
{
if (segments.Length > 1)
FileName = segments[0];
if (segments.Length > 2)
{
Project = segments[1];
RecipeName = segments[2];
Recipe = string.Concat(segments[1], " \\ ", segments[2]);
}
}
internal static DateTime GetDateTime(Logistics logistics, string dateTimeText)
{
DateTime result;
string inputDateFormat = "HH:mm MM/dd/yy";
if (dateTimeText.Length != inputDateFormat.Length)
result = logistics.DateTimeFromSequence;
else
{
if (!DateTime.TryParseExact(dateTimeText, inputDateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime dateTimeParsed))
result = logistics.DateTimeFromSequence;
else
{
if (dateTimeParsed < logistics.DateTimeFromSequence.AddDays(1) && dateTimeParsed > logistics.DateTimeFromSequence.AddDays(-1))
result = dateTimeParsed;
else
result = logistics.DateTimeFromSequence;
}
}
return result;
}
private void SetDateTimeData(Logistics logistics, string[] segments)
{
DateTime dateTime;
if (segments.Length < 2)
dateTime = logistics.DateTimeFromSequence;
else
{
string dateTimeText = string.Concat(segments[0], ' ', segments[1]);
dateTime = GetDateTime(logistics, dateTimeText);
}
Date = dateTime;
if (segments.Length > 3 && float.TryParse(segments[2], out float temp))
Temp = temp.ToString("0.0");
if (segments.Length > 7 && segments[6] == "Avg=")
Avg = segments[7];
if (segments.Length > 7 && segments[8] == "Dev=")
StandardDeviation = segments[9];
if (!string.IsNullOrEmpty(Avg) && !string.IsNullOrEmpty(StandardDeviation) && float.TryParse(Avg, out float average) && float.TryParse(StandardDeviation, out float standardDeviation))
StandardDeviationPercentage = Math.Round(standardDeviation / average, 4).ToString("0.00%");
}
private void SetOperatorData(string[] segments, bool updateEmployee)
{
if (segments.Length > 1 && updateEmployee)
Employee = segments[0];
if (segments.Length > 2)
EquipId = segments[1];
}
private void SetEngineerData(string[] segments)
{
if (segments.Length > 1)
Engineer = segments[0];
}
private void SetNumProbePointsData(string[] segments)
{
if (segments.Length > 6)
DataReject = segments[6];
}
private static Detail GetRData(string[] segments)
{
Detail result = new();
if (segments.Length > 0 && float.TryParse(segments[0], out float r))
result.R = r.ToString("0.0");
if (segments.Length > 1 && float.TryParse(segments[1], out float t))
result.T = t.ToString("0.0");
if (segments.Length > 2 && float.TryParse(segments[2], out float rs))
result.Rs = rs.ToString("0.0000");
if (segments.Length > 12 && float.TryParse(segments[12], out float merit))
result.Merit = merit.ToString("0.00");
result.Pt = "-1";
result.UniqueId = string.Empty;
return result;
}
#nullable enable
private void Parse(IFileRead fileRead, Logistics logistics, List<FileInfo> fileInfoCollection, Run run)
{
if (fileRead is null)
throw new ArgumentNullException(nameof(fileRead));
Lot = "LotID";
Detail detail;
string[] segments;
string[] separator = new string[] { " " };
string[] lines = File.ReadAllLines(logistics.ReportFullPath);
for (int i = 0; i < lines.Length; i++)
{
segments = lines[i].Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (lines[i].Contains("<Title>") && segments.Length > 0)
SetTitleData(logistics, run);
else if (lines[i].Contains("<FileName, Proj,Rcpe, LotID,WfrID"))
SetFileNameData(segments);
else if (lines[i].Contains("<DateTime,Temp,TCR%,N|P>"))
SetDateTimeData(logistics, segments);
else if (lines[i].Contains("<Operator, Epuipment>"))
SetOperatorData(segments, updateEmployee: string.IsNullOrEmpty(Employee));
else if (lines[i].Contains("<Engineer>"))
SetEngineerData(segments);
else if (lines[i].Contains("<NumProbePoints, SingleOrDualProbeConfig, #ActPrbPts, Rsens,IdrvMx,VinGain, DataRejectSigma, MeritThreshold"))
SetNumProbePointsData(segments);
else if (lines[i].Contains("<R,Th,Data, Rs,RsA,RsB, #Smpl, x,y, Irng,Vrng"))
{
for (int z = i; z < lines.Length; z++)
{
i = z;
if (string.IsNullOrEmpty(lines[z]))
continue;
detail = GetRData(lines[z].Split(separator, StringSplitOptions.RemoveEmptyEntries));
_Details.Add(detail);
}
}
}
for (int i = 0; i < _Details.Count; i++)
{
if (_Details[i] is not Detail item)
continue;
item.HeaderUniqueId = UniqueId;
item.Pt = (i + 1).ToString();
item.UniqueId = string.Concat(item, "_Point-", item.Pt);
}
StringBuilder stringBuilder = new();
string reportFileName = Path.GetFileName(logistics.ReportFullPath);
_ = stringBuilder.AppendLine($"RUN [{Title}]");
_ = stringBuilder.AppendLine($"Recipe {Project} \\ {RecipeName} RESISTIVITY {"####"}");
_ = stringBuilder.AppendLine($"EQUIP# {EquipId} Engineer {Engineer}");
_ = stringBuilder.AppendLine($"LotID {Lot} D.L.RATIO {"#.####"}");
_ = stringBuilder.AppendLine($"OPERATOR {Employee} TEMP {Temp} {Date:HH:mm MM/dd/yy}");
_ = stringBuilder.AppendLine($"AutoOptimizeGain = {"###"} AutoProbeHeightSet = {"##"}");
_ = stringBuilder.AppendLine($"DataReject > {"#.#"}Sigma");
_ = stringBuilder.AppendLine($"0 ..\\{Project}.prj\\{RecipeName}.rcp\\{reportFileName} {Date:HH:mm MM/dd/yy}");
_ = stringBuilder.AppendLine($"pt# R Th Rs[Ohm/sq@T] Merit");
for (int i = 0; i < _Details.Count; i++)
{
if (_Details[i] is not Detail item)
continue;
_ = stringBuilder.AppendLine($"{item.Pt} {item.R} {item.T} {item.Rs} {item.Merit}");
}
_ = stringBuilder.AppendLine($"Avg = {Avg} {StandardDeviationPercentage} SEMI Radial= {"#.##%"}");
LogBody = stringBuilder.ToString();
fileInfoCollection.Add(logistics.FileInfo);
}
internal static List<Description> GetDescriptions(JsonElement[] jsonElements)
{
List<Description> results = new();
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<Description>(jsonElement.ToString(), jsonSerializerOptions);
if (description is null)
continue;
results.Add(description);
}
return results;
}
}