2022-10-10 17:35:21 -07:00

371 lines
14 KiB
C#

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<Item> Items { get; }
public Job(string lsl2SQLConnectionString, string metrologyFileShare, 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
{
string psn;
int? rdsNumber;
string epiLayer;
string basicType;
const string hyphen = "-";
Input input = JsonSerializer.Deserialize<Input>(mid);
if (!long.TryParse(input.Sequence, out long sequence))
DateTime = DateTime.Now;
else
DateTime = new DateTime(sequence);
int? reactorNumber = GetReactorNumber(input);
(int? workOrderNumber, int? _, int? workOrderCassette, int? slotNumber, bool isWorkOrder) = GetWorkOrder(input);
if (isWorkOrder || reactorNumber.HasValue)
(psn, rdsNumber) = (string.Empty, null);
else if (input.MID.Length is not 2 and not 3)
(psn, rdsNumber, reactorNumber) = Get(input);
else
(psn, rdsNumber, reactorNumber) = Get(metrologyFileShare, input);
Equipment = input.MesEntity;
IsAreaSi = input.Area == "Si";
JobName = DateTime.Ticks.ToString();
AutomationMode = string.Concat(DateTime.Ticks, ".", input.MesEntity);
if (IsValid(rdsNumber))
(basicType, rdsNumber, psn, reactorNumber, epiLayer) = GetWithValidRDS(lsl2SQLConnectionString, psn, rdsNumber, reactorNumber);
else if (isWorkOrder || reactorNumber.HasValue)
(basicType, rdsNumber, psn, reactorNumber, epiLayer) = Get(lsl2SQLConnectionString, reactorNumber, slotNumber, workOrderNumber, workOrderCassette);
else
{
epiLayer = "1";
basicType = hyphen;
}
Qty = "1";
ProductName = psn;
EpiLayer = epiLayer;
BasicType = basicType;
RecipeName = input.Recipe;
StateModel = input.EquipmentType;
PackageName = hyphen; //WAFER_ID WaferLot
ProcessSpecName = hyphen; //WAFER_POS PocketNumber
if (rdsNumber is null)
LotName = input.MID;
else
LotName = rdsNumber.Value.ToString();
if (reactorNumber is null)
ProcessType = string.Empty;
else
ProcessType = reactorNumber.Value.ToString();
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 (int?, int?, int?, int?, bool) GetWorkOrder(Input input)
{
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;
return new(workOrderNumber, workOrderStep, workOrderCassette, slotNumber, workOrderStep is not null || workOrderNumber is not null || workOrderCassette is not null);
}
private static bool IsValid(int? rdsNumber) => !IsInvalid(rdsNumber);
private static bool IsInvalid(int? rdsNumber) => rdsNumber is null or < 100000 or > 100000000;
private static (string, int, int?) Get(Input input)
{
string psn;
int rdsNumber;
int? reactorNumber;
const int zero = 0;
string[] segments;
if (string.IsNullOrEmpty(input.MID))
segments = Array.Empty<string>();
else
segments = Regex.Split(input.MID, "[^0-9']");
if (segments.Length < 3)
rdsNumber = 0;
else
_ = int.TryParse(segments[1], out rdsNumber);
if (IsInvalid(rdsNumber) || !int.TryParse(segments[zero], out int reactor))
{
psn = string.Empty;
reactorNumber = null;
}
else
{
psn = segments[2];
reactorNumber = reactor;
}
return new(psn, rdsNumber, reactorNumber);
}
private static (string, int?, int?) Get(string metrologyFileShare, Input input)
{
string[] files;
string[] lines;
string moveFile;
int? reactor = null;
int? rdsNumber = null;
string psn = 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);
if (string.IsNullOrEmpty(input.MID))
files = Array.Empty<string>();
else
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 int rds) || IsInvalid(rds))
continue;
rdsNumber = rds;
break;
}
if (rdsNumber is not null)
{
moveFile = Path.Combine(usedDirectory, Path.GetFileName(file));
if (File.Exists(moveFile))
File.Delete(file);
else
File.Move(file, moveFile);
break;
}
}
return new(psn, rdsNumber, reactor);
}
private static string GetRunJson(string lsl2SQLConnectionString, int? rds, int? workOrderNumber, int? workOrderCassette, int? slot, int? reactor)
{
string result;
object scalar = null;
StringBuilder sql = new();
_ = sql.Append(" select ").
Append(" rr.rds_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(" from lsl2sql.dbo.react_run rr ").
Append(" where rr.rds_no = ").Append(rds is null ? -1 : rds.Value).Append(' ').
Append(" union all ").
Append(" select ").
Append(" rr.rds_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(" from lsl2sql.dbo.react_run rr ").
Append(" where rr.rds_no = ( ").
Append(" select max(wm.rds_no) ").
Append(" from lsl2sql.dbo.wm_in_slot_no wm ").
Append(" where wm.wo_no = ").Append(workOrderNumber is null ? -1 : workOrderNumber.Value).Append(' ').
Append(" and wm.in_cass_no = ").Append(workOrderCassette is null ? -1 : workOrderCassette.Value).Append(' ').
Append(" and wm.slot_no = ").Append(slot is null ? -1 : slot.Value).Append(' ').
Append(" ) ").
Append(" union all ").
Append(" select ").
Append(" rr.rds_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(" from lsl2sql.dbo.react_run rr ").
Append(" where rr.rds_no = ( ").
Append(" select max(qa.rds_no) ").
Append(" from lsl2sql.dbo.react_run qa ").
Append(" where qa.load_sig != '' ").
Append(" and qa.load_sig_dtm > '2022-07-01 00:00:00.000' ").
Append(" and qa.reactor = ").Append(reactor is null ? -1 : reactor.Value).Append(' ').
Append(" ) ").
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, int?, string, int?, string) Get(string lsl2SQLConnectionString, int? reactorNumber, int? slotNumber, int? workOrderNumber, int? workOrderCassette)
{
string psn;
int? rdsNumber;
string basicType;
const int zero = 0;
string epiLayer = "1";
const string hyphen = "-";
string json = GetRunJson(lsl2SQLConnectionString, rds: -1, workOrderNumber, workOrderCassette, slotNumber, reactorNumber);
if (string.IsNullOrEmpty(json))
{
rdsNumber = null;
basicType = hyphen;
psn = string.Empty;
}
else
{
Run[] runs;
try
{ runs = JsonSerializer.Deserialize<Run[]>(json); }
catch (Exception)
{ runs = Array.Empty<Run>(); }
if (!runs.Any())
{
rdsNumber = null;
basicType = hyphen;
psn = string.Empty;
}
else
{
psn = runs[zero].PSN;
rdsNumber = runs[zero].RdsNo;
if (reactorNumber is null)
reactorNumber = runs[zero].Reactor;
string loadLockSide = runs[zero].LoadLockSide;
string loadLockSideFull = loadLockSide switch
{
"L" => "Left",
"R" => "Right",
_ => loadLockSide,
};
basicType = $"{loadLockSideFull} - {runs[zero].ReactorType}";
}
}
return new(basicType, rdsNumber, psn, reactorNumber, epiLayer);
}
private static (string, int?, string, int?, string) GetWithValidRDS(string lsl2SQLConnectionString, string psn, int? rdsNumber, int? reactorNumber)
{
string basicType;
const int zero = 0;
string epiLayer = "1";
const string hyphen = "-";
string json = GetRunJson(lsl2SQLConnectionString, rdsNumber, workOrderNumber: -1, workOrderCassette: -1, slot: -1, reactor: -1);
if (string.IsNullOrEmpty(json))
basicType = hyphen;
else
{
Run[] runs;
try
{ runs = JsonSerializer.Deserialize<Run[]>(json); }
catch (Exception)
{ runs = Array.Empty<Run>(); }
if (!runs.Any())
basicType = hyphen;
else
{
if (string.IsNullOrEmpty(psn))
psn = runs[zero].PSN;
if (reactorNumber is null)
reactorNumber = runs[zero].Reactor;
string loadLockSide = runs[zero].LoadLockSide;
string loadLockSideFull = loadLockSide switch
{
"L" => "Left",
"R" => "Right",
_ => loadLockSide,
};
basicType = $"{loadLockSideFull} - {runs[zero].ReactorType}";
}
}
return new(basicType, rdsNumber, psn, reactorNumber, epiLayer);
}
}