import type { NamespaceTable } from "./NameSpaceTable"; import { coerceNodeId, NodeId } from "./NodeId"; import { UAReference } from "./UAReference"; import { assert } from "@/util/assert"; import { XMLElem, type IToXML } from "@/util/XmlElem"; import { UARolePermission } from "./UARolePermission"; //TODO import { UAExtension } from "./UAExtension"; //TODO import { UAUserWriteMask } from "./UAUserWriteMask"; //TODO import { UAWriteMask } from "./UAWriteMask"; //TODO import { UAAccessRestriction } from "./UAAccessRestriction"; //TODO export class UABaseNode implements IToXML{ public nodeId: NodeId; public nodeClass="UABaseNode"; public browseName: string; public displayName?: string; //LocText public description?: string; //LocText public symbolicName?: string; //SymbolicName public releaseStatus?: string; //ReleaseStatus public hasNoPermissions?: boolean; public writeMask?: UAWriteMask; public userWriteMask?: UAUserWriteMask; public category?: string; public documentation?: string; public accessRestriction?: UAAccessRestriction; public rolePermissions: UARolePermission[]=[]; public extensions: UAExtension[]=[]; public references: UAReference[]=[]; public opts: string[]=[]; constructor(options: UABaseNodeOptions) { this.nodeId=options.nodeId; this.browseName=options.browseName; this.displayName=options.displayName; this.references=options.references||[]; } public static nullBaseNode=new UABaseNode({browseName: "", nodeId: NodeId.nullNodeId}); reIndex(nst: NamespaceTable, onst: NamespaceTable) { const nsName=onst.getUri(this.nodeId.namespace); assert(nsName!=undefined) const newIndex=nst.getIndex(nsName); assert(newIndex!=undefined) this.nodeId.namespace=newIndex; for(const uaref of this.references) { uaref.reIndex(nst, onst); } } getParent(): UABaseNode|null { const ref=this.getParentRef(); if(ref?.fromNode===this) return ref.toNode; if(ref?.toNode===this) return ref.fromNode; return null; } setParent(node: UABaseNode, refType: String) { } getParentRef(): UAReference|null{ for(const ref of this.references) { switch(ref.referenceType) { case 'HasComponent': case 'HasOrderedComponent': case 'Organizes': case 'HasProperty': case 'HasSubtype': case 'HasAddIn': if(ref.fromNode===this&&ref.isForward===false) return ref; if(ref.toNode===this&&ref.isForward===true) return ref; } } return null; } getChildren(): UABaseNode[] { const children: UABaseNode[]=[]; for(const ref of this.references) { switch(ref.referenceType) { case 'HasComponent': case 'HasOrderedComponent': case 'Organizes': case 'HasProperty': case 'HasSubtype': case 'HasAddIn': if(ref.isForward&&ref.fromNode===this) { if(!children.includes(ref.toNode)) children.push(ref.toNode); } if(!ref.isForward&&ref.toNode===this) { if(!children.includes(ref.fromNode)) children.push(ref.fromNode); } break; } } return children; } resolveReferences(nm: Map) { for(const ref of this.references) { const fromNode=nm.get(ref.fromRef.toString()) if(fromNode) ref.fromNode=fromNode; const toNode=nm.get(ref.toRef.toString()) if(!toNode) continue; //TODO: if we cant find the node; the parser is still incomplete or the nodeset is broken ref.toNode=toNode; if(ref.fromNode.nodeId.toString()===this.nodeId.toString()){ //add this reference to referenced node //Bug? when loading from filedrop; fromNode is a proxy; this is not. if(!ref.toNode.references.includes(ref)) ref.toNode.references.push(ref); } } } static fromXML(xmlObject: any): UABaseNode{ const xmlReferences=xmlObject['References']||[]; const references:UAReference[]=[]; const nodeId=coerceNodeId(xmlObject['@_NodeId']); for(const xmlref of xmlReferences.Reference||[]) { references.push(UAReference.fromXML(xmlref, nodeId)); } const ua=new UABaseNode({nodeId: nodeId, browseName: xmlObject['@_BrowseName'], displayName: xmlObject['DisplayName']['#text'], references: references}); return ua; } toXML(lnst: NamespaceTable, gnst: NamespaceTable): XMLElem { throw new Error("UABaseNode has no xml rep; implement in subtype."); } static localNodeId(nodeId: NodeId, lnst: NamespaceTable, gnst: NamespaceTable) { const ns_uri=gnst.getUri(nodeId.namespace); assert(ns_uri); const nsIdx=lnst.getIndex(ns_uri); assert(nsIdx); const tmpNode= coerceNodeId(nodeId.toString()); tmpNode.namespace=nsIdx; return tmpNode; } } export interface UABaseNodeOptions { browseName: string; namespace?: string; nodeId: NodeId; references?: UAReference[]; displayName?: string; description?: string }