diff --git a/Conversion/Converter.cs b/Conversion/Converter.cs index cacf43b..220e577 100644 --- a/Conversion/Converter.cs +++ b/Conversion/Converter.cs @@ -16,24 +16,36 @@ namespace vassago.Conversion { public static class Converter { - public static string DebugInfo(){ - var convertibles = knownConversions.Select(kc => kc.Item1).Union(knownConversions.Select(kc => kc.Item2)).Union( - knownAliases.Keys.SelectMany(k => k)).Distinct(); - return $"{convertibles.Count()} convertibles; {string.Join(", ", convertibles)}"; - } private delegate decimal Convert1Way(decimal input); private static string currencyPath; private static ExchangePairs currencyConf = null; private static DateTime lastUpdatedCurrency = DateTime.UnixEpoch; - private static List> knownConversions = new List>() - { - new Tuple("℉", "°C", (f => {return(f- 32.0m) / 1.8m;}), (c => {return 1.8m*c + 32.0m;})), - }; + private static List> knownConversions = new List>(); private static Dictionary, string> knownAliases = new Dictionary, string>(new List, string>>()); + public static string DebugInfo() + { + var convertibles = knownConversions.Select(kc => kc.Item1).Union(knownConversions.Select(kc => kc.Item2)).Union( + knownAliases.Keys.SelectMany(k => k)).Distinct(); + return $"{convertibles.Count()} convertibles; {string.Join(", ", convertibles)}"; + } public static void Load(string currencyPath) { Converter.currencyPath = currencyPath; + loadStatic(); + Task.Run(async () => + { + while (true) + { + await Task.Delay(TimeSpan.FromHours(8)); + loadCurrency(); + } + }); + } + private static void loadStatic() + { + knownConversions = new List>(); + knownAliases = new Dictionary, string>(new List, string>>()); var convConf = JsonConvert.DeserializeObject(File.ReadAllText("assets/conversion.json")); foreach (var unit in convConf.Units) { @@ -43,18 +55,12 @@ namespace vassago.Conversion { AddLinearPair(lp.item1, lp.item2, lp.factor); } - Task.Run(async () => { - while(true) - { - loadCurrency(); - await Task.Delay(TimeSpan.FromHours(8)); - } - }); + loadCurrency(); } private static void loadCurrency() { Console.WriteLine("loading currency exchange data."); - if(currencyConf != null) + if (currencyConf != null) { knownConversions.RemoveAll(kc => kc.Item1 == currencyConf.Base); } @@ -62,38 +68,41 @@ namespace vassago.Conversion { currencyConf = JsonConvert.DeserializeObject(File.ReadAllText(currencyPath)); - if(!knownAliases.ContainsValue(currencyConf.Base)) + if (!knownAliases.ContainsValue(currencyConf.Base)) { knownAliases.Add(new List() { currencyConf.Base.ToLower() }, currencyConf.Base); } foreach (var rate in currencyConf.rates) { - if(!knownAliases.ContainsValue(rate.Key)) + if (!knownAliases.ContainsValue(rate.Key)) { knownAliases.Add(new List() { rate.Key.ToLower() }, rate.Key); } AddLinearPair(currencyConf.Base, rate.Key, rate.Value); - Console.WriteLine($"{rate.Key.ToLower()} alias of {rate.Key}"); } } } public static string Convert(decimal numericTerm, string sourceunit, string destinationUnit) { - var normalizedSourceUnit = NormalizeUnit(sourceunit); - if (string.IsNullOrWhiteSpace(normalizedSourceUnit)) + var normalizationAttempt = NormalizeUnit(sourceunit); + if (normalizationAttempt.Item2 != null) { - return $"parse failure: what's {sourceunit}?"; + return $"problem with {sourceunit}: {normalizationAttempt.Item2}"; } - var normalizedDestUnit = NormalizeUnit(destinationUnit); - if (string.IsNullOrWhiteSpace(normalizedDestUnit)) + var normalizedSourceUnit = normalizationAttempt.Item1; + + normalizationAttempt = NormalizeUnit(destinationUnit); + if (normalizationAttempt.Item2 != null) { - return $"parse failure: what's {destinationUnit}?"; + return $"problem with {destinationUnit}: {normalizationAttempt.Item2}"; } + var normalizedDestUnit = normalizationAttempt.Item1; if (normalizedSourceUnit == normalizedDestUnit) { return $"source and dest are the same, so... {numericTerm} {normalizedDestUnit}?"; } + var foundPath = exhaustiveBreadthFirst(normalizedDestUnit, new List() { normalizedSourceUnit })?.ToList(); if (foundPath != null) @@ -118,7 +127,7 @@ namespace vassago.Conversion } else { - if(String.Format("{0:G3}", accumulator).Contains("E-")) + if (String.Format("{0:G3}", accumulator).Contains("E-")) { return $"{accumulator} {normalizedDestUnit}"; } @@ -130,21 +139,34 @@ namespace vassago.Conversion } return "dimensional analysis failure - I know those units but can't find a path between them."; } - private static string NormalizeUnit(string unit) + private static Tuple NormalizeUnit(string unit) { - if(string.IsNullOrWhiteSpace(unit)) - return null; + if (string.IsNullOrWhiteSpace(unit)) + return new(null, "no unit provided"); var normalizedUnit = unit.ToLower(); if (knownConversions.FirstOrDefault(c => c.Item1 == normalizedUnit || c.Item2 == normalizedUnit) != null) { - return normalizedUnit; + return new(normalizedUnit, null); } + //if "unit" isn't a canonical name... if (!knownAliases.ContainsValue(normalizedUnit)) { - var key = knownAliases.Keys.FirstOrDefault(listkey => listkey.Contains(normalizedUnit)); - if (key != null) + //then we look through aliases... + var keys = knownAliases.Keys.Where(listkey => listkey.Contains(normalizedUnit)); + if (keys?.Count() > 1) { - return knownAliases[key]; + var sb = new StringBuilder(); + sb.Append($"{normalizedUnit} could refer to any of"); + foreach (var key in keys) + { + sb.Append($" {knownAliases[key]}"); + } + return new(null, sb.ToString()); + } + else if (keys.Count() == 1) + { + //for the canonical name. + return new(knownAliases[keys.First()], null); } } if (normalizedUnit.EndsWith("es")) @@ -155,7 +177,7 @@ namespace vassago.Conversion { return NormalizeUnit(normalizedUnit.Substring(0, normalizedUnit.Length - 1)); } - return null; + return new(null, "couldn't find unit"); } private static IEnumerable exhaustiveBreadthFirst(string dest, IEnumerable currentPath) { @@ -170,9 +192,9 @@ namespace vassago.Conversion { if (conv.Item1 == last && currentPath.Contains(conv.Item2) == false && conv.Item3 != null) { - var test = exhaustiveBreadthFirst(dest, currentPath.Append(conv.Item2)); - if (test != null) - return test; + var test = exhaustiveBreadthFirst(dest, currentPath.Append(conv.Item2)); + if (test != null) + return test; } if (conv.Item2 == last && currentPath.Contains(conv.Item1) == false && conv.Item4 != null) { @@ -191,4 +213,4 @@ namespace vassago.Conversion )); } } -} \ No newline at end of file +} diff --git a/assets/conversion.json b/assets/conversion.json index 043a238..8eea90b 100644 --- a/assets/conversion.json +++ b/assets/conversion.json @@ -245,6 +245,21 @@ "aliases":[ "uj" ] + }, + { + "canonical":"USD", + "aliases":[ + "american dollars", + "dollar" + ] + }, + { + "canonical": "CAD", + "aliases": [ + "canadian dollars", + "dollar", + "maple syrup money" + ] } ], "linearPairs":[ @@ -304,4 +319,4 @@ {"item1":"atm", "item2":"Pa", "factor":101325}, {"item1":"bar", "item2":"psi", "factor":14.5038} ] -} \ No newline at end of file +}