gc-wing/apps/web/src/entities/legacyVessel/lib/index.ts
2026-02-15 11:22:38 +09:00

76 lines
2.0 KiB
TypeScript

import { normalizeShipName } from "./normalizeShipName";
import type { LegacyVesselInfo } from "../model/types";
export type LegacyVesselIndex = {
byName: Map<string, LegacyVesselInfo>;
byMmsi: Map<number, LegacyVesselInfo>;
};
function score(v: LegacyVesselInfo) {
// Prefer records that were merged from more sources.
return Number(!!v.sources.permittedList) + Number(!!v.sources.checklist) + Number(!!v.sources.fleet906);
}
export function buildLegacyVesselIndex(vessels: LegacyVesselInfo[]): LegacyVesselIndex {
const byName = new Map<string, LegacyVesselInfo>();
const byMmsi = new Map<number, LegacyVesselInfo>();
for (const v of vessels) {
const keys = new Set<string>();
if (v.shipNameRoman) keys.add(normalizeShipName(v.shipNameRoman));
if (v.shipNameCn) keys.add(normalizeShipName(v.shipNameCn));
if (v.callSign) keys.add(normalizeShipName(v.callSign));
for (const k of keys) {
if (!k) continue;
const prev = byName.get(k);
if (!prev) {
byName.set(k, v);
continue;
}
if (score(v) > score(prev)) byName.set(k, v);
}
for (const m of v.mmsiList || []) {
if (!Number.isFinite(m)) continue;
const prev = byMmsi.get(m);
if (!prev) {
byMmsi.set(m, v);
continue;
}
if (score(v) > score(prev)) byMmsi.set(m, v);
}
}
return { byName, byMmsi };
}
export type LegacyMatchable = {
mmsi?: number;
name?: string;
callsign?: string;
};
export function matchLegacyVessel(t: LegacyMatchable, idx: LegacyVesselIndex): LegacyVesselInfo | null {
const mmsi = t.mmsi;
if (typeof mmsi === "number") {
const hit = idx.byMmsi.get(mmsi);
if (hit) return hit;
}
const nameKey = t.name ? normalizeShipName(t.name) : "";
if (nameKey) {
const hit = idx.byName.get(nameKey);
if (hit) return hit;
}
const csKey = t.callsign ? normalizeShipName(t.callsign) : "";
if (csKey) {
const hit = idx.byName.get(csKey);
if (hit) return hit;
}
return null;
}