import 'package:abawo_bt_app/model/gear_ratio_codec.dart'; enum GearRetentionMode { keepHighest, keepAll } class GearConfiguratorCalculation { const GearConfiguratorCalculation({ required this.ratios, required this.discardedBelowRange, required this.discardedAboveRange, required this.duplicateCount, required this.truncatedCount, }); final List ratios; final int discardedBelowRange; final int discardedAboveRange; final int duplicateCount; final int truncatedCount; } GearConfiguratorCalculation calculateGearRatios({ required List chainrings, required List sprockets, required GearRetentionMode mode, int maxRatios = 32, }) { final sortedChainrings = List.from(chainrings)..sort(); final sortedSprockets = List.from(sprockets)..sort((a, b) => b - a); var discardedBelowRange = 0; var discardedAboveRange = 0; var duplicateCount = 0; final encoded = {}; final ratios = []; void addRatio(double ratio) { if (ratio < gearRatioMin) { discardedBelowRange++; return; } if (ratio > gearRatioMax) { discardedAboveRange++; return; } final raw = encodeGearRatioByte(ratio); if (!encoded.add(raw)) { duplicateCount++; return; } ratios.add(decodeGearRatioByte(raw)); } switch (mode) { case GearRetentionMode.keepAll: for (final chainring in sortedChainrings) { for (final sprocket in sortedSprockets) { addRatio(chainring / sprocket); } } break; case GearRetentionMode.keepHighest: var threshold = double.negativeInfinity; for (final chainring in sortedChainrings) { final beforeLength = ratios.length; for (final sprocket in sortedSprockets) { final ratio = chainring / sprocket; if (ratio >= threshold) { addRatio(ratio); } } if (ratios.length > beforeLength) { threshold = ratios.reduce((a, b) => a > b ? a : b); } } break; } ratios.sort(); final truncatedCount = ratios.length > maxRatios ? ratios.length - maxRatios : 0; final limited = ratios.take(maxRatios).toList(growable: false); return GearConfiguratorCalculation( ratios: limited, discardedBelowRange: discardedBelowRange, discardedAboveRange: discardedAboveRange, duplicateCount: duplicateCount, truncatedCount: truncatedCount, ); }