using System.Collections.ObjectModel; using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; using Microsoft.Extensions.Logging; namespace File_Folder_Helper.ADO2025.PI6; internal static partial class Helper20250521 { [GeneratedRegex(@"[~\-,.0-9]")] private static partial Regex Number(); [GeneratedRegex(@"[^\u0020-\u007E]")] private static partial Regex ASCII(); private record Record(string Directory, string FileNameWithoutExtension); private record LineCheck(string[] Segments, DateTime TransactionDate, DateTime EffectiveDate) { internal static LineCheck Get(int dateLineSegmentCount, string datePattern, string line) { LineCheck result; string[] segments = line.Split(' '); if (segments.Length >= dateLineSegmentCount && segments[0].Length == datePattern.Length && segments[1].Length == datePattern.Length && DateTime.TryParseExact(segments[0], datePattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime transactionDate) && DateTime.TryParseExact(segments[1], datePattern, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime effectiveDate)) { result = new(Segments: segments, TransactionDate: transactionDate, EffectiveDate: effectiveDate); } else { result = new(Segments: segments, TransactionDate: DateTime.MinValue, EffectiveDate: DateTime.MinValue); } return result; } } private record RecordB(int I, DateTime TransactionDate, DateTime EffectiveDate, string Description, decimal WithdrawalOrDeposit, decimal Balance); [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(RecordB[]))] private partial class Helper20250521RecordB : JsonSerializerContext { } internal static void MatchDirectory(ILogger logger, List args) { Record record; string datePattern = args[5]; string searchPattern = args[2]; string searchPatternB = args[3]; string columns = args[6].Replace('~', ','); int dateLineSegmentCount = int.Parse(args[4]); string sourceDirectory = Path.GetFullPath(args[0].Split('~')[0]); ReadOnlyDictionary keyValuePairs = GetKeyValuePairs(searchPattern, sourceDirectory); MoveMatchDirectory(searchPatternB, keyValuePairs, sourceDirectory); ReadOnlyCollection records = GetRecords(searchPatternB, sourceDirectory, dateLineSegmentCount, datePattern, columns); WriteRecords(sourceDirectory, records); } private static ReadOnlyDictionary GetKeyValuePairs(string searchPattern, string sourceDirectory) { Dictionary results = []; string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.AllDirectories); foreach (string file in files) { results.Add(Path.GetFileNameWithoutExtension(file), Path.GetDirectoryName(file)); } return results.AsReadOnly(); } private static void MoveMatchDirectory(string searchPatternB, ReadOnlyDictionary keyValuePairs, string sourceDirectory) { string checkFile; string fileNameWithoutExtension; string[] files = Directory.GetFiles(sourceDirectory, searchPatternB, SearchOption.AllDirectories); foreach (string file in files) { fileNameWithoutExtension = Path.GetFileNameWithoutExtension(file); if (!keyValuePairs.TryGetValue(fileNameWithoutExtension, out string? match)) continue; checkFile = Path.Combine(match, Path.GetFileName(file)); if (File.Exists(checkFile)) continue; File.Move(file, checkFile); } } private static ReadOnlyCollection GetRecords(string searchPatternB, string sourceDirectory, int dateLineSegmentCount, string datePattern, string columns) { List results = []; string line; string[] lines; RecordB? record; LineCheck lineCheck; string[] files = Directory.GetFiles(sourceDirectory, searchPatternB, SearchOption.AllDirectories); foreach (string file in files) { lines = File.ReadAllLines(file); for (int i = 0; i < lines.Length; i++) { line = lines[i]; if (string.IsNullOrEmpty(line)) { continue; } lineCheck = LineCheck.Get(dateLineSegmentCount, datePattern, line); if (lineCheck.EffectiveDate == DateTime.MinValue || lineCheck.TransactionDate == DateTime.MinValue) { continue; } else { record = GetRecord(dateLineSegmentCount, datePattern, lines, i, lineCheck.Segments, lineCheck.TransactionDate, lineCheck.EffectiveDate); if (record is not null) { i = record.I; results.Add(record); } } } } return results.AsReadOnly(); } private static RecordB? GetRecord(int dateLineSegmentCount, string datePattern, string[] lines, int i, string[] segments, DateTime transactionDate, DateTime effectiveDate) { RecordB? result = null; string line; RecordB record; LineCheck lineCheck; List collection = []; for (int j = i + 1; j < lines.Length; j++) { line = lines[j]; if (string.IsNullOrEmpty(line)) { continue; } lineCheck = LineCheck.Get(dateLineSegmentCount, datePattern, line); if (lineCheck.EffectiveDate == DateTime.MinValue || lineCheck.TransactionDate == DateTime.MinValue) { collection.Add(line); } else { if (lineCheck.Segments.Length > dateLineSegmentCount) { collection.Insert(0, string.Join(' ', lineCheck.Segments.Skip(2))); } result = GetRecord(transactionDate, effectiveDate, collection.AsReadOnly(), j - 1); break; } } if (result is null && collection.Count > 0) { result = GetRecord(transactionDate, effectiveDate, collection.AsReadOnly(), lines.Length - 1); } return result; } private static RecordB GetRecord(DateTime transactionDate, DateTime effectiveDate, ReadOnlyCollection collection, int i) { RecordB? result; List verified = []; foreach (string check in collection) { if (Number().Replace(check, string.Empty).Length != 0) { verified.Clear(); } else { verified.Add(check); } if (verified.Count == 2) { break; } } if (verified.Count != 2) { result = null; } else { decimal balance = decimal.Parse(verified[^1]); decimal withdrawalOrDeposit = decimal.Parse(verified[^2]); string description = ASCII().Replace(string.Join(' ', collection.SkipLast(2)), string.Empty); result = new(I: i, TransactionDate: transactionDate, EffectiveDate: effectiveDate, Description: description, WithdrawalOrDeposit: withdrawalOrDeposit, Balance: balance); } return result; } private static void WriteRecords(string sourceDirectory, ReadOnlyCollection records) { string json = JsonSerializer.Serialize(records.ToArray(), Helper20250521RecordB.Default.RecordBArray); string sourceDirectoryVsCode = Path.Combine(sourceDirectory, ".vscode"); if (!Directory.Exists(sourceDirectoryVsCode)) _ = Directory.CreateDirectory(sourceDirectoryVsCode); File.WriteAllText(Path.Combine(sourceDirectoryVsCode, $"{DateTime.Now.Ticks}.json"), json); } }