1/*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {Computation} from 'trace/tree_node/computation';
18import {HierarchyTreeNode} from 'trace/tree_node/hierarchy_tree_node';
19import {PropertiesProvider} from 'trace/tree_node/properties_provider';
20
21export abstract class HierarchyTreeBuilder {
22  protected root: PropertiesProvider | undefined;
23  protected children: PropertiesProvider[] | undefined;
24  private computations: Computation[] = [];
25
26  setRoot(value: PropertiesProvider): this {
27    this.root = value;
28    return this;
29  }
30
31  setChildren(value: PropertiesProvider[]): this {
32    this.children = value;
33    return this;
34  }
35
36  setComputations(value: Computation[]): this {
37    this.computations = value;
38    return this;
39  }
40
41  build(): HierarchyTreeNode {
42    if (!this.root) {
43      throw Error('root not set');
44    }
45
46    if (!this.children) {
47      throw Error('children not set');
48    }
49
50    const identifierToChildren = this.buildIdentifierToChildrenMap(
51      this.children,
52    );
53
54    const root = this.buildHierarchyTree(this.root, identifierToChildren);
55
56    this.computations.forEach((computation) =>
57      computation.setRoot(root).executeInPlace(),
58    );
59
60    return root;
61  }
62
63  private buildHierarchyTree(
64    root: PropertiesProvider,
65    identifierToChildren: Map<string | number, readonly HierarchyTreeNode[]>,
66  ): HierarchyTreeNode {
67    const rootProperties = root.getEagerProperties();
68    const node = this.makeNode(rootProperties.id, rootProperties.name, root);
69    this.assignParentChildRelationships(node, identifierToChildren, true);
70    return node;
71  }
72
73  protected makeNode(
74    id: string,
75    name: string,
76    propertiesProvider: PropertiesProvider,
77  ): HierarchyTreeNode {
78    return new HierarchyTreeNode(id, name, propertiesProvider);
79  }
80
81  protected setParentChildRelationship(
82    parent: HierarchyTreeNode,
83    child: HierarchyTreeNode,
84  ) {
85    parent.addOrReplaceChild(child);
86    child.setParent(parent);
87  }
88
89  protected abstract buildIdentifierToChildrenMap(
90    nodes: PropertiesProvider[],
91  ): Map<string | number, readonly HierarchyTreeNode[]>;
92
93  protected abstract assignParentChildRelationships(
94    node: HierarchyTreeNode,
95    identifierToChildren: Map<string | number, readonly HierarchyTreeNode[]>,
96    isRoot?: boolean,
97  ): void;
98}
99