using System; using System.Collections.Generic; using System.Data.SqlClient; using System.IO; using System.Linq; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; namespace Adaptation.FileHandlers.TIBCO.Transport; public class Job { public string AutomationMode { get; } public string BasicType { get; } public string EpiLayer { get; } public string Equipment { get; } public string JobName { get; } public string LotName { get; } public string PackageName { get; } public string ProcessSpecName { get; } public string ProcessType { get; } public string ProductName { get; } public string Qty { get; } public string RecipeName { get; } public string StateModel { get; } // public bool IsAreaSi { get; } public DateTime DateTime { get; } public List Items { get; } public Job(string lsl2SQLConnectionString, string metrologyFileShare, string mid) { const int zero = 0; Items = new List(); if (string.IsNullOrEmpty(mid) || mid[zero] != '{' || mid[mid.Length - 1] != '}' || !mid.Contains("\"Si\"")) IsAreaSi = false; else { int rds; string psn; string lotName; string reactor; string epiLayer; string basicType; const string hyphen = "-"; Input input = JsonSerializer.Deserialize(mid); IsAreaSi = input.Area == "Si"; if (input.MID is null) input.MID = string.Empty; if (!long.TryParse(input.Sequence, out long sequence)) DateTime = DateTime.Now; else DateTime = new DateTime(sequence); if (input.MID.Length is not 2 and not 3) (psn, rds, reactor) = Get(input); else (psn, rds, reactor) = Get(metrologyFileShare, input); AutomationMode = string.Concat(DateTime.Ticks, ".", input.MesEntity); Equipment = input.MesEntity; JobName = DateTime.Ticks.ToString(); if (!IsValid(rds)) (basicType, epiLayer, lotName, psn, reactor) = Get(lsl2SQLConnectionString, psn, rds, reactor); else { basicType = hyphen; lotName = input.MID; epiLayer = "1"; } EpiLayer = epiLayer; BasicType = basicType; LotName = lotName; PackageName = hyphen; //WAFER_ID WaferLot ProcessSpecName = hyphen; //WAFER_POS PocketNumber ProcessType = reactor; ProductName = psn; Qty = "1"; RecipeName = input.Recipe; StateModel = input.EquipmentType; Items.Add(new Item { Name = "0", Type = "NA", Number = (0 + 1).ToString(), Qty = "1", CarrierName = hyphen }); } } private static bool IsValid(int rds) => rds is < 100000 or > 100000000; private static (string, int, string) Get(Input input) { int rds; string psn; string reactor; const int zero = 0; string[] segments = Regex.Split(input.MID, @"[^0-9']"); if (segments.Length < 3) rds = 0; else _ = int.TryParse(segments[1], out rds); if (IsValid(rds)) { psn = string.Empty; reactor = string.Empty; } else { psn = segments[2]; reactor = segments[zero]; } return new(psn, rds, reactor); } private static (string, int, string) Get(string metrologyFileShare, Input input) { int rds = 0; string psn; string reactor; string[] lines; string moveFile; psn = string.Empty; reactor = string.Empty; string usedDirectory = Path.Combine(metrologyFileShare, "Used"); if (!Directory.Exists(metrologyFileShare)) throw new Exception($"Unable to access file-share <{metrologyFileShare}>"); if (!Directory.Exists(usedDirectory)) _ = Directory.CreateDirectory(usedDirectory); string[] files = Directory.GetFiles(metrologyFileShare, $"*-{input.MID}.rsv", SearchOption.TopDirectoryOnly); foreach (string file in files.OrderByDescending(l => new FileInfo(l).LastWriteTime)) { lines = File.ReadAllLines(file); foreach (string line in lines) { if (string.IsNullOrEmpty(line)) continue; if (!int.TryParse(line, out rds) || IsValid(rds)) continue; break; } if (rds != 0) { moveFile = Path.Combine(usedDirectory, Path.GetFileName(file)); if (File.Exists(moveFile)) File.Delete(file); else File.Move(file, moveFile); break; } } return new(psn, rds, reactor); } private static string GetRunJson(string lsl2SQLConnectionString, int rds) { string result; object scalar = null; StringBuilder sql = new(); _ = sql.Append(" select "). Append(" qa.rds_no "). Append(" , qa.max_rds_layer_keys_mv_no "). Append(" , qa.max_part_no "). Append(" , substring(max_part_no, 0, len(max_part_no)) max_part_no_substr_0 "). Append(" , substring(max_part_no, 1, len(max_part_no)) max_part_no_substr_1 "). Append(" , rr.part_no "). Append(" , rr.reactor "). Append(" , rr.ps_no "). Append(" , rr.load_lock_side "). Append(" , rr.reactor_type "). Append(" , rr.recipe_name "). Append(" , rr.recipe_no "). Append(" , rr.spec_type "). Append(" , react_tool_id "). Append(" , epi_layer "). Append(" , epi_step "). Append(" , epi_step_lsid "). Append(" , epi_dopant "). Append(" , epi_thick_min "). Append(" , epi_thick_max "). Append(" , epi_thick_targ "). Append(" , epi_res_min "). Append(" , epi_res_max "). Append(" , epi_res_targ "). Append(" from ( "). Append(" select top (1000) "). Append(" rds_no "). Append(" , ( "). Append(" select max(mv_no) "). Append(" from lsl2sql.dbo.rds_rds_layer_keys "). Append(" where seq = rds_no "). Append(" ) max_rds_layer_keys_mv_no "). Append(" , case when part_no != '' "). Append(" then part_no "). Append(" else "). Append(" ( "). Append(" select max(part_no) "). Append(" from lsl2sql.dbo.react_run b "). Append(" where b.ps_no = qa.ps_no "). Append(" ) "). Append(" end max_part_no "). Append(" from lsl2sql.dbo.react_run qa "). Append(" where rds_no = '").Append(rds).Append("' "). Append(" ) as qa "). Append(" inner join lsl2sql.dbo.react_run rr "). Append(" on qa.rds_no = rr.rds_no "). Append(" left join lsl2sql.dbo.epi_part_layer_spec es "). Append(" on max_part_no = epi_pn "). Append(" or substring(max_part_no, 0, len(max_part_no)) = epi_pn "). Append(" or substring(max_part_no, 1, len(max_part_no)) = epi_pn "). Append(" order by epi_layer "). Append(" for json path "); try { using SqlConnection sqlConnection = new(lsl2SQLConnectionString); sqlConnection.Open(); using (SqlCommand sqlCommand = new(sql.ToString(), sqlConnection)) scalar = sqlCommand.ExecuteScalar(); sqlConnection.Close(); } catch (Exception) { } if (scalar is null) result = string.Empty; else result = scalar.ToString(); return result; } private static (string, string, string, string, string) Get(string lsl2SQLConnectionString, string psn, int rds, string reactor) { string lotName; string epiLayer; string basicType; const int zero = 0; const string hyphen = "-"; lotName = rds.ToString(); string json = GetRunJson(lsl2SQLConnectionString, rds); if (string.IsNullOrEmpty(json)) { epiLayer = "1"; basicType = hyphen; } else { Run[] runs; try { runs = JsonSerializer.Deserialize(json); } catch (Exception) { runs = Array.Empty(); } if (!runs.Any()) { epiLayer = "1"; basicType = hyphen; } else { if (string.IsNullOrEmpty(reactor)) reactor = runs[zero].Reactor.ToString(); if (string.IsNullOrEmpty(psn)) psn = runs[zero].PSN; string loadLockSide = runs[zero].LoadLockSide; string loadLockSideFull = loadLockSide switch { "L" => "Left", "R" => "Right", _ => loadLockSide, }; basicType = $"{loadLockSideFull} - {runs[zero].ReactorType}"; int maxRdsLayerKeysMvNo = runs[zero].MaxRdsLayerKeysMvNo; if (maxRdsLayerKeysMvNo == 1) epiLayer = "1"; else { epiLayer = runs[zero].EpiLayer; foreach (Run run in runs) { if (run.EpiThickMin is null || run.EpiThickMax is null) continue; if (run.EpiResMin is null || run.EpiResMax is null) continue; } } } } return new(basicType, epiLayer, lotName, psn, reactor); } }