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.RegularExpressions; namespace Adaptation.FileHandlers.pcl { public class ProcessData : IProcessData { private int _I; private string _Data; private readonly ILog _Log; private readonly List _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 string Date { get; set; } public string Employee { get; set; } public string EquipId { get; set; } public string Engineer { get; set; } public string FileName { get; set; } public string Layer { get; set; } public string Lot { get; set; } public string PSN { get; set; } public string RDS { get; set; } public string Reactor { get; set; } public string Recipe { get; set; } public string ResistivitySpec { get; set; } public string Run { get; set; } public string SemiRadial { get; set; } public string StdDev { get; set; } public string Temp { get; set; } public string UniqueId { get; set; } public string Zone { get; set; } List Shared.Properties.IProcessData.Details => _Details; public ProcessData(IFileRead fileRead, Logistics logistics, List fileInfoCollection) { fileInfoCollection.Clear(); _Details = new List(); _I = 0; _Data = string.Empty; JobID = logistics.JobID; MesEntity = logistics.MesEntity; _Log = LogManager.GetLogger(typeof(ProcessData)); Parse(fileRead, logistics, fileInfoCollection); } string IProcessData.GetCurrentReactor(IFileRead fileRead, Logistics logistics, Dictionary reactors) { throw new Exception(string.Concat("See ", nameof(Parse))); } Tuple> IProcessData.GetResults(IFileRead fileRead, Logistics logistics, List fileInfoCollection) { Tuple> results; List tests = new(); foreach (object item in _Details) tests.Add(Test.CDE); List 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 fileReadDescriptions = (from l in descriptions select (Description)l).ToList(); string json = JsonSerializer.Serialize(fileReadDescriptions, fileReadDescriptions.GetType()); JsonElement[] jsonElements = JsonSerializer.Deserialize(json); results = new Tuple>(logistics.Logistics1[0], tests.ToArray(), jsonElements, fileInfoCollection); return results; } private string GetBefore(string text) { string str; string str1; int num = _Data.IndexOf(text, _I); if (num <= -1) { str = _Data.Substring(_I); _I = _Data.Length; str1 = str.Trim(); } else { str = _Data.Substring(_I, num - _I); _I = num + text.Length; str1 = str.Trim(); } return str1; } private string GetBefore(string text, bool trim) { string str; string before; if (!trim) { int num = _Data.IndexOf(text, _I); if (num <= -1) { str = _Data.Substring(_I); _I = _Data.Length; before = str; } else { str = _Data.Substring(_I, num - _I); _I = num + text.Length; before = str; } } else { before = GetBefore(text); } return before; } private string GetToEOL() { return GetBefore("\n"); } private string GetToEOL(bool trim) { string str; str = (!trim ? GetBefore("\n", false) : GetToEOL()); return str; } private string GetToken() { while (true) { if ((_I >= _Data.Length || !IsNullOrWhiteSpace(_Data.Substring(_I, 1)))) break; _I++; } int num = _I; while (true) { if ((num >= _Data.Length || IsNullOrWhiteSpace(_Data.Substring(num, 1)))) break; num++; } string str = _Data.Substring(_I, num - _I); _I = num; return str.Trim(); } private string GetToText(string text) { string str = _Data.Substring(_I, _Data.IndexOf(text, _I) - _I).Trim(); return str; } private bool IsBlankLine() { int num = _Data.IndexOf("\n", _I); return IsNullOrWhiteSpace((num > -1 ? _Data.Substring(_I, num - _I) : _Data.Substring(_I))); } private bool IsNullOrWhiteSpace(string text) { bool flag; int num = 0; while (true) { if (num >= text.Length) { flag = true; break; } else if (char.IsWhiteSpace(text[num])) { num++; } else { flag = false; break; } } return flag; } private string PeekNextLine() { int num = _I; string toEOL = GetToEOL(); _I = num; return toEOL; } private void ScanPast(string text) { int num = _Data.IndexOf(text, _I); if (num <= -1) { _I = _Data.Length; } else { _I = num + text.Length; } } 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 Parse(IFileRead fileRead, Logistics logistics, List fileInfoCollection) { if (fileRead is null) { } // Convert the source file to UTF8Encoding format and then back to string for processing. This convertion // shall eliminate the special HEX characters such as 0x18 "CANCEL" and 0x20 "SPACE" captured via nPort. string rawText = File.ReadAllText(logistics.ReportFullPath); UTF8Encoding utf8Encoding = new(); byte[] bytes = utf8Encoding.GetBytes(rawText); string convertedText = utf8Encoding.GetString(bytes); // Replaces all control characters with a space, except for the TAB (0x09), LF (0x0A), CR (0x0D), and // normal ASCII characters, which are valid characters for SharePoint. string receivedData = Regex.Replace(convertedText, @"[^\u0009\u000A\u000D\u0020-\u007E]", " "); string log = receivedData; for (short i = 0; i < short.MaxValue; i++) { if (!log.Contains(" ")) break; log = log.Replace(" ", " "); } log = log.Replace(" ", "\t").Replace(": ", "\t").Replace(":\t", "\t"); IEnumerable lines = (from l in log.Split('\r') select l.Trim()); string logFile = Path.ChangeExtension(logistics.ReportFullPath, ".log"); File.WriteAllLines(logFile, lines); fileInfoCollection.Add(new FileInfo(logFile)); //parse file string h = string.Empty; receivedData = receivedData.Replace("\r", "\n").Trim(); _I = 0; _Data = string.Empty; if (string.IsNullOrEmpty(receivedData)) throw new Exception("No data!"); Detail detail; _I = 0; _Data = receivedData; ScanPast("RUN:"); Run = GetToEOL(); ScanPast("Recipe:"); Recipe = GetBefore("RESISTIVITY SPEC:"); if (string.IsNullOrEmpty(Recipe)) { _I = 0; _Data = receivedData; ScanPast("RUN:"); Run = GetToEOL(); ScanPast("DEVICE:"); Recipe = GetBefore("RESISTIVITY SPEC:"); } ResistivitySpec = GetToEOL(); ScanPast("EQUIP#:"); EquipId = GetBefore("Engineer:"); Engineer = GetToEOL(); ScanPast("LotID:"); Lot = GetBefore("D.L.RATIO:"); // Remove illegal characters \/:*?"<>| found in the Lot. Lot = Regex.Replace(Lot, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0]; DLRatio = GetToEOL(); ScanPast("OPERATOR:"); Employee = GetBefore("TEMP:"); Temp = GetToken(); string dateTimeText = GetToEOL(); DateTime dateTime = GetDateTime(logistics, dateTimeText); Date = dateTime.ToString(); ScanPast("AutoOptimizeGain ="); AutoOptimizeGain = GetBefore("AutoProbeHeightSet ="); AutoProbeHeightSet = GetToEOL(); ScanPast("DataReject"); DataReject = GetToEOL(); GetToEOL(); FileName = GetToEOL(); GetToEOL(); GetToEOL(); bool check = false; while (!IsBlankLine()) { detail = new Detail() { Pt = GetToken() }; if (detail.Pt.Contains("Avg")) break; else if (!detail.Pt.Contains(":")) { detail.R = GetToken(); detail.T = GetToken(); detail.Rs = GetToken(); detail.Merit = GetToken(); detail.UniqueId = string.Concat("_Point-", _Details.Count + 1); GetToEOL(); _Details.Add(detail); } else { check = true; break; } } _I = 0; _Data = receivedData; if (!check) { ScanPast("Avg ="); Avg = GetToken(); StdDev = GetToken(); ScanPast("SEMI Radial="); SemiRadial = GetToEOL(); } else { ScanPast("RsAv "); Avg = GetBefore("+/-"); StdDev = GetToken(); _Log.Debug($"****ProcessData - RsAv StDev={StdDev}"); ScanPast("(Mx+Mn)"); SemiRadial = GetToken(); _Log.Debug($"****ProcessData - RsAv SemiRadial={SemiRadial}"); GetToEOL(); int num = 0; GetBefore(": "); for (string i = GetToken(); !string.IsNullOrEmpty(i); i = GetToken()) { if (!i.Contains(":")) { detail = new Detail(); int num1 = num + 1; num = num1; _Log.Debug($"****ProcessData - RsAv Point={num1}"); detail.Pt = num1.ToString(); detail.Rs = i; detail.Merit = GetToken().Replace("|", ""); detail.UniqueId = string.Concat("_Point-", _Details.Count + 1); _Details.Add(detail); } } } //Id = -1; Run = Run.Trim(); if (!Run.StartsWith("[") && !Run.EndsWith("]")) throw new Exception("Lot summary data is invalid or missing."); Run = Run.Replace("[", ""); Run = Run.Replace("]", ""); Run = Regex.Replace(Run, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0]; _Log.Debug($"****ParseData - cde.Run:'{Run}'"); if (string.IsNullOrEmpty(Run)) throw new Exception("Batch (Run) information does not exist"); //parse out batch and validate string[] parsedBatch = Run.Split('-'); if (parsedBatch.Length >= 1) Reactor = parsedBatch[0]; if (parsedBatch.Length >= 2) RDS = parsedBatch[1]; if (parsedBatch.Length >= 3) { string[] parsedPSN = parsedBatch[2].Split('.'); if (parsedPSN.Length >= 1) PSN = parsedPSN[0]; if (parsedPSN.Length >= 2) Layer = parsedPSN[1]; } if (parsedBatch.Length >= 4) Zone = parsedBatch[3]; //create filename / unique id string timeFormat = "yyyyMMddHHmmss"; //fix equip StringBuilder equipFixed = new(); foreach (char c in EquipId) { if (char.IsLetterOrDigit(c) || c == '-' || c == '.') { equipFixed.Append(c); } } EquipId = equipFixed.ToString(); _Log.Debug($"****ParseData - cde.EquipId:'{EquipId}'"); // The "cde.Run" string is used as part of the SharePoint header unique ID. The "cde.Run" ID is typed // at the tool by the users. The characters are not controlled and the user can type any characters like // "\", "*", ".", " ", etc. Some of these characters are not valid and thus can't be used for the // SharePoint header unique ID. Therefore, we need to filter out invalid characters and only keep the // important ones. StringBuilder runFixed = new(); foreach (char c in Run) { if (char.IsLetterOrDigit(c) || c == '-' || c == '.') runFixed.Append(c); } Run = runFixed.ToString(); UniqueId = string.Concat(EquipId, "_", Run, "_", logistics.DateTimeFromSequence.ToString(timeFormat)); foreach (Detail item in _Details) { item.HeaderUniqueId = UniqueId; item.UniqueId = string.Concat(item, item.UniqueId); } fileInfoCollection.Add(new FileInfo(logistics.ReportFullPath)); } } }