import { circuitGroupCategoryNumbers, type CircuitGroupCategory, } from "../../shared/constants/circuit-group.js"; export type GroupedEquipmentIdentifierKind = | "group_upstream_protection" | "group_rcd" | "circuit"; export interface ParsedGroupedEquipmentIdentifier { category: CircuitGroupCategory; groupNumber: number; kind: GroupedEquipmentIdentifierKind; circuitNumber: number | null; } const categoryByNumber: Record = { "1": "lighting", "2": "single_phase", "3": "three_phase", }; function requirePositiveInteger(value: number, fieldName: string): void { if (!Number.isInteger(value) || value < 1) { throw new RangeError(`${fieldName} must be a positive integer`); } } function getGroupStem( category: CircuitGroupCategory, functionLetter: "F" | "Q", groupNumber: number ): string { requirePositiveInteger(groupNumber, "groupNumber"); return `-${circuitGroupCategoryNumbers[category]}${functionLetter}${groupNumber}`; } export function formatCircuitGroupPrefix( category: CircuitGroupCategory, groupNumber: number ) { return `${getGroupStem(category, "F", groupNumber)}.`; } export function formatGroupUpstreamProtectionIdentifier( category: CircuitGroupCategory, groupNumber: number ): string { return `${getGroupStem(category, "F", groupNumber)}.0`; } export function formatGroupRcdIdentifier( category: CircuitGroupCategory, groupNumber: number ): string { return `${getGroupStem(category, "Q", groupNumber)}.0`; } export function formatGroupedCircuitIdentifier( category: CircuitGroupCategory, groupNumber: number, circuitNumber: number ): string { requirePositiveInteger(circuitNumber, "circuitNumber"); return `${getGroupStem(category, "F", groupNumber)}.${circuitNumber}`; } export function parseGroupedEquipmentIdentifier( equipmentIdentifier: string ): ParsedGroupedEquipmentIdentifier | null { const match = /^-(1|2|3)(F|Q)([1-9]\d*)\.(0|[1-9]\d*)$/.exec( equipmentIdentifier ); if (!match) { return null; } const [, categoryNumber, functionLetter, groupNumberValue, suffixValue] = match; const category = categoryByNumber[categoryNumber]; const groupNumber = Number(groupNumberValue); const suffix = Number(suffixValue); if (functionLetter === "Q") { return suffix === 0 ? { category, groupNumber, kind: "group_rcd", circuitNumber: null, } : null; } if (suffix === 0) { return { category, groupNumber, kind: "group_upstream_protection", circuitNumber: null, }; } return { category, groupNumber, kind: "circuit", circuitNumber: suffix, }; } export function getNextGroupedCircuitNumber( category: CircuitGroupCategory, groupNumber: number, equipmentIdentifiers: Iterable ): number { requirePositiveInteger(groupNumber, "groupNumber"); let highestCircuitNumber = 0; for (const equipmentIdentifier of equipmentIdentifiers) { const parsed = parseGroupedEquipmentIdentifier(equipmentIdentifier); if ( parsed?.kind === "circuit" && parsed.category === category && parsed.groupNumber === groupNumber && parsed.circuitNumber !== null ) { highestCircuitNumber = Math.max( highestCircuitNumber, parsed.circuitNumber ); } } return highestCircuitNumber + 1; } export function getNextGroupedCircuitIdentifier( category: CircuitGroupCategory, groupNumber: number, equipmentIdentifiers: Iterable ): string { return formatGroupedCircuitIdentifier( category, groupNumber, getNextGroupedCircuitNumber( category, groupNumber, equipmentIdentifiers ) ); } export function getNextCircuitGroupNumber( category: CircuitGroupCategory, groups: Iterable<{ category: CircuitGroupCategory; groupNumber: number; }> ): number { let highestGroupNumber = 0; for (const group of groups) { if (group.category === category) { requirePositiveInteger(group.groupNumber, "groupNumber"); highestGroupNumber = Math.max(highestGroupNumber, group.groupNumber); } } return highestGroupNumber + 1; }