1/*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { SpSystemTrace } from '../SpSystemTrace';
17import { TraceRow } from '../trace/base/TraceRow';
18import { renders } from '../../database/ui-worker/ProcedureWorker';
19import { SpStatisticsHttpUtil } from '../../../statistics/util/SpStatisticsHttpUtil';
20import { BaseStruct } from '../../bean/BaseStruct';
21import { folderSupplier, rowThreadHandler } from './SpChartManager';
22import { EmptyRender } from '../../database/ui-worker/cpu/ProcedureWorkerCPU';
23import { TraceRowConfig } from '../trace/base/TraceRowConfig';
24import { ProcessMemStruct } from '../../bean/ProcessMemStruct';
25import { MemRender } from '../../database/ui-worker/ProcedureWorkerMem';
26import { FuncRender, FuncStruct } from '../../database/ui-worker/ProcedureWorkerFunc';
27import { ThreadRender } from '../../database/ui-worker/ProcedureWorkerThread';
28import { promises } from 'dns';
29const FOLD_HEIGHT = 24;
30export class SpImportUserPluginsChart {
31	private trace: SpSystemTrace;
32	static userPluginData: [];
33	private traceId?: string | undefined;
34
35	constructor(trace: SpSystemTrace) {
36		this.trace = trace;
37	}
38
39	async init(traceId?: string): Promise<void> {
40		this.traceId = traceId;
41		//@ts-ignore
42		let folderRow = this.createFolderRow(this.traceId);
43		folderRow.rowId = 'UserPluginsRows';
44		folderRow.rowType = TraceRow.ROW_TYPE_IMPORT;
45		folderRow.name = 'UserPluginsRows';
46		folderRow.selectChangeHandler = this.trace.selectChangeHandler;
47		this.trace.rowsEL?.appendChild(folderRow);
48	}
49
50	createFolderRow(traceId?: string): TraceRow<BaseStruct> {
51		let folder = TraceRow.skeleton<BaseStruct>(traceId);
52		folder.rowParentId = '';
53		folder.folder = true;
54		folder.style.height = '40px';
55		folder.rowHidden = folder.expansion;
56		folder.summaryProtoPid = [];
57		folder.setAttribute('children', '');
58		folder.supplier = folderSupplier();
59		folder.onThreadHandler = folderThreadHandler(folder, this.trace);
60		folder.addRowSampleUpload();
61		this.addTraceRowEventListener(folder);
62		return folder;
63	}
64
65	/**
66	 * 监听文件上传事件
67	 * @param row 
68	 * @param start_ts 
69	 */
70	addTraceRowEventListener(row: TraceRow<BaseStruct>): void {
71		row.uploadEl?.addEventListener('sample-file-change', (e: unknown) => {
72			this.getJsonData(e).then((res: unknown) => {
73				if (row.childrenList.length) { this.handleDynamicRowList(row); }
74				//@ts-ignore
75				if (res && res.data) {
76					let len = TraceRowConfig.allTraceRowList.length;
77					//@ts-ignore
78					res.data.forEach(item => {
79						//支持mem,thread, func
80						if (![TraceRow.ROW_TYPE_MEM, TraceRow.ROW_TYPE_THREAD, TraceRow.ROW_TYPE_FUNC].includes(item.rowType)) {
81							return;
82						}
83						for (let index = 0; index < len - 1; index++) {
84							const element = TraceRowConfig.allTraceRowList[index];
85							if (element.rowType === item.rowType && element.name === item.threadName) {
86								//@ts-ignore
87								let parentRows = this.trace.shadowRoot?.querySelectorAll<TraceRow<unknown>>(`trace-row[row-id='${element.rowParentId}']`);
88								let childRow = TraceRow.skeleton<BaseStruct>();
89								//@ts-ignore
90								childRow.rowId = element.rowId;
91								childRow.rowType = element.rowType;
92								childRow.protoParentId = parentRows?.[0].name;
93								childRow.protoPid = element.rowParentId!;
94								childRow.rowParentId = 'UserPluginsRows';
95								childRow.rowHidden = element.rowHidden;
96								childRow.style.width = childRow.style.width;
97								childRow.style.height = element.style.height;
98								childRow.enableCollapseChart(FOLD_HEIGHT, this.trace);
99								//@ts-ignore
100								childRow.name = element.name;
101								childRow.setAttribute('children', '');
102								childRow.needRefresh = true;
103								childRow.favoriteChangeHandler = element.favoriteChangeHandler;
104								childRow.selectChangeHandler = element.selectChangeHandler;
105								this.addDrawAttributes(item, childRow, element);
106								row.summaryProtoPid!.push(childRow.protoPid);
107								row.addChildTraceRow(childRow);
108							};
109						};
110					});
111					row.expansion = true;
112				};
113				this.trace.refreshCanvas(false);
114			});
115		});
116	}
117	//清空row-parent-id='UserPluginsRows'动态添加的子Row的list数据
118	handleDynamicRowList(row: TraceRow<BaseStruct>): void {
119		row.summaryProtoPid = [];
120		// 使用querySelectorAll找到所有row-parent-id='UserPluginsRows'的div元素
121		//@ts-ignore
122		let childRows: Array<TraceRow<unknown>> = [
123			//@ts-ignore
124			...this.trace.shadowRoot!.querySelectorAll<TraceRow<unknown>>(`trace-row[row-parent-id='UserPluginsRows']`),
125		];
126		// 遍历这些元素  
127		childRows.forEach((div) => {
128			// 如果等于,则从父节点中删除该元素  
129			if (div.parentNode) {
130				div.parentNode.removeChild(div);
131			}
132		});
133		//删除上一次导入file添加的row
134		TraceRowConfig.allTraceRowList = TraceRowConfig.allTraceRowList.filter(item => item.rowParentId !== 'UserPluginsRows');
135		row.expansion = false;
136		row.childrenList = [];
137	}
138
139	addDrawAttributes(item: { rowType: string, threadName: string }, childRow: TraceRow<BaseStruct>, element: unknown): void {
140		//@ts-ignore
141		if (element.supplier) {
142			//@ts-ignore
143			childRow.supplier = async (): Promise<unknown> => {
144				//@ts-ignore
145				let res = await element.supplier!();
146				return res;
147			};
148			//@ts-ignore
149		} else if (element.supplierFrame) {
150			//@ts-ignore
151			childRow.supplierFrame = async (): Promise<unknown> => {
152				//@ts-ignore
153				let res = await element.supplierFrame!();
154				return res;
155			};
156		}
157		if (item.rowType === TraceRow.ROW_TYPE_MEM) {//处理mem
158			childRow.findHoverStruct = (): void => {
159				//@ts-ignore
160				ProcessMemStruct.hoverProcessMemStruct = childRow.getHoverStruct(false);
161			};
162			childRow.focusHandler = (): void => {
163				if (childRow.hoverY <= 5 || childRow.hoverY >= 35) {
164					ProcessMemStruct.hoverProcessMemStruct = undefined;
165				}
166				this.trace.displayTip(
167					childRow,
168					ProcessMemStruct.hoverProcessMemStruct,
169					`<span>${ProcessMemStruct.hoverProcessMemStruct?.value || '0'}</span>`
170				);
171			};
172			childRow.onThreadHandler = rowThreadHandler<MemRender>('mem', 'context',
173				//@ts-ignore
174				{ type: `mem ${element.rowId} ${element.name}` }, childRow, this.trace);
175		} else if (item.rowType === TraceRow.ROW_TYPE_FUNC) {
176			//处理func
177			//@ts-ignore
178			if (element.asyncFuncName) {
179				//@ts-ignore
180				childRow.asyncFuncName = element.asyncFuncName;
181				//@ts-ignore
182				childRow.asyncFuncNamePID = element.asyncFuncNamePID;
183				//@ts-ignore
184				childRow.asyncFuncStartTID = element.asyncFuncStartTID;
185			}
186			//@ts-ignore
187			if (element.asyncFuncThreadName) {
188				//@ts-ignore
189				childRow.asyncFuncThreadName = element.asyncFuncThreadName;
190				//@ts-ignore
191				childRow.asyncFuncNamePID = element.asyncFuncNamePID;
192			}
193			childRow.findHoverStruct = (): void => {
194				//@ts-ignore
195				FuncStruct.hoverFuncStruct = childRow.getHoverStruct();
196			};
197			childRow.onThreadHandler = rowThreadHandler<FuncRender>('func', 'context',
198				//@ts-ignore
199				{ type: '' }, childRow, this.trace);
200		} else if (item.rowType === TraceRow.ROW_TYPE_THREAD) {
201			//处理thread
202			childRow.onThreadHandler = rowThreadHandler<ThreadRender>('thread', 'context',
203				{ type: '', translateY: childRow.translateY }, childRow, this.trace);
204		}
205	}
206	/**
207	 * 获取上传的文件内容 转为json格式
208	 * @param file 
209	 * @returns 
210	 */
211	getJsonData(file: unknown): Promise<unknown> {
212		return new Promise((resolve, reject) => {
213			let reader = new FileReader();
214			//@ts-ignore
215			reader.readAsText(file.detail || file);
216			reader.onloadend = (e: unknown): void => {
217				//@ts-ignore
218				const fileContent = e.target?.result;
219				try {
220					resolve(JSON.parse(fileContent));
221					document.dispatchEvent(
222						new CustomEvent('file-correct')
223					);
224					SpStatisticsHttpUtil.addOrdinaryVisitAction({
225						event: 'seach-row',
226						action: 'seach-row',
227					});
228				} catch (error) {
229					document.dispatchEvent(
230						new CustomEvent('file-error')
231					);
232				}
233			};
234		});
235	}
236}
237export const folderThreadHandler = (row: TraceRow<BaseStruct>, trace: SpSystemTrace) => {
238	return (useCache: boolean): void => {
239		row.canvasSave(trace.canvasPanelCtx!);
240		if (row.expansion) {
241			// @ts-ignore
242			trace.canvasPanelCtx?.clearRect(0, 0, row.frame.width, row.frame.height);
243		} else {
244			(renders.empty as EmptyRender).renderMainThread(
245				{
246					context: trace.canvasPanelCtx,
247					useCache: useCache,
248					type: '',
249				},
250				row
251			);
252		}
253		row.canvasRestore(trace.canvasPanelCtx!, trace);
254	};
255};
256
257