/** 
 | 
 * Row data are defined as name and (immediate) parent only. 
 | 
 * DataHierarchyProvider class is able to query recursively to infer all ancestors. 
 | 
 */ 
 | 
export interface DataHierarchy { 
 | 
  Name: string; 
 | 
  ParentKey: string; 
 | 
  NameKey: string; 
 | 
  OndrawImageName?: string; 
 | 
} 
 | 
  
 | 
/** 
 | 
 * Provider class to get all ancestor row names by passing in the target child row. 
 | 
 */ 
 | 
export class DataHierarchyProvider { 
 | 
  private readonly store: Map<string, DataHierarchy> = new Map(); 
 | 
  
 | 
  public constructor(data: Record<string, DataHierarchy>) { 
 | 
    for (const t of Object.keys(data)) { 
 | 
      const a = data[t]; 
 | 
      this.store.set(a.NameKey, a); // Stores row data and its immediate parent 
 | 
    } 
 | 
  } 
 | 
  
 | 
  /** 
 | 
   * Given a row name, infer the ancestor rows. 
 | 
   * 
 | 
   * @param key Row name. 
 | 
   * @returns Tuple containing row name and all ancestors. 
 | 
   */ 
 | 
  public getHierarchy(key: DataHierarchy): [DataHierarchy, DataHierarchy[]] { 
 | 
    // Recursive get all ancestor rows 
 | 
    const ancestor = this.store.get(key.NameKey); 
 | 
    let ancestorArr: DataHierarchy[] = []; 
 | 
    ancestorArr = this.recursiveGetAncestor(ancestor!, ancestorArr); 
 | 
    return [key, ancestorArr]; 
 | 
  } 
 | 
  
 | 
  private recursiveGetAncestor(ancestor: DataHierarchy, ancestorArr: DataHierarchy[]): DataHierarchy[] { 
 | 
    const hasParent = ancestor !== undefined && ancestor.ParentKey !== ''; 
 | 
    if (hasParent) { 
 | 
      const ancestorName = this.store.get(ancestor.ParentKey); 
 | 
      if (ancestorName) { 
 | 
        ancestorArr = [ancestorName].concat(ancestorArr); // Put ancestor to the front of array 
 | 
        ancestorArr = this.recursiveGetAncestor(ancestorName, ancestorArr); 
 | 
      } else { 
 | 
        throw(TypeError(`No Ancestor: ${ancestor.ParentKey} to be found.`)); 
 | 
      } 
 | 
    } 
 | 
    return ancestorArr; 
 | 
  } 
 | 
} 
 |