1/*
2* Copyright (c) 2024 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 { NapiLog } = require('../tools/NapiLog');
17const util = require('util');
18const path = require('path');
19const fs = require('fs');
20const { writeFile, readFile } = require('../tools/tool');
21const re = require('../tools/re');
22const LENGTH = 10;
23const TWO_DECIMAL = 2;
24
25function analyzeRetIsObject(retType, objectInfo) {
26    // 去除 * 和 空格
27    retType = retType.replace('*', '').replace('struct', '').trim();
28    let objKeys = Object.keys(objectInfo);
29    for (let i = 0; i < objKeys.length; i++) {
30        if (retType === objKeys[i]) {
31            return true;
32        }
33    }
34    return false;
35}
36
37
38function analyzeRetIsTypeDef(type, info) {
39  let typedefKeys = Object.keys(info);
40  for (let i = 0; i < typedefKeys.length; i++) {
41    if (type === typedefKeys[i]) {
42      return info[type];
43    }
44  }
45  return null;
46}
47
48//tsFuncName
49function generateDirectFunction(params, index, tsFuncName, directFuncPath, hFileName) {
50    let funcInfo = {
51        'name': '',
52        'params': [],
53        'retType': '',
54    };
55
56    let funcNameReplace = tsFuncName;
57
58    // 方法的注册
59    let initReplace = genInitFunction(directFuncPath, funcNameReplace);
60
61    // 分析方法  分析第index个方法
62    analyzeFunction(funcInfo, params, index);
63
64    // 生成
65    let paramGenResult = genParamInfo(directFuncPath, funcInfo, params);
66
67    // 返回值处理  对于对象要使用循环处理
68    let retGenResult = '';
69    let retObjInfo = {
70        'objName': '',
71        'flag': false
72    };
73
74    let funcRetOutPath = directFuncPath.cppTempleteDetails.funcBody.funcReturnOut;
75    retGenResult = returnTypeC2Js(funcRetOutPath, funcInfo, params, retGenResult, retObjInfo);
76
77    let { bodyReplace, funcInfoParams } = getReplaceInfo(directFuncPath, funcInfo, funcNameReplace, hFileName);
78
79    let funcGetParamTempletePath = path.join(__dirname,
80      directFuncPath.cppTempleteDetails.funcBody.funcParamIn.funcGetParamTemplete);
81    let funcGetParamTemplete = readFile(funcGetParamTempletePath);
82    let genParamReplace = getGenParamReplace(funcGetParamTemplete, funcInfo, funcNameReplace, paramGenResult);
83    bodyReplace = getBodyReplace2(funcInfo, bodyReplace, genParamReplace);
84    if (funcInfo.retType.replace('*', '').trim() !== 'void') {
85        let returnType = funcInfo.retType === 'std::string' ? 'const char *' : funcInfo.retType;
86        returnType = returnType === 'size_t' ? 'int64_t' : returnType;
87        let funcReturnTempletePath = path.join(__dirname, funcRetOutPath.funcReturnTemplete);
88        let funcReturnTemplete = readFile(funcReturnTempletePath);
89        let funcReturnReplace = replaceAll(funcReturnTemplete, '[return_name]', retObjInfo.objName);
90        funcReturnReplace = replaceAll(funcReturnReplace, '[funcName]', funcNameReplace);
91        funcReturnReplace = replaceAll(funcReturnReplace, '[return_replace]', retGenResult);
92        bodyReplace = replaceAll(bodyReplace, '[func_return_replace]', funcReturnReplace);
93    } else {
94        bodyReplace = replaceAll(bodyReplace, '[func_return_replace]', '    return NULL;\n');
95    }
96    bodyReplace = replaceAll(bodyReplace, '[return_replace]', retGenResult);
97
98    let funcHDeclare = genFuncHDeclare(directFuncPath, funcNameReplace, hFileName, funcInfo, funcInfoParams);
99
100    return [funcHDeclare, initReplace, bodyReplace];
101}
102
103function getReplaceInfo(directFuncPath, funcInfo, funcNameReplace, hFileName) {
104  let funcBodyTempletePath = path.join(__dirname, directFuncPath.cppTempleteDetails.funcBody.funcBodyTemplete);
105  let bodyTemplete = readFile(funcBodyTempletePath);
106  let funcInfoParams = genFuncInfoParams(funcInfo);
107  let bodyReplace = replaceAll(bodyTemplete, '[funcName]', funcNameReplace);
108  bodyReplace = getBodyReplace(bodyReplace, funcNameReplace, hFileName, funcInfo, funcInfoParams);
109  return { bodyReplace, funcInfoParams };
110}
111
112function getBodyReplace(bodyReplace, funcNameReplace, hFileName, funcInfo, funcInfoParams) {
113  bodyReplace = replaceAll(bodyReplace, '[get_error_msg_tag]', funcNameReplace);
114  bodyReplace = replaceAll(bodyReplace, '[file_introduce_replace]', hFileName);
115  bodyReplace = replaceAll(bodyReplace, '[func_introduce_replace]', funcInfo.name);
116  bodyReplace = replaceAll(bodyReplace, '[input_introduce_replace]', funcInfoParams === '' ? 'void' : funcInfoParams);
117  bodyReplace = replaceAll(bodyReplace, '[output_introduce_replace]', funcInfo.retType);
118  return bodyReplace;
119}
120
121function getBodyReplace2(funcInfo, bodyReplace, genParamReplace) {
122  if (funcInfo.params.length !== 0) {
123    bodyReplace = replaceAll(bodyReplace, '[func_getParam_replace]', genParamReplace);
124  } else {
125    bodyReplace = replaceAll(bodyReplace, '[func_getParam_replace]', '');
126  }
127  return bodyReplace;
128}
129
130function getGenParamReplace(funcGetParamTemplete, funcInfo, funcNameReplace, paramGenResult) {
131  let genParamReplace = replaceAll(funcGetParamTemplete, '[param_length]', 'PARAMS' + funcInfo.params.length);
132  genParamReplace = replaceAll(genParamReplace, '[funcName]', funcNameReplace);
133  genParamReplace = replaceAll(genParamReplace, '[getParam_replace]', paramGenResult);
134  return genParamReplace;
135}
136
137function genFuncInfoParams(funcInfo) {
138  let funcInfoParams = '';
139  let funcInfoParamTemp = '[paramName]: [paramType]; ';
140  for (let i = 0; i < funcInfo.params.length; i++) {
141    let funcInfoParamReplace = replaceAll(funcInfoParamTemp, '[paramName]', funcInfo.params[i].name);
142    funcInfoParamReplace = replaceAll(funcInfoParamReplace, '[paramType]', funcInfo.params[i].type);
143    funcInfoParams += funcInfoParamReplace;
144  }
145  return funcInfoParams;
146}
147
148function genFuncHDeclare(directFuncPath, funcNameReplace, hFileName, funcInfo, funcInfoParams) {
149  let funcHDeclarePath = path.join(__dirname, directFuncPath.cppTempleteDetails.funcHDeclare.funcHDeclare);
150  let funcHDeclare = readFile(funcHDeclarePath);
151  funcHDeclare = replaceAll(funcHDeclare, '[funcName]', funcNameReplace);
152
153  funcHDeclare = replaceAll(funcHDeclare, '[file_introduce_replace]', hFileName);
154  funcHDeclare = replaceAll(funcHDeclare, '[func_introduce_replace]', funcInfo.name);
155  funcHDeclare = replaceAll(funcHDeclare, '[input_introduce_replace]', funcInfoParams === '' ? 'void' : funcInfoParams);
156  funcHDeclare = replaceAll(funcHDeclare, '[output_introduce_replace]', funcInfo.retType);
157  return funcHDeclare;
158}
159
160function genParamInfo(directFuncPath, funcInfo, params) {
161  let relativeParamGenPath = directFuncPath.cppTempleteDetails.funcBody.funcParamIn.paramGenTemplete;
162  let paramGenTempletePath = path.join(__dirname, relativeParamGenPath);
163  let paramGenTemplete = readFile(paramGenTempletePath);
164  let funcParamTypePath = directFuncPath.cppTempleteDetails.funcBody.funcParamIn.funcParamType;
165  let paramGenResult = '';
166  // napi 获取参数
167  for (let i = 0; i < funcInfo.params.length; i++) {
168    paramGenResult = getParamJs2C(funcInfo, i, paramGenTemplete, funcParamTypePath, paramGenResult, params);
169  }
170  return paramGenResult;
171}
172
173function analyzeFunction(funcInfo, params, index) {
174  funcInfo.name = params.functions[index].name;
175  funcInfo.retType = params.functions[index].rtnType;
176  let parseParams = params.functions[index].parameters;
177  for (let i = 0; i < parseParams.length; ++i) {
178    let param = createParam(parseParams[i]);
179    funcInfo.params.push(param);
180  }
181}
182
183function genInitFunction(directFuncPath, funcNameReplace) {
184  let funcInitPath = path.join(__dirname, directFuncPath.initTempleteDetails.funcInitTemplete);
185  let funcInitTemplete = readFile(funcInitPath);
186  let initReplace = replaceAll(funcInitTemplete, '[func_name_replace]', funcNameReplace);
187  return initReplace;
188}
189
190function getParamJs2C(funcInfo, i, paramGenTemplete, funcParamTypePath, paramGenResult, params) {
191  let paramType = funcInfo.params[i].type === 'size_t' ? 'int64_t' : funcInfo.params[i].type;
192  // 去除const 和 *
193  paramType = paramType.replace('const', '').replace('*', '').trim();
194  let paramName = funcInfo.params[i].name;
195  let paramGen = replaceAll(paramGenTemplete, '[param_index_replace]', 'PARAMS' + i);
196  paramGen = replaceAll(paramGen, '[param_name_replace]', paramName);
197  if (paramType === 'double') {
198    let getParamPath = path.join(__dirname, funcParamTypePath.double);
199    paramGen = getParamGenCon(getParamPath, i, paramName, paramGen);
200    paramGenResult += paramGen;
201  } else if (paramType === 'uint32_t') {
202    let getParamPath = path.join(__dirname, funcParamTypePath.uint32_t);
203    paramGen = getParamGenCon(getParamPath, i, paramName, paramGen);
204    paramGenResult += paramGen;
205  } else if (paramType === 'int32_t' || paramType === 'int') {
206    let getParamPath = path.join(__dirname, funcParamTypePath.int32_t);
207    paramGen = getParamGenCon(getParamPath, i, paramName, paramGen);
208    paramGenResult += paramGen;
209  } else if (paramType === 'int64_t' || paramType === 'size_t') {
210    let getParamPath = path.join(__dirname, funcParamTypePath.int64_t);
211    paramGen = getParamGenCon(getParamPath, i, paramName, paramGen);
212    paramGenResult += paramGen;
213  } else if (paramType === 'bool') {
214    let getParamPath = path.join(__dirname, funcParamTypePath.bool);
215    paramGen = getParamGenCon(getParamPath, i, paramName, paramGen);
216    paramGenResult += paramGen;
217  } else if (paramType === 'std::string' || paramType.indexOf('char') >= 0) {
218    let getParamPath = path.join(__dirname, funcParamTypePath.string);
219    paramGen = getParamGenCon(getParamPath, i, paramName, paramGen);
220    paramGenResult += paramGen;
221  } else if (analyzeRetIsTypeDef(paramType, params.typedefs)) { // typedefs
222    funcInfo.params[i].type = analyzeRetIsTypeDef(paramType, params.typedefs);
223    paramGenResult = getParamJs2C(funcInfo, i, paramGenTemplete, funcParamTypePath, paramGenResult, params);
224  }
225  // 其他情况,处理成对象 napi_get_cb_info之后不做任何处理
226  return paramGenResult;
227}
228
229function getParamGenCon(getParamPath, i, paramName, paramGen) {
230  let getParam = readFile(getParamPath);
231  getParam = replaceAll(getParam, '[param_index_replace]', 'PARAMS' + i);
232  getParam = replaceAll(getParam, '[param_name_replace]', paramName);
233  paramGen = replaceAll(paramGen, '[getParam_replace]', getParam);
234  return paramGen;
235}
236
237function returnTypeC2Js(funcRetOutPath, funcInfo, params, retGenResult, retObjInfo) {
238    let setRetPropertyPath = path.join(__dirname, funcRetOutPath.funcReturnType.returnObj.funcReturnObjectToSet);
239    let setRetProperty = readFile(setRetPropertyPath);
240    let returnName = funcInfo.name;
241    if (!retObjInfo.flag) {
242        retObjInfo.objName = returnName;
243    }
244    if (funcInfo.retType === 'uint32_t') {
245        let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.uint32_t);
246        retGenResult = getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty);
247    } else if (funcInfo.retType === 'double') {
248        let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.double);
249        retGenResult = getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty);
250    } else if (funcInfo.retType === 'int32_t' || funcInfo.retType === 'int') {
251        let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.int32_t);
252        retGenResult = getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty);
253    } else if (funcInfo.retType === 'int64_t' || funcInfo.retType === 'size_t') {
254        let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.int64_t);
255        retGenResult = getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty);
256    } else if (funcInfo.retType === 'bool') {
257        let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.bool);
258        retGenResult = getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty);
259    } else if (funcInfo.retType === 'std::string' || funcInfo.retType.substring(0, 10) === 'const char' ||
260          funcInfo.retType === 'char *') {
261        let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.string);
262        retGenResult = getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty);
263    } else if (analyzeRetIsObject(funcInfo.retType, params.classes)) { // 返回值是对象
264        if (!retObjInfo.flag) {
265            retGenResult = getObjRetContent(funcRetOutPath, retGenResult, returnName);
266            retObjInfo.flag = true;
267            let objectProperty = getObjectProperty(funcInfo, params);
268            // 遍历属性
269            for (let i = 0; i < objectProperty.length; i++) {
270                let testRes = returnTypeC2Js(funcRetOutPath, objectProperty[i], params, retGenResult, retObjInfo);
271                retGenResult = testRes;
272            }
273        } else {
274            retGenResult = getObjRetGenResult(retObjInfo, retGenResult, funcRetOutPath, returnName, setRetPropertyPath);
275        }
276    } else if (analyzeRetIsTypeDef(funcInfo.retType, params.typedefs)) { // typedefs
277      funcInfo.retType = analyzeRetIsTypeDef(funcInfo.retType, params.typedefs);
278      retGenResult = returnTypeC2Js(funcRetOutPath, funcInfo, params, retGenResult, retObjInfo);
279    }
280    return retGenResult;
281}
282
283function getObjectProperty(funcInfo, params) {
284  let retType = funcInfo.retType.replace('*', '').trim();
285  let objectName = '';
286  let objectProperty = [];
287
288  let myObject = params.classes[retType];
289  objectName = myObject.bare_name;
290  let myObjectProperty = myObject.properties.public;
291  for (let j = 0; j < myObjectProperty.length; j++) {
292    let propertyObj = {
293      'name': '',
294      'retType': ''
295    };
296    propertyObj.name = myObjectProperty[j].name;
297    propertyObj.retType = myObjectProperty[j].type;
298
299    objectProperty.push(propertyObj);
300  }
301  return objectProperty;
302}
303
304function getObjRetGenResult(retObjInfo, retGenResult, funcRetOutPath, returnName, setRetPropertyPath) {
305  if (retObjInfo.objName !== '') {
306    retGenResult = getObjRetContent(funcRetOutPath, retGenResult, returnName);
307    let setRetPropertyObj = readFile(setRetPropertyPath);
308    setRetPropertyObj = replaceAll(setRetPropertyObj, '[set_objname_replace]', retObjInfo.objName);
309    setRetPropertyObj = replaceAll(setRetPropertyObj, '[set_propname_replace]', returnName);
310    setRetPropertyObj = replaceAll(setRetPropertyObj, '[set_propvalue_replace]', returnName);
311    retGenResult += setRetPropertyObj;
312  }
313  return retGenResult;
314}
315
316function getObjRetContent(funcRetOutPath, retGenResult, returnName) {
317  let funcReturnTypePath = path.join(__dirname, funcRetOutPath.funcReturnType.returnObj.object);
318  let funcReturnType = readFile(funcReturnTypePath);
319  retGenResult += replaceAll(funcReturnType, '[return_name_replace]', returnName);
320  return retGenResult;
321}
322
323function getRetTypeContent(funcReturnTypePath, returnName, retGenResult, retObjInfo, setRetProperty) {
324  let funcReturnType = readFile(funcReturnTypePath);
325  funcReturnType = replaceAll(funcReturnType, '[return_name_replace]', returnName);
326  retGenResult += funcReturnType;
327  if (retObjInfo.flag) {
328    setRetProperty = replaceAll(setRetProperty, '[set_objname_replace]', retObjInfo.objName);
329    setRetProperty = replaceAll(setRetProperty, '[set_propname_replace]', returnName);
330    setRetProperty = replaceAll(setRetProperty, '[set_propvalue_replace]', returnName);
331    retGenResult += setRetProperty;
332  }
333  return retGenResult;
334}
335
336function replaceAll(s, sfrom, sto) {
337    while (s.indexOf(sfrom) >= 0) {
338        s = s.replace(sfrom, sto);
339    }
340    return s;
341}
342
343function createParam(parseParamInfo) {
344    let param = {
345        'name': '',
346        'type': ''
347    };
348    param.name = parseParamInfo.name;
349    param.type = parseParamInfo.type;
350    return param;
351}
352
353module.exports = {
354    generateDirectFunction
355};