import 'package:lbjconsole/models/train_record.dart'; import 'package:lbjconsole/models/merged_record.dart'; class MergeService { static String? _generateGroupKey(TrainRecord record, GroupBy groupBy) { final train = record.train.trim(); final loco = record.loco.trim(); final hasTrain = train.isNotEmpty && train != "" && !train.contains("-----"); final hasLoco = loco.isNotEmpty && loco != ""; switch (groupBy) { case GroupBy.trainOnly: return hasTrain ? train : null; case GroupBy.locoOnly: return hasLoco ? loco : null; case GroupBy.trainOrLoco: if (hasTrain && hasLoco) { return "train:$train|loco:$loco"; } else if (hasTrain) { return "train:$train"; } else if (hasLoco) { return "loco:$loco"; } return null; case GroupBy.trainAndLoco: return (hasTrain && hasLoco) ? "${train}_$loco" : null; } } static List getMixedList( List allRecords, MergeSettings settings) { if (!settings.enabled) { allRecords .sort((a, b) => b.receivedTimestamp.compareTo(a.receivedTimestamp)); return allRecords; } final now = DateTime.now(); final validRecords = settings.timeWindow.duration == null ? allRecords : allRecords .where((r) => now.difference(r.receivedTimestamp) <= settings.timeWindow.duration!) .toList(); validRecords .sort((a, b) => b.receivedTimestamp.compareTo(a.receivedTimestamp)); if (settings.groupBy == GroupBy.trainOrLoco) { return _groupByTrainOrLoco(validRecords); } final groupedRecords = >{}; for (final record in validRecords) { final key = _generateGroupKey(record, settings.groupBy); if (key != null) { groupedRecords.putIfAbsent(key, () => []).add(record); } } final List mergedRecords = []; final Set mergedRecordIds = {}; groupedRecords.forEach((key, group) { if (group.length >= 2) { mergedRecords.add(MergedTrainRecord( groupKey: key, records: group, latestRecord: group.first, )); for (final record in group) { mergedRecordIds.add(record.uniqueId); } } }); final singleRecords = validRecords .where((r) => !mergedRecordIds.contains(r.uniqueId)) .toList(); final List mixedList = [...mergedRecords, ...singleRecords]; mixedList.sort((a, b) { final aTime = a is MergedTrainRecord ? a.latestRecord.receivedTimestamp : (a as TrainRecord).receivedTimestamp; final bTime = b is MergedTrainRecord ? b.latestRecord.receivedTimestamp : (b as TrainRecord).receivedTimestamp; return bTime.compareTo(aTime); }); return mixedList; } static List _groupByTrainOrLoco(List records) { final List mergedRecords = []; final List singleRecords = []; final Set usedRecordIds = {}; for (int i = 0; i < records.length; i++) { final record = records[i]; if (usedRecordIds.contains(record.uniqueId)) continue; final group = [record]; for (int j = i + 1; j < records.length; j++) { final otherRecord = records[j]; if (usedRecordIds.contains(otherRecord.uniqueId)) continue; final recordTrain = record.train.trim(); final otherTrain = otherRecord.train.trim(); final recordLoco = record.loco.trim(); final otherLoco = otherRecord.loco.trim(); final trainMatch = recordTrain.isNotEmpty && recordTrain != "" && !recordTrain.contains("-----") && otherTrain.isNotEmpty && otherTrain != "" && !otherTrain.contains("-----") && recordTrain == otherTrain; final locoMatch = recordLoco.isNotEmpty && recordLoco != "" && otherLoco.isNotEmpty && otherLoco != "" && recordLoco == otherLoco; final bothTrainEmpty = (recordTrain.isEmpty || recordTrain == "" || recordTrain.contains("----")) && (otherTrain.isEmpty || otherTrain == "" || otherTrain.contains("----")); if (trainMatch || locoMatch || (bothTrainEmpty && locoMatch)) { group.add(otherRecord); } } if (group.length >= 2) { for (final record in group) { usedRecordIds.add(record.uniqueId); } final firstRecord = group.first; final train = firstRecord.train.trim(); final loco = firstRecord.loco.trim(); String uniqueGroupKey; if (train.isNotEmpty && train != "" && !train.contains("-----") && loco.isNotEmpty && loco != "") { uniqueGroupKey = "train_or_loco:${train}_$loco"; } else if (train.isNotEmpty && train != "" && !train.contains("-----")) { uniqueGroupKey = "train_or_loco:train:$train"; } else if (loco.isNotEmpty && loco != "") { uniqueGroupKey = "train_or_loco:loco:$loco"; } else { uniqueGroupKey = "train_or_loco:group_${mergedRecords.length}"; } mergedRecords.add(MergedTrainRecord( groupKey: uniqueGroupKey, records: group, latestRecord: group.first, )); } else { singleRecords.add(record); usedRecordIds.add(record.uniqueId); } } final List result = [...mergedRecords, ...singleRecords]; result.sort((a, b) { final aTime = a is MergedTrainRecord ? a.latestRecord.receivedTimestamp : (a as TrainRecord).receivedTimestamp; final bTime = b is MergedTrainRecord ? b.latestRecord.receivedTimestamp : (b as TrainRecord).receivedTimestamp; return bTime.compareTo(aTime); }); return result; } }