uto_manager/lib/domain/services/template_instantiator.dart

122 lines
3.8 KiB
Dart

import 'package:uto_manager/domain/entities/authorized_rank.dart';
import 'package:uto_manager/domain/entities/doctrinal_branch.dart';
import 'package:uto_manager/domain/entities/echelon.dart';
import 'package:uto_manager/domain/entities/position_slot.dart';
import 'package:uto_manager/domain/entities/unit_node.dart';
import 'package:uto_manager/domain/value_objects/duty_mos.dart';
// ---------------------------------------------------------------------------
// Template definition model
// ---------------------------------------------------------------------------
/// Defines a position slot within a template unit definition.
class SlotDefinition {
const SlotDefinition({
required this.positionTitle,
required this.dutyMos,
required this.authorizedRank,
this.isKeyLeader = false,
});
final String positionTitle;
final String dutyMos;
final String authorizedRank;
final bool isKeyLeader;
}
/// Defines a unit node within a template, including its slots and children.
class UnitDefinition {
const UnitDefinition({
required this.name,
required this.echelon,
required this.branch,
this.isKeyLeader = false,
this.slots = const [],
this.children = const [],
});
final String name;
final String echelon;
final String branch;
final bool isKeyLeader;
final List<SlotDefinition> slots;
final List<UnitDefinition> children;
}
// ---------------------------------------------------------------------------
// Instantiation result
// ---------------------------------------------------------------------------
/// The result of instantiating a doctrinal template.
class InstantiationResult {
const InstantiationResult({
required this.units,
required this.slots,
});
/// All [UnitNode]s in the instantiated tree (flat list, ordered parent-first).
final List<UnitNode> units;
/// All [PositionSlot]s in the instantiated tree.
final List<PositionSlot> slots;
}
// ---------------------------------------------------------------------------
// Service
// ---------------------------------------------------------------------------
/// Converts a [UnitDefinition] tree into concrete [UnitNode] and
/// [PositionSlot] domain objects with generated UUIDs.
///
/// This service is pure domain logic with no infrastructure dependencies.
/// The caller is responsible for persisting the result to the database.
class TemplateInstantiator {
const TemplateInstantiator({required this.idGenerator});
/// Function that generates a unique ID string (e.g., UUID v4).
final String Function() idGenerator;
/// Instantiates [definition] as a root unit (no parent).
InstantiationResult instantiate(UnitDefinition definition) {
final units = <UnitNode>[];
final slots = <PositionSlot>[];
_walk(definition, null, units, slots);
return InstantiationResult(units: units, slots: slots);
}
void _walk(
UnitDefinition def,
String? parentUnitId,
List<UnitNode> units,
List<PositionSlot> slots,
) {
final unitId = idGenerator();
final unit = UnitNode(
unitId: unitId,
echelon: Echelon.values.firstWhere((e) => e.name == def.echelon),
branch: DoctrinalBranch.values.firstWhere((b) => b.name == def.branch),
parentUnitId: parentUnitId,
name: def.name,
isKeyLeader: def.isKeyLeader,
);
units.add(unit);
for (final slotDef in def.slots) {
final slot = PositionSlot(
slotId: idGenerator(),
unitId: unitId,
positionTitle: slotDef.positionTitle,
dutyMos: DutyMos.unvalidated(slotDef.dutyMos),
authorizedRank: AuthorizedRank.values.firstWhere((r) => r.name == slotDef.authorizedRank),
isKeyLeader: slotDef.isKeyLeader,
);
slots.add(slot);
}
for (final child in def.children) {
_walk(child, unitId, units, slots);
}
}
}