715 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			715 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Data;
 | 
						|
using System.Data.SqlClient;
 | 
						|
using System.Globalization;
 | 
						|
using System.IO;
 | 
						|
using System.Linq;
 | 
						|
using System.Net.Http;
 | 
						|
using System.Text;
 | 
						|
using System.Text.Json;
 | 
						|
using System.Text.RegularExpressions;
 | 
						|
using System.Threading.Tasks;
 | 
						|
 | 
						|
namespace Adaptation.FileHandlers.TIBCO.Transport;
 | 
						|
 | 
						|
#nullable enable
 | 
						|
 | 
						|
public partial class Job
 | 
						|
{
 | 
						|
 | 
						|
    public string? AutomationMode { get; }
 | 
						|
    public string? BasicType { get; }
 | 
						|
    public string? CreationUser { get; }
 | 
						|
    public string? Equipment { get; }
 | 
						|
    public string? JobName { get; }
 | 
						|
    public string? LastUpdateUser { get; }
 | 
						|
    public string? LotName { get; }
 | 
						|
    public string? LotState { get; }
 | 
						|
    public string? PackageName { get; }
 | 
						|
    public string? ProcessSpecName { get; }
 | 
						|
    public string? ProcessType { get; }
 | 
						|
    public string? ProductName { get; }
 | 
						|
    public string? Qty { get; }
 | 
						|
    public string? Qty2 { get; }
 | 
						|
    public string? RecipeName { get; }
 | 
						|
    public string? SpecName { get; }
 | 
						|
    public string? StateModel { get; }
 | 
						|
    public string? Status { get; }
 | 
						|
    //
 | 
						|
    public bool IsAreaSi { get; }
 | 
						|
    public DateTime DateTime { get; }
 | 
						|
    public List<Item> Items { get; }
 | 
						|
 | 
						|
    public Job(string lsl2SQLConnectionString, string metrologyFileShare, string barcodeHostFileShare, HttpClient httpClient, string mid)
 | 
						|
    {
 | 
						|
        const int zero = 0;
 | 
						|
        Items = new List<Item>();
 | 
						|
        if (string.IsNullOrEmpty(mid) || mid[zero] != '{' || mid[mid.Length - 1] != '}' || !mid.Contains("\"Si\""))
 | 
						|
            IsAreaSi = false;
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Common common;
 | 
						|
            CommonB commonB;
 | 
						|
            int? reactorNumber;
 | 
						|
            WorkOrder workOrder;
 | 
						|
            const string hyphen = "-";
 | 
						|
            const string bioRad2 = "BIORAD2";
 | 
						|
            const string bioRad3 = "BIORAD3";
 | 
						|
            const string twoAlphaPattern = "^[a-zA-z]{2,3}";
 | 
						|
            const string reactorNumberPattern = @"^[0-9]{2}--";
 | 
						|
            Input input = JsonSerializer.Deserialize<Input>(mid) ?? throw new Exception();
 | 
						|
            if (!long.TryParse(input.Sequence, out long sequence))
 | 
						|
                DateTime = DateTime.Now;
 | 
						|
            else
 | 
						|
                DateTime = new DateTime(sequence);
 | 
						|
            const string dep08CEPIEPSILON = "DEP08CEPIEPSILON";
 | 
						|
            if (input.EquipmentType == dep08CEPIEPSILON)
 | 
						|
                (common, workOrder) = Get(input, httpClient);
 | 
						|
            else if (!string.IsNullOrEmpty(input.MID) && !string.IsNullOrEmpty(input.MesEntity) && Regex.IsMatch(input.MID, reactorNumberPattern) && input.MesEntity is bioRad2 or bioRad3)
 | 
						|
                (common, workOrder) = Get(input, barcodeHostFileShare);
 | 
						|
            else
 | 
						|
            {
 | 
						|
                workOrder = GetWorkOrder(input);
 | 
						|
                reactorNumber = GetReactorNumber(input);
 | 
						|
                if (workOrder.IsWorkOrder || reactorNumber.HasValue)
 | 
						|
                    common = new(layer: null,
 | 
						|
                                 psn: null,
 | 
						|
                                 rdsNumber: null,
 | 
						|
                                 reactor: null,
 | 
						|
                                 zone: null,
 | 
						|
                                 employee: null);
 | 
						|
                else if (!string.IsNullOrEmpty(input.MID) && input.MID.Length is 2 or 3 && Regex.IsMatch(input.MID, twoAlphaPattern))
 | 
						|
                    common = GetTwoAlphaPattern(metrologyFileShare, input);
 | 
						|
                else
 | 
						|
                    common = Get(input);
 | 
						|
            }
 | 
						|
            bool isValid = IsValid(common.RDSNumber);
 | 
						|
            if (isValid)
 | 
						|
                commonB = GetWithValidRDS(lsl2SQLConnectionString, common.Layer, common.PSN, common.RDSNumber, common.ReactorNumber, common.Zone);
 | 
						|
            else if (workOrder.IsWorkOrder || common.RDSNumber.HasValue)
 | 
						|
                commonB = Get(lsl2SQLConnectionString, common.Layer, common.PSN, common.ReactorNumber, workOrder.SlotNumber, workOrder.WorkOrderNumber, workOrder.WorkOrderCassette, common.Zone);
 | 
						|
            else
 | 
						|
                commonB = new(comment: hyphen,
 | 
						|
                              layer: hyphen,
 | 
						|
                              rdsNumber: common.RDSNumber,
 | 
						|
                              psn: common.PSN,
 | 
						|
                              reactorNumber: common.ReactorNumber,
 | 
						|
                              zone: hyphen);
 | 
						|
            Qty = "1";
 | 
						|
            Status = hyphen; // INFO
 | 
						|
            CreationUser = hyphen; // ?
 | 
						|
            LotState = hyphen; // LAYER2
 | 
						|
            LastUpdateUser = hyphen; // ?
 | 
						|
            Equipment = input.MesEntity; // ?
 | 
						|
            PackageName = hyphen; // WAFER_ID
 | 
						|
            Qty2 = input.Sequence; // SEQUENCE
 | 
						|
            RecipeName = input.Recipe; // PPID
 | 
						|
            IsAreaSi = input.Area == "Si"; // N/A
 | 
						|
            StateModel = input.EquipmentType; // ?
 | 
						|
            JobName = DateTime.Ticks.ToString(); // ?
 | 
						|
            AutomationMode = string.Concat(DateTime.Ticks, ".", input.MesEntity); // ?
 | 
						|
            SpecName = !string.IsNullOrEmpty(commonB.Layer) ? commonB.Layer : hyphen; // LAYER
 | 
						|
            ProductName = !string.IsNullOrEmpty(commonB.PSN) ? commonB.PSN : hyphen; // PRODUCT
 | 
						|
            ProcessSpecName = !string.IsNullOrEmpty(commonB.Zone) ? commonB.Zone : hyphen; // WAFER_POS
 | 
						|
            BasicType = !string.IsNullOrEmpty(commonB.Comment) ? commonB.Comment : hyphen; // BASIC_TYPE
 | 
						|
            LotName = commonB.RDSNumber is not null ? commonB.RDSNumber.Value.ToString() : input.MID; // MID
 | 
						|
            ProcessType = commonB.ReactorNumber is not null ? commonB.ReactorNumber.Value.ToString() : hyphen; // PROCESS_JOBID
 | 
						|
            Items.Add(new Item { Name = "0", Type = "NA", Number = (0 + 1).ToString(), Qty = "1", CarrierName = hyphen });
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    private static int? GetReactorNumber(Input input)
 | 
						|
    {
 | 
						|
        int? result;
 | 
						|
        bool isReactor = !string.IsNullOrEmpty(input.MID) && input.MID.Length == 2 && Regex.IsMatch(input.MID, "^[0-9]{2}$");
 | 
						|
        if (!isReactor)
 | 
						|
            result = null;
 | 
						|
        else if (!int.TryParse(input.MID, out int reactor))
 | 
						|
            result = null;
 | 
						|
        else
 | 
						|
            result = reactor;
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    private static WorkOrder GetWorkOrder(Input input)
 | 
						|
    {
 | 
						|
        WorkOrder result;
 | 
						|
        int? slotNumber;
 | 
						|
        int? workOrderStep = null;
 | 
						|
        int? workOrderNumber = null;
 | 
						|
        MatchCollection[] collection;
 | 
						|
        int? workOrderCassette = null;
 | 
						|
        if (string.IsNullOrEmpty(input.MID))
 | 
						|
            collection = Array.Empty<MatchCollection>();
 | 
						|
        else
 | 
						|
        {
 | 
						|
            string pattern = @"^([oiOI])?([0-9]{6,7})\.([0-5]{1})\.([0-9]{1,2})$"; // o171308.1.51
 | 
						|
            collection = (from l in input.MID.Split('-') select Regex.Matches(l, pattern)).ToArray();
 | 
						|
        }
 | 
						|
        foreach (MatchCollection matchCollection in collection)
 | 
						|
        {
 | 
						|
            if (matchCollection.Count == 0)
 | 
						|
                continue;
 | 
						|
            if (!matchCollection[0].Success || matchCollection[0].Groups.Count != 5)
 | 
						|
                continue;
 | 
						|
            if (!int.TryParse(matchCollection[0].Groups[3].Value, out int workOrderStepValue))
 | 
						|
                continue;
 | 
						|
            if (!int.TryParse(matchCollection[0].Groups[2].Value, out int workOrderNumberValue))
 | 
						|
                continue;
 | 
						|
            if (!int.TryParse(matchCollection[0].Groups[4].Value, out int workOrderCassetteValue))
 | 
						|
                continue;
 | 
						|
            workOrderStep = workOrderStepValue;
 | 
						|
            workOrderNumber = workOrderNumberValue;
 | 
						|
            workOrderCassette = workOrderCassetteValue;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        if (string.IsNullOrEmpty(input.Slot) || !int.TryParse(input.Slot, out int slot))
 | 
						|
            slotNumber = null;
 | 
						|
        else
 | 
						|
            slotNumber = slot;
 | 
						|
        result = new(workOrderNumber: workOrderNumber,
 | 
						|
                     workOrderStep: workOrderStep,
 | 
						|
                     workOrderCassette: workOrderCassette,
 | 
						|
                     slotNumber: slotNumber,
 | 
						|
                     isWorkOrder: workOrderStep is not null || workOrderNumber is not null || workOrderCassette is not null);
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    private static bool IsValid(int? rdsNumber) => !IsInvalid(rdsNumber);
 | 
						|
 | 
						|
    private static bool IsInvalid(int? rdsNumber) => rdsNumber is null or < 100000 or > 100000000;
 | 
						|
 | 
						|
    private static (string?, string?) GetReactorAndRDS(string? text, string formattedText, string[] segments)
 | 
						|
    {
 | 
						|
        string? rds;
 | 
						|
        string? reactor;
 | 
						|
        if (string.IsNullOrEmpty(text) || segments.Length < 1 || string.IsNullOrEmpty(formattedText))
 | 
						|
            reactor = null;
 | 
						|
        else
 | 
						|
            reactor = segments[0];
 | 
						|
        if (segments.Length < 2 || !int.TryParse(segments[1], out int rdsValue) || rdsValue < 99)
 | 
						|
            rds = null;
 | 
						|
        else
 | 
						|
            rds = segments[1];
 | 
						|
        if (!string.IsNullOrEmpty(reactor) && reactor.Length > 3)
 | 
						|
        {
 | 
						|
            rds = reactor;
 | 
						|
            reactor = null;
 | 
						|
        }
 | 
						|
        return new(reactor, rds);
 | 
						|
    }
 | 
						|
 | 
						|
    private static (string?, string?) GetLayerAndPSN(string[] segments)
 | 
						|
    {
 | 
						|
        string? psn;
 | 
						|
        string? layer;
 | 
						|
        if (segments.Length <= 2)
 | 
						|
        {
 | 
						|
            psn = null;
 | 
						|
            layer = null;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            string[] segmentsB = segments[2].Split('.');
 | 
						|
            psn = segmentsB[0];
 | 
						|
            if (segmentsB.Length <= 1)
 | 
						|
                layer = null;
 | 
						|
            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 = null;
 | 
						|
        else
 | 
						|
        {
 | 
						|
            result = segments[3];
 | 
						|
            if (result.Length > 1 && result[0] == '0')
 | 
						|
                result = result.Substring(1);
 | 
						|
        }
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    private static Common Get(Input input)
 | 
						|
    {
 | 
						|
        string? psn;
 | 
						|
        string? rds;
 | 
						|
        int rdsCheck;
 | 
						|
        string? zone;
 | 
						|
        string? layer;
 | 
						|
        int? rdsNumber;
 | 
						|
        string? reactor;
 | 
						|
        string? employee;
 | 
						|
        int? reactorNumber;
 | 
						|
        string mid = string.IsNullOrEmpty(input.MID) ? string.Empty : input.MID;
 | 
						|
        if (mid.Length > 2 && mid[0] == '1' && (mid[1] == 'T' || mid[1] == 't'))
 | 
						|
            mid = mid.Substring(2);
 | 
						|
        mid = Regex.Replace(mid, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
 | 
						|
        string[] segments = mid.Split(new char[] { '-' });
 | 
						|
        // bool hasRDS = Regex.IsMatch(mid, "[-]?([QP][0-9]{4,}|[0-9]{5,})[-]?");
 | 
						|
        (reactor, rds) = GetReactorAndRDS(input.MID, mid, segments);
 | 
						|
        rdsNumber = string.IsNullOrEmpty(rds) || !int.TryParse(rds, out rdsCheck) ? null : rdsCheck;
 | 
						|
        bool isInvalid = IsInvalid(rdsNumber);
 | 
						|
        if (isInvalid || !int.TryParse(reactor, out int reactorCheck))
 | 
						|
        {
 | 
						|
            psn = null;
 | 
						|
            zone = null;
 | 
						|
            layer = null;
 | 
						|
            employee = null;
 | 
						|
            reactorNumber = null;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            zone = GetZone(segments);
 | 
						|
            reactorNumber = reactorCheck;
 | 
						|
            (layer, psn) = GetLayerAndPSN(segments);
 | 
						|
            employee = segments.Length <= 4 ? null : segments[4];
 | 
						|
        }
 | 
						|
        return new(layer: layer,
 | 
						|
                   psn: psn,
 | 
						|
                   rdsNumber: rdsNumber,
 | 
						|
                   reactor: reactorNumber,
 | 
						|
                   zone: zone,
 | 
						|
                   employee: employee);
 | 
						|
    }
 | 
						|
 | 
						|
    private static string[] GetDirectories(string fileShare)
 | 
						|
    {
 | 
						|
        DateTime dateTime = DateTime.Now;
 | 
						|
        DateTime before = dateTime.AddHours(-1);
 | 
						|
        Calendar calendar = new CultureInfo("en-US").Calendar;
 | 
						|
        string weekOfYear = $"{dateTime:yyyy}_Week_{calendar.GetWeekOfYear(dateTime, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
 | 
						|
        string weekOfYearForBefore = $"{before:yyyy}_Week_{calendar.GetWeekOfYear(before, CalendarWeekRule.FirstDay, DayOfWeek.Sunday):00}";
 | 
						|
        return new string[]
 | 
						|
        {
 | 
						|
            Path.Combine(fileShare, weekOfYear, dateTime.ToString("yyyy-MM-dd_HH")),
 | 
						|
            Path.Combine(fileShare, weekOfYearForBefore, before.ToString("yyyy-MM-dd_HH"))
 | 
						|
        };
 | 
						|
    }
 | 
						|
 | 
						|
    private static Common GetTwoAlphaPattern(string metrologyFileShare, Input input)
 | 
						|
    {
 | 
						|
        string lines;
 | 
						|
        const int zero = 0;
 | 
						|
        string? psn = null;
 | 
						|
        int? reactor = null;
 | 
						|
        string? zone = null;
 | 
						|
        string? layer = null;
 | 
						|
        int? rdsNumber = null;
 | 
						|
        List<string> files = new();
 | 
						|
        WorkMaterialOut? workMaterialOut;
 | 
						|
        if (string.IsNullOrEmpty(metrologyFileShare) || !Directory.Exists(metrologyFileShare))
 | 
						|
            throw new Exception($"Unable to access file-share <{metrologyFileShare}>");
 | 
						|
        if (!string.IsNullOrEmpty(input.MID) && input.MID.Length is 3)
 | 
						|
        {
 | 
						|
            string[] checkDirectories = GetDirectories(metrologyFileShare);
 | 
						|
            foreach (string checkDirectory in checkDirectories)
 | 
						|
            {
 | 
						|
                if (!Directory.Exists(checkDirectory))
 | 
						|
                    _ = Directory.CreateDirectory(checkDirectory);
 | 
						|
                files.AddRange(Directory.GetFiles(checkDirectory, $"WMO-{input.MID}.json", SearchOption.TopDirectoryOnly));
 | 
						|
                files.AddRange(Directory.GetFiles(checkDirectory, $"WMO-{input.MID.Substring(1, 2)}{input.MID[zero]}.json", SearchOption.TopDirectoryOnly));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        foreach (string file in files.OrderByDescending(l => new FileInfo(l).LastWriteTime))
 | 
						|
        {
 | 
						|
            lines = File.ReadAllText(file);
 | 
						|
            workMaterialOut = JsonSerializer.Deserialize<WorkMaterialOut>(lines, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
 | 
						|
            if (workMaterialOut is null)
 | 
						|
                continue;
 | 
						|
            if (!string.IsNullOrEmpty(workMaterialOut.Layer))
 | 
						|
                layer = workMaterialOut.Layer;
 | 
						|
            if (!string.IsNullOrEmpty(workMaterialOut.PSN))
 | 
						|
                psn = workMaterialOut.PSN;
 | 
						|
            if (!string.IsNullOrEmpty(workMaterialOut.RunDataSheet) && int.TryParse(workMaterialOut.RunDataSheet, out int rds))
 | 
						|
                rdsNumber = rds;
 | 
						|
            reactor = workMaterialOut.Reactor;
 | 
						|
            if (!string.IsNullOrEmpty(workMaterialOut.Zone))
 | 
						|
                zone = workMaterialOut.Zone;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        return new(layer: layer,
 | 
						|
                   psn: psn,
 | 
						|
                   rdsNumber: rdsNumber,
 | 
						|
                   reactor: reactor,
 | 
						|
                   zone: zone,
 | 
						|
                   employee: null);
 | 
						|
    }
 | 
						|
 | 
						|
    private static List<string> GetFiles(Input input, string barcodeHostFileShare)
 | 
						|
    {
 | 
						|
        List<string> results = new();
 | 
						|
        string[] checkDirectories = GetDirectories(barcodeHostFileShare);
 | 
						|
        foreach (string checkDirectory in checkDirectories)
 | 
						|
        {
 | 
						|
            if (!Directory.Exists(checkDirectory))
 | 
						|
                _ = Directory.CreateDirectory(checkDirectory);
 | 
						|
            results.AddRange(Directory.GetFiles(checkDirectory, $"{input.MesEntity}.csv", SearchOption.TopDirectoryOnly));
 | 
						|
        }
 | 
						|
        return results;
 | 
						|
    }
 | 
						|
 | 
						|
    private static string? GetText(long sequence, List<string> files)
 | 
						|
    {
 | 
						|
        string? result = null;
 | 
						|
        string text;
 | 
						|
        string[] lines;
 | 
						|
        FileInfo fileInfo;
 | 
						|
        foreach (string file in files.OrderByDescending(l => new FileInfo(l).LastWriteTime))
 | 
						|
        {
 | 
						|
            fileInfo = new FileInfo(file);
 | 
						|
            if (fileInfo.LastWriteTime.Ticks > sequence)
 | 
						|
                continue;
 | 
						|
            lines = File.ReadAllLines(file);
 | 
						|
            if (lines.Length == 0)
 | 
						|
                continue;
 | 
						|
            text = lines.First();
 | 
						|
            if (string.IsNullOrEmpty(text) || text.Length < 3 || text[0] != '1' || (text[1] != 't' && text[1] != 'T'))
 | 
						|
                continue;
 | 
						|
            result = text;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    private static (Common common, WorkOrder workOrder) Get(Input input, HttpClient httpClient)
 | 
						|
    {
 | 
						|
        int? rds;
 | 
						|
        string psn;
 | 
						|
        Common common;
 | 
						|
        WorkOrder workOrder;
 | 
						|
        Task<Stream> streamTask;
 | 
						|
        Task<HttpResponseMessage> httpResponseMessageTask;
 | 
						|
        string mid = string.IsNullOrEmpty(input.MID) ? string.Empty : input.MID;
 | 
						|
        JsonSerializerOptions jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true };
 | 
						|
        int? reactor = mid.Length < 2 || !int.TryParse(mid.Substring(0, 2), out int reactorNumber) ? null : reactorNumber;
 | 
						|
        httpResponseMessageTask = httpClient.GetAsync($"{httpClient.BaseAddress}/reactors/{reactor}");
 | 
						|
        httpResponseMessageTask.Wait();
 | 
						|
        if (httpResponseMessageTask.Result.StatusCode != System.Net.HttpStatusCode.OK)
 | 
						|
            throw new Exception($"Unable to OI <{httpResponseMessageTask.Result.StatusCode}>");
 | 
						|
        streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
 | 
						|
        streamTask.Wait();
 | 
						|
        if (!streamTask.Result.CanRead)
 | 
						|
            throw new NullReferenceException(nameof(streamTask));
 | 
						|
        ReactorRoot? reactorRoot = JsonSerializer.Deserialize<ReactorRoot>(streamTask.Result, jsonSerializerOptions);
 | 
						|
        streamTask.Result.Dispose();
 | 
						|
        if (reactorRoot is null || reactor != reactorRoot.Reactor.ReactorNo || reactorRoot.Reactor.LoadedRDS is null || reactorRoot.Reactor.LoadedRDS.Length < 1)
 | 
						|
        {
 | 
						|
            rds = null;
 | 
						|
            psn = string.Empty;
 | 
						|
            workOrder = new(null, null, null, null, false);
 | 
						|
            common = new(layer: null,
 | 
						|
                         psn: psn,
 | 
						|
                         rdsNumber: rds,
 | 
						|
                         reactor: reactor,
 | 
						|
                         zone: null,
 | 
						|
                         employee: null);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            rds = reactorRoot.Reactor.LoadedRDS[0];
 | 
						|
            workOrder = new(null, null, null, null, false);
 | 
						|
            httpResponseMessageTask = httpClient.GetAsync($"{httpClient.BaseAddress}/materials/rds/{rds}");
 | 
						|
            httpResponseMessageTask.Wait();
 | 
						|
            if (httpResponseMessageTask.Result.StatusCode != System.Net.HttpStatusCode.OK)
 | 
						|
                throw new Exception($"Unable to OI <{httpResponseMessageTask.Result.StatusCode}>");
 | 
						|
            streamTask = httpResponseMessageTask.Result.Content.ReadAsStreamAsync();
 | 
						|
            streamTask.Wait();
 | 
						|
            if (!streamTask.Result.CanRead)
 | 
						|
                throw new NullReferenceException(nameof(streamTask));
 | 
						|
            RunDataSheetRoot? runDataSheetRoot = JsonSerializer.Deserialize<RunDataSheetRoot>(streamTask.Result, jsonSerializerOptions);
 | 
						|
            streamTask.Result.Dispose();
 | 
						|
            if (runDataSheetRoot is null || reactor != runDataSheetRoot.RunDataSheet.Reactor)
 | 
						|
            {
 | 
						|
                psn = string.Empty;
 | 
						|
                common = new(layer: null,
 | 
						|
                             psn: psn,
 | 
						|
                             rdsNumber: rds,
 | 
						|
                             reactor: reactor,
 | 
						|
                             zone: null,
 | 
						|
                             employee: null);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                psn = runDataSheetRoot.RunDataSheet.PSN.ToString();
 | 
						|
                common = new(layer: null,
 | 
						|
                             psn: psn,
 | 
						|
                             rdsNumber: rds,
 | 
						|
                             reactor: reactor,
 | 
						|
                             zone: null,
 | 
						|
                             employee: null);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return new(common, workOrder);
 | 
						|
    }
 | 
						|
 | 
						|
    private static (Common common, WorkOrder workOrder) Get(Input input, string barcodeHostFileShare)
 | 
						|
    {
 | 
						|
        if (string.IsNullOrEmpty(barcodeHostFileShare) || !Directory.Exists(barcodeHostFileShare))
 | 
						|
            throw new Exception($"Unable to access file-share <{barcodeHostFileShare}>");
 | 
						|
        int? rds;
 | 
						|
        long sequence = 0;
 | 
						|
        WorkOrder workOrder;
 | 
						|
        string mid = string.IsNullOrEmpty(input.MID) ? string.Empty : input.MID;
 | 
						|
        int? reactor = mid.Length < 2 || !int.TryParse(mid.Substring(0, 2), out int reactorNumber) ? null : reactorNumber;
 | 
						|
        bool parsed = !string.IsNullOrEmpty(input.Sequence) && long.TryParse(input.Sequence, out sequence);
 | 
						|
        List<string> files;
 | 
						|
        if (!parsed || string.IsNullOrEmpty(input.MID))
 | 
						|
            files = new();
 | 
						|
        else
 | 
						|
            files = GetFiles(input, barcodeHostFileShare);
 | 
						|
        string? text = GetText(sequence, files);
 | 
						|
        if (text is null || text.Length < 3)
 | 
						|
        {
 | 
						|
            rds = null;
 | 
						|
            workOrder = new(null, null, null, null, false);
 | 
						|
        }
 | 
						|
        else if (!text.Contains('.'))
 | 
						|
        {
 | 
						|
            rds = !int.TryParse(text.Substring(2), out int rdsNumber) ? null : rdsNumber;
 | 
						|
            workOrder = new(null, null, null, null, false);
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            rds = null;
 | 
						|
            workOrder = GetWorkOrder(new(input, text.Substring(2)));
 | 
						|
        }
 | 
						|
        Common common = new(layer: null,
 | 
						|
                            psn: null,
 | 
						|
                            rdsNumber: rds,
 | 
						|
                            reactor: reactor,
 | 
						|
                            zone: null,
 | 
						|
                            employee: null);
 | 
						|
        return new(common, workOrder);
 | 
						|
    }
 | 
						|
 | 
						|
#nullable disable
 | 
						|
 | 
						|
    private static string GetRunJson(string lsl2SQLConnectionString, string commandText)
 | 
						|
    {
 | 
						|
        StringBuilder result = new();
 | 
						|
        try
 | 
						|
        {
 | 
						|
            using SqlConnection sqlConnection = new(lsl2SQLConnectionString);
 | 
						|
            sqlConnection.Open();
 | 
						|
            using SqlCommand sqlCommand = new(commandText, sqlConnection);
 | 
						|
            SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(CommandBehavior.SequentialAccess);
 | 
						|
            while (sqlDataReader.Read())
 | 
						|
                _ = result.Append(sqlDataReader.GetString(0));
 | 
						|
        }
 | 
						|
        catch (Exception)
 | 
						|
        {
 | 
						|
            _ = result.Clear();
 | 
						|
        }
 | 
						|
        return result.ToString();
 | 
						|
    }
 | 
						|
 | 
						|
    private static string GetCommandText(int? rds, int? workOrderNumber, int? workOrderCassette, int? slot, int? reactor)
 | 
						|
    { // cSpell:disable
 | 
						|
        List<string> results = new();
 | 
						|
        int rdsValue = rds is null ? -1 : rds.Value;
 | 
						|
        int slotValue = slot is null ? -1 : slot.Value;
 | 
						|
        int reactorValue = reactor is null ? -1 : reactor.Value;
 | 
						|
        int workOrderNumberValue = workOrderNumber is null ? -1 : workOrderNumber.Value;
 | 
						|
        int workOrderCassetteValue = workOrderCassette is null ? -1 : workOrderCassette.Value;
 | 
						|
        results.Add(" select ");
 | 
						|
        results.Add("         rr.rds_no ");
 | 
						|
        results.Add("       , rr.reactor ");
 | 
						|
        results.Add("       , rr.ps_no ");
 | 
						|
        results.Add("       , rr.load_lock_side ");
 | 
						|
        results.Add("       , rr.reactor_type ");
 | 
						|
        results.Add("       , rr.recipe_name ");
 | 
						|
        results.Add("       , rr.recipe_no ");
 | 
						|
        results.Add("       , rr.spec_type ");
 | 
						|
        results.Add("       , ( ");
 | 
						|
        results.Add("           select max(wm.zone) ");
 | 
						|
        results.Add("           from lsl2sql.dbo.wm_out_slot wm ");
 | 
						|
        results.Add("           where wm.wo_no = rr.wo_no ");
 | 
						|
        results.Add("             and wm.rds = rr.rds_no ");
 | 
						|
        results.Add($"             and wm.in_cass_no = {workOrderCassetteValue}");
 | 
						|
        results.Add($"             and wm.slot_no = {slotValue}");
 | 
						|
        results.Add("       ) zone ");
 | 
						|
        results.Add(" from lsl2sql.dbo.react_run rr ");
 | 
						|
        results.Add($" where rr.rds_no = {rdsValue}");
 | 
						|
        results.Add(" union all ");
 | 
						|
        results.Add(" select ");
 | 
						|
        results.Add("         rr.rds_no ");
 | 
						|
        results.Add("       , rr.reactor ");
 | 
						|
        results.Add("       , rr.ps_no ");
 | 
						|
        results.Add("       , rr.load_lock_side ");
 | 
						|
        results.Add("       , rr.reactor_type ");
 | 
						|
        results.Add("       , rr.recipe_name ");
 | 
						|
        results.Add("       , rr.recipe_no ");
 | 
						|
        results.Add("       , rr.spec_type ");
 | 
						|
        results.Add("       , ( ");
 | 
						|
        results.Add("           select max(wm.zone) ");
 | 
						|
        results.Add("           from lsl2sql.dbo.wm_out_slot wm ");
 | 
						|
        results.Add("           where wm.wo_no = rr.wo_no ");
 | 
						|
        results.Add("             and wm.rds = rr.rds_no ");
 | 
						|
        results.Add($"             and wm.in_cass_no = {workOrderCassetteValue}");
 | 
						|
        results.Add($"             and wm.slot_no = {slotValue}");
 | 
						|
        results.Add("       ) zone ");
 | 
						|
        results.Add(" from lsl2sql.dbo.react_run rr ");
 | 
						|
        results.Add(" where rr.rds_no = ( ");
 | 
						|
        results.Add("   select max(wm.rds) ");
 | 
						|
        results.Add("   from lsl2sql.dbo.wm_out_slot wm ");
 | 
						|
        results.Add($"   where wm.wo_no = {workOrderNumberValue}");
 | 
						|
        results.Add($"     and wm.in_cass_no = {workOrderCassetteValue}");
 | 
						|
        results.Add($"     and wm.slot_no = {slotValue}");
 | 
						|
        results.Add(" ) ");
 | 
						|
        results.Add(" union all ");
 | 
						|
        results.Add(" select ");
 | 
						|
        results.Add("         rr.rds_no ");
 | 
						|
        results.Add("       , rr.reactor ");
 | 
						|
        results.Add("       , rr.ps_no ");
 | 
						|
        results.Add("       , rr.load_lock_side ");
 | 
						|
        results.Add("       , rr.reactor_type ");
 | 
						|
        results.Add("       , rr.recipe_name ");
 | 
						|
        results.Add("       , rr.recipe_no ");
 | 
						|
        results.Add("       , rr.spec_type ");
 | 
						|
        results.Add("       , ( ");
 | 
						|
        results.Add("           select max(wm.zone) ");
 | 
						|
        results.Add("           from lsl2sql.dbo.wm_out_slot wm ");
 | 
						|
        results.Add("           where wm.wo_no = rr.wo_no ");
 | 
						|
        results.Add("             and wm.rds = rr.rds_no ");
 | 
						|
        results.Add($"             and wm.in_cass_no = {workOrderCassetteValue}");
 | 
						|
        results.Add($"             and wm.slot_no = {slotValue}");
 | 
						|
        results.Add("       ) zone ");
 | 
						|
        results.Add(" from lsl2sql.dbo.react_run rr ");
 | 
						|
        results.Add(" where rr.rds_no = ( ");
 | 
						|
        results.Add("   select max(qa.rds_no) ");
 | 
						|
        results.Add("   from lsl2sql.dbo.react_run qa ");
 | 
						|
        results.Add("   where qa.load_sig != '' ");
 | 
						|
        results.Add("       and qa.load_sig_dtm > '2023-05-01 00:00:00.000' ");
 | 
						|
        results.Add($"       and qa.reactor = {reactorValue}");
 | 
						|
        results.Add(" ) ");
 | 
						|
        results.Add(" for json path ");
 | 
						|
        return string.Join(Environment.NewLine, results);
 | 
						|
    } // cSpell:restore
 | 
						|
 | 
						|
    private static CommonB Get(string lsl2SQLConnectionString, string layer, string psn, int? reactorNumber, int? slotNumber, int? workOrderNumber, int? workOrderCassette, string zone)
 | 
						|
    {
 | 
						|
        int? rdsNumber;
 | 
						|
        string comment;
 | 
						|
        const int zero = 0;
 | 
						|
        const string hyphen = "-";
 | 
						|
        string commandText = GetCommandText(rds: null,
 | 
						|
                                            workOrderNumber: workOrderNumber,
 | 
						|
                                            workOrderCassette: workOrderCassette,
 | 
						|
                                            slot: slotNumber,
 | 
						|
                                            reactor: reactorNumber);
 | 
						|
        string json = GetRunJson(lsl2SQLConnectionString, commandText);
 | 
						|
        if (string.IsNullOrEmpty(json))
 | 
						|
        {
 | 
						|
            rdsNumber = null;
 | 
						|
            comment = hyphen;
 | 
						|
            psn = string.Empty;
 | 
						|
            zone = string.Empty;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Run[] runs;
 | 
						|
            try
 | 
						|
            { runs = JsonSerializer.Deserialize<Run[]>(json); }
 | 
						|
            catch (Exception)
 | 
						|
            { runs = Array.Empty<Run>(); }
 | 
						|
            if (runs.Length == 0)
 | 
						|
            {
 | 
						|
                rdsNumber = null;
 | 
						|
                comment = hyphen;
 | 
						|
                psn = string.Empty;
 | 
						|
                zone = string.Empty;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                rdsNumber = runs[zero].RdsNo;
 | 
						|
                if (string.IsNullOrEmpty(psn))
 | 
						|
                    psn = runs[zero].PSN;
 | 
						|
                if (string.IsNullOrEmpty(zone))
 | 
						|
                    zone = runs[zero].Zone;
 | 
						|
                if (string.IsNullOrEmpty(layer))
 | 
						|
                    layer = runs[zero].EpiLayer;
 | 
						|
                reactorNumber = runs[zero].Reactor;
 | 
						|
                string loadLockSide = runs[zero].LoadLockSide;
 | 
						|
                string loadLockSideFull = loadLockSide switch
 | 
						|
                {
 | 
						|
                    "L" => "Left",
 | 
						|
                    "R" => "Right",
 | 
						|
                    _ => loadLockSide,
 | 
						|
                };
 | 
						|
                comment = $"{loadLockSideFull} - {runs[zero].ReactorType}";
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return new(comment: comment,
 | 
						|
                   layer: layer,
 | 
						|
                   rdsNumber: rdsNumber,
 | 
						|
                   psn: psn,
 | 
						|
                   reactorNumber: reactorNumber,
 | 
						|
                   zone: zone);
 | 
						|
    }
 | 
						|
 | 
						|
    private static CommonB GetWithValidRDS(string lsl2SQLConnectionString, string layer, string psn, int? rdsNumber, int? reactorNumber, string zone)
 | 
						|
    {
 | 
						|
        string comment;
 | 
						|
        const int zero = 0;
 | 
						|
        const string hyphen = "-";
 | 
						|
        string commandText = GetCommandText(rds: rdsNumber,
 | 
						|
                                            workOrderNumber: null,
 | 
						|
                                            workOrderCassette: null,
 | 
						|
                                            slot: null,
 | 
						|
                                            reactor: null);
 | 
						|
        string json = GetRunJson(lsl2SQLConnectionString, commandText);
 | 
						|
        if (string.IsNullOrEmpty(json))
 | 
						|
        {
 | 
						|
            comment = hyphen;
 | 
						|
            zone = string.Empty;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            Run[] runs;
 | 
						|
            try
 | 
						|
            { runs = JsonSerializer.Deserialize<Run[]>(json); }
 | 
						|
            catch (Exception)
 | 
						|
            { runs = Array.Empty<Run>(); }
 | 
						|
            if (runs.Length == 0)
 | 
						|
            {
 | 
						|
                comment = hyphen;
 | 
						|
                zone = string.Empty;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                if (string.IsNullOrEmpty(psn))
 | 
						|
                    psn = runs[zero].PSN;
 | 
						|
                if (string.IsNullOrEmpty(zone))
 | 
						|
                    zone = runs[zero].Zone;
 | 
						|
                if (string.IsNullOrEmpty(layer))
 | 
						|
                    layer = runs[zero].EpiLayer;
 | 
						|
                reactorNumber = runs[zero].Reactor is null ? reactorNumber : runs[zero].Reactor.Value;
 | 
						|
                string loadLockSide = runs[zero].LoadLockSide;
 | 
						|
                string loadLockSideFull = loadLockSide switch
 | 
						|
                {
 | 
						|
                    "L" => "Left",
 | 
						|
                    "R" => "Right",
 | 
						|
                    _ => loadLockSide,
 | 
						|
                };
 | 
						|
                comment = $"{loadLockSideFull} - {runs[zero].ReactorType}";
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return new(comment: comment,
 | 
						|
                   layer: layer,
 | 
						|
                   rdsNumber: rdsNumber,
 | 
						|
                   psn: psn,
 | 
						|
                   reactorNumber: reactorNumber,
 | 
						|
                   zone: zone);
 | 
						|
    }
 | 
						|
 | 
						|
} |