import 'package:d4rt/d4rt.dart'; import 'package:collection/collection.dart'; import 'package:d4rt_formulas/d4rt_formulas.dart'; class Multimap extends DelegatingMap> { final Map> _map; Multimap(super.map) : _map = map; factory Multimap.create() { return Multimap({}); } @override List? operator [](Object? key) { if (_map.containsKey(key)) { return super[key]; } final List newList = []; super[key as K] = newList; return super[key]; } } class Corpus{ final Multimap _tags = Multimap.create(); final Map _allFormulas = {}; void loadFormulas(List formulas, {bool replaceOnDuplicates = false, bool checkUnits = true}) { for (final formula in formulas) { if (!replaceOnDuplicates && _allFormulas.containsKey(formula.name)) { throw ArgumentError("Duplicate formula:$formula"); } if( checkUnits ){ for( final inputVar in formula.input + [formula.output] ){ if( getUnit(inputVar.unit) == null ){ throw ArgumentError( "Unit not found: ${inputVar.unit}"); } } } _allFormulas[formula.name] = formula; for( final tag in formula.tags ){ _tags[tag]?.add(formula); } } } List getTagFormulas(String tag){ if( _tags[tag] == null ){ return []; } return _tags[tag]?.toList(growable:false) as List; } final Multimap _baseToUnits = Multimap.create(); final Map _allUnits = {}; void loadUnits(List units, [bool replaceOnDuplicates = false]) { for (final unit in units) { if (!replaceOnDuplicates && _allUnits.containsKey(unit.name)) { throw ArgumentError("Duplicate unit:$unit"); } _allUnits[unit.name] = unit; _baseToUnits[unit.baseUnit]?.add(unit.name); } } List unitsOfSameMagnitude(String unit){ final base = getUnit(unit).baseUnit; return _baseToUnits[base] as List; } UnitSpec getUnit(String unit) { if (!_allUnits.containsKey(unit)) { throw ArgumentError("Unit not found:$unit"); } return _allUnits.get(unit); } String _converterFromCodeString(Number x, String codeString) { final buffer = StringBuffer(); buffer.writeln("final x = ${x};"); buffer.writeln("main(){return $codeString;}"); final code = buffer.toString(); return code; } Number _convertToBase(Number x, String fromUnit) { final unit = getUnit(fromUnit); if (unit.factorFromUnitToBase != null) { return x * (unit.factorFromUnitToBase as Number); } if (unit.codeFromUnitToBase == null) { throw ArgumentError("Unit has no codeFromUnitToBase: $unit"); } final d4rt = D4rt(); final completeSource = _converterFromCodeString(x, unit.codeFromUnitToBase as String); final ret = d4rt.execute(source: completeSource); return ret as Number; } Number _convertFromBase(Number x, String toUnit) { final unit = getUnit(toUnit); if (unit.factorFromUnitToBase != null) { return x / (unit.factorFromUnitToBase as Number); } if (unit.codeFromBaseToUnit == null) { throw ArgumentError("Unit has no codeFromBaseToUnit: $unit"); } final d4rt = D4rt(); final completeSource = _converterFromCodeString(x, unit.codeFromBaseToUnit as String); final ret = d4rt.execute(source: completeSource); return ret as Number; } Number convert(Number x, String fromUnit, String toUnit) { final xBase = _convertToBase(x, fromUnit); final xTo = _convertFromBase(xBase, toUnit); return xTo; } Iterable allUnits() => _allUnits.values; }