using System; using System.IO; using System.Collections.Generic; using System.Diagnostics; using System.Text.RegularExpressions; using DesertPaintCodex.Models; using DesertPaintCodex.Util; namespace DesertPaintCodex.Services { internal static class ReagentService { // PP format private static readonly Regex _reagentRegex = new(@"(?\w+)\s*\|\s*(?\d+),\s*(?\d+),\s*(?\d+)\s*\|\s*(?\d+)\s*\|\s*(?[YN])\s*\|\s*(?(bulk|normal))\s*\|\s*(?\d+).*"); private static readonly Regex _catalystRegex = new(@"(?\w+)\s*\|\s*catalyst\s*\|\s*(?\d+)\s*\|\s*(?[YN])\s*\|\s*(?(bulk|normal)).*"); private static readonly Regex _internalReagentRegex = new(@"(?(\w*\s)*\w+)\s*\|\s*(?\w+)\s*\|\s*(?\d+),\s*(?\d+),\s*(?\d+).*"); private static readonly Regex _internalCatalystRegex = new(@"(?(\w+\s)*\w+)\s*\|\s*(?\w+)\s*\|\s*catalyst.*"); private static readonly Dictionary _reagents = new(); private static readonly Dictionary _nameLookup = new(); // pp name to our name private static string _lastReagentsFile = string.Empty; private static bool _initialized = false; public static List Names { get; } = new(); public static void Initialize() { if (_initialized) return; string? reagentsPath = FileUtils.FindApplicationResourceFile("ingredients.txt"); Debug.Assert(reagentsPath != null); Load(reagentsPath); } // Loads reagent name/colors public static void Load(string file) { if (_lastReagentsFile == file) return; _lastReagentsFile = file; _reagents.Clear(); _nameLookup.Clear(); Names.Clear(); using StreamReader reader = new(file); string? line; while ((line = reader.ReadLine()) != null) { Match match = _internalReagentRegex.Match(line); if (match.Success) { string name = match.Groups["name"].Value; string ppname = match.Groups["ppname"].Value; _reagents.Add(name, new Reagent(name, ppname, byte.Parse(match.Groups["red"].Value), byte.Parse(match.Groups["green"].Value), byte.Parse(match.Groups["blue"].Value))); // nameStore.AppendValues(name); Names.Add(name); _nameLookup.Add(ppname, name); } else { match = _internalCatalystRegex.Match(line); if (!match.Success) continue; string name = match.Groups["name"].Value; string ppname = match.Groups["ppname"].Value; _reagents.Add(name, new Reagent(ppname, ppname)); // nameStore.AppendValues(name); Names.Add(name); _nameLookup.Add(ppname, name); } } } public static void LoadProfileReagents(string file) { Initialize(); using StreamReader reader = new(file); string? line; while ((line = reader.ReadLine()) != null) { Match match = _reagentRegex.Match(line); if (match.Success) { string ppname = match.Groups["name"].Value; if (_nameLookup.TryGetValue(ppname, out string? name)) { Reagent reagent = GetReagent(name); if (reagent.IsCatalyst) continue; reagent.Enabled = match.Groups["enabled"].Value.Equals("Y"); reagent.Cost = uint.Parse(match.Groups["cost"].Value); reagent.RecipeMax = uint.Parse(match.Groups["max"].Value); } else { // bad name? } } else { match = _catalystRegex.Match(line); if (!match.Success) continue; string ppname = match.Groups["name"].Value; if (_nameLookup.TryGetValue(ppname, out string? name)) { Reagent reagent = GetReagent(name); if (reagent is not {IsCatalyst: true}) continue; reagent.Enabled = match.Groups["enabled"].Value.Equals("Y"); reagent.Cost = uint.Parse(match.Groups["cost"].Value); } else { // bad name? } } } } public static void SaveProfileReagents(string file) { Initialize(); using StreamWriter writer = new(file); writer.WriteLine("// Ingredients are in the form:"); writer.WriteLine("// Name | RGB values | cost | enabled (Y/N) | bulk/normal | max items per paint (1-20)"); writer.WriteLine("//"); writer.WriteLine("// It is recommended to only change the cost value"); writer.WriteLine("// It is not recommended to set many of the ingredients above 10 per paint"); List sortedReagents = new(_reagents.Count); sortedReagents.AddRange(_reagents.Values); sortedReagents.Sort((x, y) => ((x.IsCatalyst && !y.IsCatalyst) ? 1 : ((y.IsCatalyst && !x.IsCatalyst) ? -1 : string.Compare(x.PracticalPaintName, y.PracticalPaintName, StringComparison.InvariantCulture)))); foreach (Reagent reagent in sortedReagents) { if (!reagent.IsCatalyst) { writer.WriteLine("{0,-10} | {1,3}, {2,3}, {3,3} | {4,7} | {5} | {6} | {7}", reagent.PracticalPaintName, reagent.Color?.Red, reagent.Color?.Blue, reagent.Color?.Green, reagent.Cost, reagent.Enabled ? "Y" : "N", reagent.RecipeMax >= 10 ? " bulk" : "normal", reagent.RecipeMax); } else { writer.WriteLine("{0,-10} | catalyst | {1,7} | {2} | normal | 1", reagent.PracticalPaintName, reagent.Cost, reagent.Enabled ? "Y" : "N"); } } } public static void InitializeReactions(ReactionSet reactions) { Initialize(); foreach (KeyValuePair pair1 in _reagents) { foreach (KeyValuePair pair2 in _reagents) { if (pair1.Key != pair2.Key) { reactions.Set(pair1.Value, pair2.Value, null); } } } } public static Reagent GetReagent(string reagentName) { Initialize(); if (_reagents.TryGetValue(reagentName, out Reagent? returnVal)) return returnVal; // convert pp name to our internal name if (_nameLookup.TryGetValue(reagentName, out string? otherName)) { _reagents.TryGetValue(otherName, out returnVal); } Debug.Assert(returnVal != null); return returnVal; } } }