1/*
2 * Copyright (c) 2022-2023 Shenzhen Kaihong Digital Industry Development 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
16const { AttributeArea } = require('./attr/AttributeArea');
17const { ModifyNode } = require('./hcs/ModifyNode');
18const { DataType, NodeType } = require('./hcs/NodeTools');
19const { NodeTools } = require('./hcs/NodeTools');
20const INT64_MAX = 9223372036854775807n;
21const INT64_MIN = -9223372036854775808n;
22const CASE_DELETE = 5;
23const CASE_QUOTE = 4;
24const CASE_BOOL = 3;
25const CASE_ARRAY = 2;
26const CASE_CHARACTER_STR = 1;
27const CASE_INTEGER = 0;
28
29class AttrEditor {
30  constructor() {
31    AttributeArea.gi().registRecvCallback(this.onChange);
32    this.files_ = [];
33    this.callback_ = null;
34  }
35  setFiles(files) {
36    this.files_ = files;
37  }
38  freshEditor(fn, node) {
39    this.filePoint_ = fn;
40    this.node_ = node;
41    if (fn in this.files_) {
42      this.root_ = this.files_[fn];
43    }
44
45    AttributeArea.gi().clear();
46    if (this.node_ !== null && this.node_ !== undefined) {
47      AttributeArea.gi().addTitle(this.node_.name_);
48      switch (this.node_.type_) {
49        case DataType.NODE:
50          switch (this.node_.nodeType_) {
51            case NodeType.DATA:
52              this.freshDataNodeNotInheritEditor(this.node_);
53              break;
54            case NodeType.COPY:
55            case NodeType.REFERENCE:
56            case NodeType.INHERIT:
57              this.freshcopyNodeEditor(this.node_);
58              break;
59            case NodeType.DELETE:
60              this.freshdeleteNodeEditor(this.node_);
61              break;
62            case NodeType.TEMPLETE:
63              this.freshTempletNodeEditor(this.node_);
64              break;
65            default:
66              break;
67          }
68          break;
69        case DataType.ATTR:
70          this.freshDefineAttributeEditor(this.node_);
71          break;
72      }
73    } else {
74      AttributeArea.gi().addTitle('Property editing area');
75    }
76
77    AttributeArea.gi().flush();
78  }
79
80  freshDataNodeNotInheritEditor(node) {
81    AttributeArea.gi().addDotLine();
82    AttributeArea.gi().addTopInput(
83      'name',
84      'Node Name',
85      node.name_,
86      this.root_ == this.node_
87    );
88    AttributeArea.gi().addSelect(
89      'node_type',
90      'Node Type',
91      AttrEditor.NODE_TYPE_STR,
92      AttrEditor.NODE_TYPE_STR[node.nodeType_],
93      this.root_ == this.node_
94    );
95  }
96  changeDataNodeNotInherit(searchId, type, value) {
97    if (searchId === 'node_type') {
98      AttrEditor.gi().changeNodeType(value);
99    } else if (searchId === 'name' && this.node_.name_ !== value) {
100      ModifyNode.modifyName(this.files_, this.root_, this.node_, value);
101    } else if (searchId === 'add_child_node') {
102      this.node_.isOpen_ = true;
103      let newNode = ModifyNode.addChildNode(this.root_, this.node_);
104      this.callCallback('change_current_select', newNode);
105    } else if (searchId === 'add_child_attr') {
106      this.node_.isOpen_ = true;
107      let newNode = ModifyNode.addChildAttr(this.root_, this.node_);
108      this.callCallback('change_current_select', newNode);
109    } else if (searchId === 'delete') {
110      ModifyNode.deleteNode(this.node_);
111      this.freshEditor();
112    }
113  }
114  freshcopyNodeEditor(node) {
115    AttributeArea.gi().addDotLine();
116    AttributeArea.gi().addTopInput('name', 'Node Name', node.name_);
117    AttributeArea.gi().addSelect(
118      'node_type',
119      'Node Type',
120      AttrEditor.NODE_TYPE_STR,
121      AttrEditor.NODE_TYPE_STR[node.nodeType_],
122      this.root_ == this.node_
123    );
124    let btnName = node.ref_;
125    if (btnName === 'unknow') {
126      switch (node.nodeType_) {
127        case NodeType.COPY:
128          btnName = '取消复制';
129          break;
130        case NodeType.INHERIT:
131          btnName = '取消继承';
132          break;
133        case NodeType.REFERENCE:
134          btnName = '取消引用';
135          break;
136      }
137    }
138    AttributeArea.gi().addLabelButton(
139      'change_target',
140      btnName,
141      'Original Node'
142    );
143  }
144
145  changecopyNode(searchId, type, value) {
146    if (searchId === 'name' && this.node_.name_ !== value) {
147      ModifyNode.modifyName(this.files_, this.root_, this.node_, value);
148    } else if (searchId === 'change_target') {
149      if (this.node_.ref_ === 'unknow') {
150        ModifyNode.modifyNodeType(this.files_, this.root_, this.node_, 0);
151        this.freshEditor(this.filePoint_, this.node_);
152        this.callCallback('cancel_change_target', this.node_);
153      } else {
154        this.callCallback('change_target', this.node_);
155      }
156    } else if (searchId === 'node_type') {
157      AttrEditor.gi().changeNodeType(value);
158    } else if (searchId === 'add_child_node') {
159      ModifyNode.addChildNode(this.root_, this.node_);
160    } else if (searchId === 'add_child_attr') {
161      ModifyNode.addChildAttr(this.root_, this.node_);
162    } else if (searchId === 'delete') {
163      ModifyNode.deleteNode(this.node_);
164      this.freshEditor();
165    }
166  }
167
168  freshdeleteNodeEditor(node) {
169    AttributeArea.gi().addTopInput('name', 'Node Name', node.name_);
170    AttributeArea.gi().addSelect(
171      'node_type',
172      'Node Type',
173      AttrEditor.NODE_TYPE_STR,
174      AttrEditor.NODE_TYPE_STR[node.nodeType_],
175      this.root_ == this.node_
176    );
177  }
178
179  changeNodeType(value) {
180    ModifyNode.modifyNodeType(
181      this.files_,
182      this.root_,
183      this.node_,
184      AttrEditor.NODE_TYPE_STR.indexOf(value)
185    );
186    this.freshEditor(this.filePoint_, this.node_);
187    if (
188      this.node_.nodeType_ === NodeType.COPY ||
189      this.node_.nodeType_ === NodeType.INHERIT ||
190      this.node_.nodeType_ === NodeType.REFERENCE
191    ) {
192      this.callCallback('change_target', this.node_);
193    }
194  }
195  changedeleteNode(searchId, type, value) {
196    if (searchId === 'name' && this.node_.name_ !== value) {
197      ModifyNode.modifyName(this.files_, this.root_, this.node_, value);
198    } else if (searchId === 'delete') {
199      ModifyNode.deleteNode(this.node_);
200      this.freshEditor();
201    } else if (searchId === 'node_type') {
202      AttrEditor.gi().changeNodeType(value);
203    }
204  }
205  freshTempletNodeEditor(node) {
206    AttributeArea.gi().addDotLine();
207    AttributeArea.gi().addTopInput('name', 'Node Name', node.name_);
208    AttributeArea.gi().addSelect(
209      'node_type',
210      'Node Type',
211      AttrEditor.NODE_TYPE_STR,
212      AttrEditor.NODE_TYPE_STR[node.nodeType_],
213      this.root_ == this.node_
214    );
215  }
216  changeTempletNode(searchId, type, value) {
217    if (searchId === 'name') {
218      ModifyNode.modifyName(this.files_, this.root_, this.node_, value);
219    } else if (searchId === 'add_child_node') {
220      ModifyNode.addChildNode(this.root_, this.node_);
221    } else if (searchId === 'add_child_attr') {
222      ModifyNode.addChildAttr(this.root_, this.node_);
223    } else if (searchId === 'delete') {
224      ModifyNode.deleteNode(this.node_);
225      this.freshEditor();
226    } else if (searchId === 'node_type') {
227      AttrEditor.gi().changeNodeType(value);
228    }
229  }
230
231  freshDefineAttributeEditor(node) {
232    let v = node.value_;
233    AttributeArea.gi().addTopInput('name', 'Name', node.name_);
234
235    if (
236      v.type_ === DataType.INT8 ||
237      v.type_ === DataType.INT16 ||
238      v.type_ === DataType.INT32 ||
239      v.type_ === DataType.INT64) {
240      AttributeArea.gi().addSelect('value_type', 'Type', AttrEditor.ATTR_TYPE_STR, AttrEditor.ATTR_TYPE_STR[CASE_INTEGER]);
241      AttributeArea.gi().addValidatorInput(
242        'value', 'Attribute Value', NodeTools.jinZhi10ToX(v.value_, v.jinzhi_), false, '请输入整数');
243    } else if (v.type_ === DataType.STRING) {
244      AttributeArea.gi().addSelect('value_type', 'Type', AttrEditor.ATTR_TYPE_STR, AttrEditor.ATTR_TYPE_STR[CASE_CHARACTER_STR]);
245      AttributeArea.gi().addInput('value', 'Attribute Value', v.value_);
246    } else if (v.type_ === DataType.ARRAY) {
247      AttributeArea.gi().addSelect('value_type', 'Type', AttrEditor.ATTR_TYPE_STR, AttrEditor.ATTR_TYPE_STR[CASE_ARRAY]);
248      AttributeArea.gi().addTextArea('value', 'Attribute Value', NodeTools.arrayToString(v, 20));
249    } else if (v.type_ === DataType.BOOL) {
250      AttributeArea.gi().addSelect('value_type', 'Type', AttrEditor.ATTR_TYPE_STR, AttrEditor.ATTR_TYPE_STR[CASE_BOOL]);
251      AttributeArea.gi().addSelect('value', 'Attribute Value', [true, false], v.value_ == 1);
252    } else if (v.type_ === DataType.REFERENCE) {
253      AttributeArea.gi().addSelect('value_type', 'Type', AttrEditor.ATTR_TYPE_STR, AttrEditor.ATTR_TYPE_STR[CASE_QUOTE]);
254      AttributeArea.gi().addLabelButton('change_target', v.value_, 'Original Node');
255    } else if (v.type_ === DataType.DELETE) {
256      AttributeArea.gi().addSelect('value_type', 'Type', AttrEditor.ATTR_TYPE_STR, AttrEditor.ATTR_TYPE_STR[CASE_DELETE]);
257    }
258  }
259
260  getNodeValue(v, value) {
261    switch (AttrEditor.ATTR_TYPE_STR.indexOf(value)) {
262      case CASE_INTEGER:
263        v.type_ = DataType.INT8;
264        v.value_ = 0;
265        v.jinzhi_ = 10;
266        break;
267      case CASE_CHARACTER_STR:
268        v.type_ = DataType.STRING;
269        v.value_ = '';
270        break;
271      case CASE_ARRAY:
272        v.type_ = DataType.ARRAY;
273        v.value_ = [];
274        break;
275      case CASE_BOOL:
276        v.type_ = DataType.BOOL;
277        v.value_ = 1;
278        break;
279      case CASE_QUOTE:
280        v.type_ = DataType.REFERENCE;
281        v.value_ = 'unknow';
282        break;
283      case CASE_DELETE:
284        v.type_ = DataType.DELETE;
285        break;
286    }
287    this.freshEditor(this.filePoint_, this.node_);
288  }
289
290  validateNumber(value) {
291    let validRes = {};
292    validRes.errMsg = '';
293    let ret = NodeTools.jinZhiXTo10(value);
294    if (ret[0] === undefined) {
295      validRes.errMsg = '请输入整数';
296    }
297
298    if (ret[0] > INT64_MAX || ret[0] < INT64_MIN) {
299      validRes.errMsg = '数字大小不能超出Int64范围';
300    }
301    validRes.value = ret[0];
302    validRes.base = ret[1];
303    return validRes;
304  }
305
306  changeDefineAttribute(searchId, type, value) {
307    let v = this.node_.value_;
308    if (searchId === 'name' && value !== this.node_.name_) {
309      ModifyNode.modifyName(this.files_, this.root_, this.node_, value);
310    }
311    if (searchId === 'value_type') {
312      this.getNodeValue(v, value);
313    }
314    if (searchId === 'change_target') {
315      this.callCallback('change_target', v);
316    }
317    if (searchId === 'value') {
318      if (
319        v.type_ === DataType.INT8 ||
320        v.type_ === DataType.INT16 ||
321        v.type_ === DataType.INT32 ||
322        v.type_ === DataType.INT64
323      ) {
324        let validRes = this.validateNumber(value);
325        let validatorLabel = document.getElementById('valid_' + searchId);
326        if (validRes.errMsg === '') {
327          validatorLabel.style.display = 'none';
328          v.value_ = validRes.value;
329          v.jinzhi_ = validRes.base;
330        } else {
331          validatorLabel.innerText = validRes.errMsg;
332          validatorLabel.style.display = '';
333        }
334      } else if (v.type_ === DataType.STRING) {
335        v.value_ = value;
336      } else if (v.type_ === DataType.ARRAY) {
337        v.value_ = NodeTools.stringToArray(value);
338      } else if (v.type_ === DataType.BOOL) {
339        v.value_ = value === 'true' ? 1 : 0;
340      }
341    }
342    if (searchId === 'delete') {
343      ModifyNode.deleteNode(this.node_);
344      this.freshEditor();
345    }
346  }
347  onChange(searchId, type, value) {
348    let pattr = AttrEditor.gi();
349    if (pattr.node_ !== null) {
350      AttributeArea.gi().addTitle(pattr.node_.name_);
351      switch (pattr.node_.type_) {
352        case DataType.NODE:
353          switch (pattr.node_.nodeType_) {
354            case NodeType.DATA:
355              pattr.changeDataNodeNotInherit(searchId, type, value);
356              break;
357            case NodeType.COPY:
358            case NodeType.REFERENCE:
359            case NodeType.INHERIT:
360              pattr.changecopyNode(searchId, type, value);
361              break;
362            case NodeType.DELETE:
363              pattr.changedeleteNode(searchId, type, value);
364              break;
365            case NodeType.TEMPLETE:
366              pattr.changeTempletNode(searchId, type, value);
367              break;
368            default:
369              break;
370          }
371          break;
372        case DataType.ATTR:
373          pattr.changeDefineAttribute(searchId, type, value);
374          break;
375      }
376      pattr.callCallback('writefile');
377    }
378  }
379
380  callCallback(type, value) {
381    if (this.callback_ !== null) {
382      this.callback_(type, value);
383    }
384  }
385  registCallback(func) {
386    this.callback_ = func;
387  }
388}
389
390AttrEditor.NODE_TYPE_STR = [
391  '数据类不继承',
392  '复制类',
393  '引用修改类',
394  '删除类',
395  '模板类',
396  '数据类继承',
397];
398AttrEditor.ATTR_CLASS = ['定义类属性', '删除类属性', '引用类属性'];
399
400AttrEditor.ATTR_TYPE_STR = ['整数', '字符串', '数组', '布尔', '引用', '删除'];
401
402AttrEditor.pInstance_ = null;
403AttrEditor.gi = function () {
404  if (AttrEditor.pInstance_ === null) {
405    AttrEditor.pInstance_ = new AttrEditor();
406  }
407  return AttrEditor.pInstance_;
408};
409
410module.exports = {
411  AttrEditor,
412};
413