1/*
2 * Copyright (C) 2022 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
16export class PluginConvertUtils {
17  private static crlf: string = '\n';
18  private static leftBrace: string = '{';
19  private static rightBrace: string = '}';
20  static pluginConfig: unknown[] = [];
21
22  public static createHdcCmd(requestString: string, outputPath: string, time: number): string {
23    return `hiprofiler_cmd \\${this.crlf}  -c - \\${this.crlf}  -o ${outputPath} \\${this.crlf}  -t ${time} \\${this.crlf}  -s \\${this.crlf}  -k \\${this.crlf}<<CONFIG${requestString}CONFIG`;
24  }
25
26  public static BeanToCmdTxt(bean: unknown, needColon: boolean): string {
27    //@ts-ignore
28    PluginConvertUtils.pluginConfig = bean.pluginConfigs;
29    //@ts-ignore
30    return this.handleObj(bean, 0, needColon, 1);
31  }
32
33  public static BeanToCmdTxtWithObjName(
34    bean: unknown,
35    needColon: boolean,
36    objName: string,
37    spacesNumber: number
38  ): string {
39    //@ts-ignore
40    return `${objName}: {${this.handleObj(bean, 0, needColon, spacesNumber)}}`;
41  }
42
43  private static handleObj(bean: object, indentation: number, needColon: boolean, spacesNumber: number): string {
44    let prefixText: string = '';
45    if (indentation === 0) {
46      prefixText = prefixText + this.crlf;
47    } else {
48      prefixText = prefixText + ' '.repeat(spacesNumber) + this.leftBrace + this.crlf;
49    }
50    if (bean) {
51      prefixText = this.getPrefixText(prefixText, indentation, needColon, spacesNumber, bean);
52    }
53    if (indentation === 0) {
54      return prefixText;
55    } else {
56      return prefixText + ' '.repeat(spacesNumber).repeat(indentation) + this.rightBrace;
57    }
58  }
59
60  private static getPrefixText(
61    prefixText: string,
62    indentation: number,
63    needColon: boolean,
64    spacesNumber: number,
65    bean: unknown
66  ): string {
67    // @ts-ignore
68    for (const [key, value] of Object.entries(bean)) {
69      const repeatedKey = Array.isArray(value);
70      if (repeatedKey) {
71        prefixText = prefixText + this.handleArray(key, value, indentation, needColon, spacesNumber);
72      } else {
73        switch (typeof value) {
74          case 'bigint':
75            prefixText = this.getMontageStrings(prefixText, spacesNumber, indentation, key, value);
76            break;
77          case 'boolean':
78            prefixText = this.getMontageStrings(prefixText, spacesNumber, indentation, key, value);
79            break;
80          case 'number':
81            if (value === 0 && !needColon) {
82              break;
83            }
84            prefixText = this.getMontageStrings(prefixText, spacesNumber, indentation, key, value);
85            break;
86          case 'string':
87            if (value === '') {
88              break;
89            }
90            prefixText = this.handleObjByStr(prefixText, value, spacesNumber, key, indentation);
91            break;
92          case 'object':
93          default:
94            prefixText = this.handleObjByDefault(prefixText, value, spacesNumber, key, indentation, needColon);
95            break;
96        }
97      }
98    }
99    return prefixText;
100  }
101
102  private static handleObjByDefault(
103    prefixText: string,
104    value: unknown,
105    spacesNumber: number,
106    key: string,
107    indentation: number,
108    needColon: boolean
109  ): string {
110    if (needColon) {
111      prefixText = `${
112        prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)
113        //@ts-ignore
114      }: ${this.handleObj(value, indentation + 1, needColon, spacesNumber)}${this.crlf}`;
115    } else {
116      prefixText = `${
117        prefixText +
118        ' '.repeat(spacesNumber).repeat(indentation + 1) +
119        this.humpToSnake(key) +
120        //@ts-ignore
121        this.handleObj(value, indentation + 1, needColon, spacesNumber)
122      }${this.crlf}`;
123    }
124    return prefixText;
125  }
126
127  private static handleObjByStr(
128    prefixText: string,
129    value: unknown,
130    spacesNumber: number,
131    key: string,
132    indentation: number
133  ): string {
134    //@ts-ignore
135    if (configEnumList.indexOf(value) >= 0 || value.startsWith('IO_REPORT')) {
136      prefixText = `${prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + //@ts-ignore
137      this.humpToSnake(key)}: ${value.toString()}${this.crlf}`;
138    } else {
139      prefixText = `${prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)}: "${
140        //@ts-ignore
141        value.toString()
142      }"${this.crlf}`;
143    }
144    return prefixText;
145  }
146
147  private static handleArray(
148    key: string,
149    arr: Array<Object>,
150    indentation: number,
151    needColon: boolean,
152    spacesNumber: number
153  ): string {
154    let text = '';
155    arr.forEach((arrValue): void => {
156      switch (typeof arrValue) {
157        case 'bigint':
158          text = this.handleArrayByBigint(text, spacesNumber, indentation, key, arrValue);
159          break;
160        case 'boolean':
161          text = this.handleArrayByBoolean(text, spacesNumber, indentation, key, arrValue);
162          break;
163        case 'number':
164          text = this.handleArrayByNumber(text, spacesNumber, indentation, key, arrValue);
165          break;
166        case 'string':
167          if (arrValue === '') {
168            break;
169          }
170          text = this.handleArrayByStr(text, spacesNumber, indentation, key, arrValue);
171          break;
172        case 'object':
173        default:
174          text = this.handleArrayByDefault(text, spacesNumber, indentation, key, arrValue, needColon);
175      }
176    });
177    return text;
178  }
179
180  private static handleArrayByBigint(
181    text: string,
182    spacesNumber: number,
183    indentation: number,
184    key: string,
185    arrValue: unknown
186  ): string {
187    //@ts-ignore
188    return `${text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)}: ${arrValue.toString()}${
189      this.crlf
190    }`;
191  }
192
193  private static handleArrayByBoolean(
194    text: string,
195    spacesNumber: number,
196    indentation: number,
197    key: string,
198    arrValue: unknown
199  ): string {
200    //@ts-ignore
201    return `${text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)}: ${arrValue.toString()}${
202      this.crlf
203    }`;
204  }
205
206  private static handleArrayByNumber(
207    text: string,
208    spacesNumber: number,
209    indentation: number,
210    key: string,
211    arrValue: unknown
212  ): string {
213    //@ts-ignore
214    return `${text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)}: ${arrValue.toString()}${
215      this.crlf
216    }`;
217  }
218
219  private static handleArrayByStr(
220    text: string,
221    spacesNumber: number,
222    indentation: number,
223    key: string,
224    arrValue: unknown
225  ): string {
226    //@ts-ignore
227    if (arrValue.startsWith('VMEMINFO') || arrValue.startsWith('PMEM')) {
228      text = `${
229        text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)
230        //@ts-ignore
231      }: ${arrValue.toString()}${this.crlf}`;
232      //@ts-ignore
233    } else if (arrValue.startsWith('REAL_BATTERY') || arrValue.startsWith('THERMAL_REPORT')) { 
234      text = `${text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)
235        //@ts-ignore
236        }: ${arrValue.toString()}${this.crlf}`;
237    } else {
238      text = `${
239        text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)
240        //@ts-ignore
241      }: "${arrValue.trim().toString()}"${this.crlf}`;
242    }
243    return text;
244  }
245
246  private static handleArrayByDefault(
247    text: string,
248    spacesNumber: number,
249    indentation: number,
250    key: string,
251    arrValue: unknown,
252    needColon: boolean
253  ): string {
254    if (needColon) {
255      text = `${text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)}: ${this.handleObj(
256        //@ts-ignore
257        arrValue,
258        indentation + 1,
259        needColon,
260        spacesNumber
261      )}${this.crlf}`;
262    } else {
263      text = `${
264        text +
265        ' '.repeat(spacesNumber).repeat(indentation + 1) +
266        this.humpToSnake(key) +
267        //@ts-ignore
268        this.handleObj(arrValue, indentation + 1, needColon, spacesNumber)
269      }${this.crlf}`;
270    }
271    return text;
272  }
273
274  // 驼峰转snake
275  private static humpToSnake(humpString: string): string {
276    return humpString.replace(/[A-Z]/g, (value) => `_${value.toLowerCase()}`);
277  }
278
279  private static getMontageStrings<T extends Object>(
280    prefixText: string,
281    spacesNumber: number,
282    indentation: number,
283    key: string,
284    value: T
285  ): string {
286    return `${
287      prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key)
288    }: ${value.toString()}${this.crlf}`;
289  }
290}
291
292const LevelConfigEnumList: string[] = ['LEVEL_UNSPECIFIED', 'DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL'];
293
294export const ffrtEnumList: string[] = ['BOOTTIME', 'REALTIME', 'REALTIME_COARSE', 'MONOTONIC',
295  'MONOTONIC_COARSE', 'MONOTONIC_RAW'];
296
297const configEnumList: string[] = [...LevelConfigEnumList, ...ffrtEnumList];
298