using System; using System.Collections.Generic; using System.Globalization; using System.Text.RegularExpressions; namespace AxCopilot.Handlers; internal static class UnitConverter { private static readonly Regex Pattern = new Regex("^(-?\\d+(?:\\.\\d+)?)\\s*([a-z°/²³µ]+)\\s+(?:in|to)\\s+([a-z°/²³µ]+)$", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Dictionary _length = new Dictionary { ["km"] = 1000.0, ["m"] = 1.0, ["cm"] = 0.01, ["mm"] = 0.001, ["mi"] = 1609.344, ["mile"] = 1609.344, ["miles"] = 1609.344, ["ft"] = 0.3048, ["feet"] = 0.3048, ["foot"] = 0.3048, ["in"] = 0.0254, ["inch"] = 0.0254, ["inches"] = 0.0254, ["yd"] = 0.9144, ["yard"] = 0.9144, ["yards"] = 0.9144, ["nm"] = 1E-09 }; private static readonly Dictionary _weight = new Dictionary { ["t"] = 1000.0, ["ton"] = 1000.0, ["tonnes"] = 1000.0, ["kg"] = 1.0, ["g"] = 0.001, ["mg"] = 1E-06, ["lb"] = 0.453592, ["lbs"] = 0.453592, ["pound"] = 0.453592, ["pounds"] = 0.453592, ["oz"] = 0.0283495, ["ounce"] = 0.0283495, ["ounces"] = 0.0283495 }; private static readonly Dictionary _speed = new Dictionary { ["m/s"] = 1.0, ["mps"] = 1.0, ["km/h"] = 5.0 / 18.0, ["kmh"] = 5.0 / 18.0, ["kph"] = 5.0 / 18.0, ["mph"] = 0.44704, ["kn"] = 0.514444, ["knot"] = 0.514444, ["knots"] = 0.514444 }; private static readonly Dictionary _data = new Dictionary { ["b"] = 1.0, ["byte"] = 1.0, ["bytes"] = 1.0, ["kb"] = 1024.0, ["kib"] = 1024.0, ["mb"] = 1048576.0, ["mib"] = 1048576.0, ["gb"] = 1073741824.0, ["gib"] = 1073741824.0, ["tb"] = 1099511627776.0, ["tib"] = 1099511627776.0, ["pb"] = 1125899906842624.0 }; private static readonly Dictionary _area = new Dictionary { ["m²"] = 1.0, ["m2"] = 1.0, ["km²"] = 1000000.0, ["km2"] = 1000000.0, ["cm²"] = 0.0001, ["cm2"] = 0.0001, ["ha"] = 10000.0, ["acre"] = 4046.86, ["acres"] = 4046.86, ["ft²"] = 0.092903, ["ft2"] = 0.092903 }; private static readonly List> _tables = new List> { _length, _weight, _speed, _data, _area }; public static bool TryConvert(string input, out string? result) { result = null; Match match = Pattern.Match(input.Trim()); if (!match.Success) { return false; } if (!double.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result2)) { return false; } string text = match.Groups[2].Value.ToLowerInvariant(); string text2 = match.Groups[3].Value.ToLowerInvariant(); if (TryConvertTemperature(result2, text, text2, out var r)) { result = FormatNum(r) + " " + TemperatureLabel(text2); return true; } foreach (Dictionary table in _tables) { if (table.TryGetValue(text, out var value) && table.TryGetValue(text2, out var value2)) { double v = result2 * value / value2; result = FormatNum(v) + " " + text2; return true; } } return false; } private static bool TryConvertTemperature(double v, string from, string to, out double r) { r = 0.0; double num; switch (from) { case "c": case "°c": case "celsius": num = v; break; case "f": case "°f": case "fahrenheit": num = (v - 32.0) * 5.0 / 9.0; break; case "k": case "kelvin": num = v - 273.15; break; default: return false; } switch (to) { case "c": case "°c": case "celsius": r = num; break; case "f": case "°f": case "fahrenheit": r = num * 9.0 / 5.0 + 32.0; break; case "k": case "kelvin": r = num + 273.15; break; default: return false; } return true; } private static string TemperatureLabel(string unit) { if (1 == 0) { } string result; switch (unit) { case "c": case "°c": case "celsius": result = "°C"; break; case "f": case "°f": case "fahrenheit": result = "°F"; break; case "k": case "kelvin": result = "K"; break; default: result = unit; break; } if (1 == 0) { } return result; } private static string FormatNum(double v) { if (v == Math.Floor(v) && Math.Abs(v) < 1000000000000.0) { return ((long)v).ToString("N0", CultureInfo.CurrentCulture); } return v.ToString("G6", CultureInfo.InvariantCulture); } }