import { Injectable } from '@angular/core'; import { Family } from '../models/family'; import { MarriageRelation } from '../models/marriage-relation'; import { Kakocho } from '../models/kakocho'; import { FamilyUnit } from '../models/family-unit'; import { FamilyUnitNode } from '../models/family-unit-node'; export interface FamilyTreeNode { family: Family; kakocho?: Kakocho; isDeceased: boolean; spouses: FamilyTreeNode[]; children: FamilyTreeNode[]; parents: FamilyTreeNode[]; } @Injectable({ providedIn: 'root', }) export class FamilyTreeBuilderService { build( families: Family[], marriages: MarriageRelation[], kakocholist: Kakocho[] ): FamilyTreeNode[] { const nodeMap = new Map(); const kakochoMap = new Map( kakocholist.map(k => [k.familyId, k]) ); // ----------------------------- // ① ノード生成(ここで統合) // ----------------------------- families.forEach((family) => { const kakocho = kakochoMap.get(family.id); nodeMap.set(family.id, { family, kakocho, isDeceased: !!kakocho, parents: [], children: [], spouses: [], }); }); // ----------------------------- // ② 親子関係 // ----------------------------- families.forEach((family) => { const childNode = nodeMap.get(family.id); if (!childNode) return; if (family.fatherId) { const father = nodeMap.get(family.fatherId); if (father) { father.children.push(childNode); childNode.parents.push(father); } } if (family.motherId) { const mother = nodeMap.get(family.motherId); if (mother) { mother.children.push(childNode); childNode.parents.push(mother); } } }); // ----------------------------- // ③ 配偶者関係(current) // ----------------------------- marriages .filter(m => m.status === 'current') .forEach((m) => { const p1 = nodeMap.get(m.person1Id); const p2 = nodeMap.get(m.person2Id); if (!p1 || !p2) return; if (!p1.spouses.some(s => s.family.id === p2.family.id)) { p1.spouses.push(p2); } }); // ----------------------------- // ④ spouseIdフォールバック // ----------------------------- families.forEach((f) => { if (!f.spouseId) return; const a = nodeMap.get(f.id); const b = nodeMap.get(f.spouseId); if (!a || !b) return; if (!a.spouses.some(s => s.family.id === b.family.id)) { a.spouses.push(b); } }); return [...nodeMap.values()]; } // ----------------------------- // Roots // ----------------------------- getRoots(nodes: FamilyTreeNode[]): FamilyTreeNode[] { return nodes.filter(node => { if (node.parents.length > 0) return false; if (node.spouses.length > 0) { const spouseId = node.spouses[0].family.id; return node.family.id < spouseId; } return true; }); } buildFamilyUnits( nodes: FamilyTreeNode[] ): FamilyUnit[] { const units: FamilyUnit[] = []; const processed = new Set(); for (const node of nodes) { if (node.spouses.length > 0) { const spouse = node.spouses[0]; const key = [ node.family.id, spouse.family.id ] .sort() .join('-'); if ( processed.has(key) ) { continue; } processed.add(key); const children = nodes .filter(child => { const fatherId = child.family.fatherId; const motherId = child.family.motherId; return ( ( fatherId === node.family.id && motherId === spouse.family.id ) || ( fatherId === spouse.family.id && motherId === node.family.id ) ); }) .map(child => child.family); units.push({ id: key, husband: node.family.gender === 'male' ? node.family : spouse.family, wife: node.family.gender === 'female' ? node.family : spouse.family, children }); } else { units.push({ id: node.family.id, husband: node.family.gender === 'male' ? node.family : undefined, wife: node.family.gender === 'female' ? node.family : undefined, children: [] }); } } return units; } buildFamilyUnitTree( units: FamilyUnit[] ): FamilyUnitNode[] { const nodeMap = new Map(); units.forEach(unit => { nodeMap.set(unit.id, { unit, children: [], parents: [] }); }); units.forEach(parentUnit => { parentUnit.children.forEach(child => { const childUnit = units.find(u => { return ( u.husband?.id === child.id || u.wife?.id === child.id ); }); if (!childUnit) { return; } const parentNode = nodeMap.get(parentUnit.id)!; const childNode = nodeMap.get(childUnit.id)!; parentNode.children.push( childNode ); childNode.parents.push( parentNode ); }); }); return [ ...nodeMap.values() ]; } getUnitRoots( nodes: FamilyUnitNode[] ): FamilyUnitNode[] { return nodes.filter( x => x.parents.length === 0 ); } }