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
16import { BaseElement, element } from '../../../base-ui/BaseElement';
17import '../../../base-ui/select/LitSelectV';
18import '../../../base-ui/select/LitSelect';
19
20import '../../../base-ui/switch/lit-switch';
21import LitSwitch, { LitSwitchChangeEvent } from '../../../base-ui/switch/lit-switch';
22import { LitSelectV } from '../../../base-ui/select/LitSelectV';
23import { LitAllocationSelect } from '../../../base-ui/select/LitAllocationSelect';
24import { SpSdkConfigHtml } from './SpSdkConfig.html';
25
26@element('sp-sdk-config')
27export class SpSdkConfig extends BaseElement {
28  private worker: Worker | undefined;
29  private sdkConfigList: unknown;
30  private customConfig: HTMLDivElement | undefined | null;
31  private selectConfig: LitSelectV | undefined | null;
32  private list: Array<HTMLElement> | undefined;
33  private pluginName: string = '';
34  private sampleInterval: number = 5000;
35
36  static get observedAttributes(): string[] {
37    return ['configName', 'value', 'type'];
38  }
39
40  get show(): boolean {
41    return this.hasAttribute('show');
42  }
43
44  set show(sdkConfigShow: boolean) {
45    if (sdkConfigShow) {
46      this.setAttribute('show', '');
47    } else {
48      this.removeAttribute('show');
49    }
50  }
51
52  set startSamp(sdkConfigStart: boolean) {
53    if (sdkConfigStart) {
54      this.setAttribute('startSamp', '');
55    } else {
56      this.removeAttribute('startSamp');
57    }
58  }
59
60  get startSamp(): boolean {
61    return this.hasAttribute('startSamp');
62  }
63
64  set configName(configName: string) {
65    if (configName !== '') {
66      this.setAttribute('configName', configName);
67    } else {
68      this.removeAttribute('configName');
69    }
70  }
71
72  get configName(): string {
73    return this.getAttribute('configName') || '';
74  }
75
76  get type(): string {
77    return this.getAttribute('type') || '';
78  }
79
80  set type(type: string) {
81    if (type !== '') {
82      this.setAttribute('type', type);
83    } else {
84      this.removeAttribute('type');
85    }
86  }
87
88  private wasmMap: Map<string, unknown> = new Map<string, unknown>();
89  private wasmList: Array<string> = [];
90
91  private changGpu(gpuName: string): void {
92    let config = this.wasmMap.get(gpuName);
93    //@ts-ignore
94    this.pluginName = config?.pluginName;
95    //@ts-ignore
96    this.sampleInterval = config?.sampleInterval;
97    let pam = {
98      action: 'open',
99      //@ts-ignore
100      componentId: config.componentId,
101      //@ts-ignore
102      wasmJsName: config.wasmJsName,
103      //@ts-ignore
104      WasmName: config.wasmName,
105    };
106    this.worker!.postMessage(pam);
107    this.worker!.onmessage = (event: MessageEvent): void => {
108      let results = event.data.results;
109      this.sdkConfigList = results.settingConfig;
110      this.initConfig();
111    };
112  }
113
114  getPlugName(): string {
115    return this.pluginName;
116  }
117
118  getSampleInterval(): number {
119    return this.sampleInterval;
120  }
121
122  getGpuConfig(): {} {
123    let configVal = this.shadowRoot?.querySelectorAll<HTMLElement>('.config');
124    let gpuConfig = {};
125    for (let i = 0; i < configVal!.length; i++) {
126      let configName = configVal![i].getAttribute('configName');
127      let type = configVal![i].getAttribute('type');
128      if (type === 'enum') {
129        let enumValue = configVal![i].getAttribute('value');
130        if (enumValue !== undefined && enumValue !== 'undefined') {
131          // @ts-ignore
132          gpuConfig[configName!] = enumValue;
133        }
134      } else if (type === 'number' || type === 'integer' || type === 'num') {
135        // @ts-ignore
136        gpuConfig[configName!] = Number(configVal![i].value);
137      } else if (type === 'boolean') {
138        let attribute = configVal![i].getAttribute('value');
139        // @ts-ignore
140        gpuConfig[configName!] = attribute === 'true';
141      } else {
142        // @ts-ignore
143        gpuConfig[configName!] = configVal![i].value;
144      }
145    }
146    return gpuConfig;
147  }
148
149  private initSdkWasm(): void {
150    try {
151      let spApplication = document.querySelector<HTMLElement>('sp-application');
152      let wasmJsonUrl = `https://${window.location.host.split(':')[0]}:${window.location.port}/application/wasm.json`;
153      if (spApplication!.hasAttribute('vs')) {
154        wasmJsonUrl = `http://${window.location.host.split(':')[0]}:${window.location.port}/wasm.json`;
155      }
156      fetch(wasmJsonUrl)
157        .then((res): void => {
158          if (res.ok) {
159            res.text().then((text) => {
160              this.wasmMap = new Map();
161              this.wasmList = [];
162              let wasmJson = JSON.parse(text);
163              let wasmFiles = wasmJson.WasmFiles;
164              wasmFiles.forEach((wasmFile: unknown) => {
165                //@ts-ignore
166                this.wasmMap.set(wasmFile.disPlayName, wasmFile);
167                //@ts-ignore
168                this.wasmList.push(wasmFile.disPlayName);
169              });
170            });
171          }
172        })
173        .catch(() => { });
174      if (this.worker === null) {
175        // @ts-ignore
176        if (window.useWb) {
177          return;
178        }
179        this.worker = new Worker(new URL('../../database/ConfigWorker', import.meta.url));
180      }
181    } catch (e) { }
182  }
183
184  initElements(): void {
185    this.initSdkWasm();
186    this.customConfig = this.shadowRoot?.querySelector<HTMLDivElement>('.configList');
187    let switchButton = this.shadowRoot?.querySelector('.config_switch') as LitSwitch;
188    switchButton.addEventListener('change', (event: CustomEventInit<LitSwitchChangeEvent>) => {
189      let detail = event.detail;
190      if (detail!.checked) {
191        this.startSamp = true;
192        this.isAbleShowConfig(false);
193      } else {
194        this.startSamp = false;
195        this.isAbleShowConfig(true);
196      }
197    });
198    this.selectConfig = this.shadowRoot?.querySelector<LitSelectV>('lit-select-v');
199    let inputDiv = this.selectConfig?.shadowRoot?.querySelector('input') as HTMLDivElement;
200    inputDiv.addEventListener('mousedown', () => {
201      if (this.startSamp) {
202        inputDiv!.removeAttribute('readonly');
203        this.selectConfig!.dataSource(this.wasmList, '', true);
204      } else {
205        inputDiv!.setAttribute('readonly', 'readonly');
206        return;
207      }
208    });
209    this.list = [];
210    this.list.push(this.selectConfig!);
211    this.isAbleShowConfig(true);
212  }
213
214  private sdkConfigByBooleanType(key: string, sdkConfigSwitch: LitSwitch, sdkConfigHeadDiv: HTMLDivElement): void {
215    sdkConfigSwitch.className = 'switch1 config';
216    sdkConfigSwitch.setAttribute('configName', key);
217    //@ts-ignore
218    sdkConfigSwitch.setAttribute('type', this.sdkConfigList.configuration[key].type);
219    //@ts-ignore
220    if (this.sdkConfigList.configuration[key].default === 'true') {
221      sdkConfigSwitch.setAttribute('checked', '');
222      sdkConfigSwitch.setAttribute('value', 'true');
223    } else {
224      sdkConfigSwitch.removeAttribute('checked');
225      sdkConfigSwitch.setAttribute('value', 'false');
226    }
227    sdkConfigHeadDiv.appendChild(sdkConfigSwitch);
228    this.list!.push(sdkConfigSwitch);
229  }
230
231  private sdkConfigByIntegerType(key: string, sdkConfigDiv: HTMLDivElement, sdkConfigTitle: HTMLSpanElement): void {
232    let input = document.createElement('input');
233    input.className = 'sdk-config-input config';
234    //@ts-ignore
235    if (this.sdkConfigList.configuration[key].default) {
236      //@ts-ignore
237      input.value = this.sdkConfigList.configuration[key].default;
238    }
239    input.setAttribute('configName', key);
240    //@ts-ignore
241    input.setAttribute('type', this.sdkConfigList.configuration[key].type);
242    input.oninput = (): void => {
243      input.value = this.checkIntegerInput(input.value);
244      sdkConfigTitle.setAttribute('value', input.value);
245    };
246    sdkConfigDiv.appendChild(input);
247    this.list!.push(input);
248  }
249
250  private sdkConfigByNumberType(key: string, sdkConfigDiv: HTMLDivElement): void {
251    let numberInput = document.createElement('input');
252    numberInput.className = 'sdk-config-input config';
253    //@ts-ignore
254    if (this.sdkConfigList.configuration[key].default) {
255      //@ts-ignore
256      numberInput.value = this.sdkConfigList.configuration[key].default;
257    }
258    numberInput.setAttribute('configName', key);
259    numberInput.setAttribute('type', 'num');
260    numberInput.oninput = (): void => {
261      numberInput.value = this.checkFloatInput(numberInput.value);
262    };
263    sdkConfigDiv.appendChild(numberInput);
264    this.list!.push(numberInput);
265  }
266
267  private sdkConfigByStringType(key: string, sdkConfigDiv: HTMLDivElement): void {
268    let html = '';
269    //@ts-ignore
270    if (this.sdkConfigList.configuration[key].enum) {
271      let placeholder = '';
272      //@ts-ignore
273      if (this.sdkConfigList.configuration[key].default) {
274        //@ts-ignore
275        placeholder = this.sdkConfigList.configuration[key].default;
276      }
277      //@ts-ignore
278      html += `<lit-select-v id="${key}" type="${this.sdkConfigList.configuration[key].type}" 
279default-value="" rounded="" class="sdk-config-select config" mode="multiple" canInsert="" 
280rounded placement = "bottom" configName ="${key}" placeholder="${placeholder}"></lit-select-v>`;
281      sdkConfigDiv.innerHTML = sdkConfigDiv.innerHTML + html;
282    } else {
283      let inputElement = document.createElement('input');
284      inputElement.className = 'sdk-config-input config';
285      //@ts-ignore
286      if (this.sdkConfigList.configuration[key].default) {
287        //@ts-ignore
288        inputElement.value = this.sdkConfigList.configuration[key].default;
289      }
290      inputElement.setAttribute('configName', key);
291      //@ts-ignore
292      inputElement.setAttribute('type', this.sdkConfigList.configuration[key].type);
293      sdkConfigDiv.appendChild(inputElement);
294      this.list!.push(inputElement);
295    }
296  }
297
298  initConfig(): void {
299    this.customConfig!.innerHTML = '';
300    this.list = [];
301    this.list.push(this.selectConfig!);
302    let sdkConfigSwitch = document.createElement('lit-switch') as LitSwitch;
303    //@ts-ignore
304    for (let key in this.sdkConfigList.configuration) {
305      let sdkConfigDiv = document.createElement('div');
306      sdkConfigDiv.className = 'sdk-config-div';
307      let sdkConfigHeadDiv = document.createElement('div');
308      sdkConfigDiv.appendChild(sdkConfigHeadDiv);
309      let sdkConfigTitle = document.createElement('span');
310      sdkConfigTitle.className = 'sdk-config-title';
311      sdkConfigTitle.textContent = key;
312      sdkConfigHeadDiv.appendChild(sdkConfigTitle);
313      let sdkConfigDes = document.createElement('span');
314      //@ts-ignore
315      sdkConfigDes.textContent = this.sdkConfigList.configuration[key].description;
316      sdkConfigDes.className = 'sdk-config-des';
317      sdkConfigHeadDiv.appendChild(sdkConfigDes);
318      //@ts-ignore
319      switch (this.sdkConfigList.configuration[key].type) {
320        case 'string':
321          this.sdkConfigByStringType(key, sdkConfigDiv);
322          break;
323        case 'number':
324          this.sdkConfigByNumberType(key, sdkConfigDiv);
325          break;
326        case 'integer':
327          this.sdkConfigByIntegerType(key, sdkConfigDiv, sdkConfigTitle);
328          break;
329        case 'boolean':
330          this.sdkConfigByBooleanType(key, sdkConfigSwitch, sdkConfigHeadDiv);
331          break;
332      }
333      this.customConfig!.appendChild(sdkConfigDiv);
334      //@ts-ignore
335      if (this.sdkConfigList.configuration[key].enum) {
336        let select = this.shadowRoot!.querySelector<LitSelectV>(`#${key}`);
337        select!.setAttribute('type', 'enum');
338        //@ts-ignore
339        select!.setAttribute('value', this.sdkConfigList.configuration.key.default);
340        //@ts-ignore
341        select!.dataSource(this.sdkConfigList.configuration.key.enum, '');
342        this.list.push(select!);
343        select!.addEventListener('click', () => {
344          select!.setAttribute('value', select!.value);
345        });
346      }
347    }
348    sdkConfigSwitch.addEventListener('change', () => {
349      sdkConfigSwitch.setAttribute('value', `${sdkConfigSwitch.hasAttribute('checked')}`);
350    });
351  }
352
353  checkIntegerInput(value: string): string {
354    let inputValue = value
355      .replace(/[^\-\d]|\-{2,}/g, '')
356      .replace(/(\d)\-|-(0+)|^0+(\d)/g, '$1')
357      .replace(/(-?\d{15})\d*/, '$1');
358    return inputValue;
359  }
360
361  checkFloatInput(value: string): string {
362    let inputValue = value
363      .replace(/[^\d.]/g, '')
364      .replace(/^\.|^0+(\d)/g, '')
365      .replace(/(\.\d+)\.|(-)\.|(\d+|\.)-/g, '$1')
366      .replace(/(-?\d{9})\d*/, '$1');
367    return inputValue.replace(/\.{2,}|-(0){2,}|(-)0+(\d+)/g, '.');
368  }
369
370  isAbleShowConfig(isAbleShow: boolean): void {
371    if (this.list!) {
372      if (isAbleShow) {
373        this.list!.forEach((item) => {
374          item.setAttribute('disabled', '');
375        });
376      } else {
377        this.list!.forEach((item) => {
378          item.removeAttribute('disabled');
379        });
380      }
381    }
382  }
383
384  initHtml(): string {
385    return SpSdkConfigHtml;
386  }
387}
388