package com.jfeng.protocol.template.engine;
import com.jfeng.protocol.annotation.SelectDisplayType;
import com.jfeng.protocol.buildin.car.none4.NoneRoad4;
import com.jfeng.protocol.comm.ByteOrderEnum;
import com.jfeng.protocol.comm.Protocolable;
import com.jfeng.protocol.template.*;
import com.jfeng.protocol.template.parse.TemplateParser;
import com.jfeng.protocol.template.result.ByteResult;
import com.jfeng.protocol.template.result.TemplateResult;
import com.jfeng.protocol.util.ByteUtils;
import com.jfeng.protocol.util.ExpressUtils;
import com.jfeng.protocol.util.StringUtils;
import io.netty.buffer.ByteBufUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
/**
* 模板执行引擎(调试)
*/
public class TemplateEngine {
private Logger logger = LoggerFactory.getLogger(TemplateEngine.class);
public TemplateResult autoDecode(String value) throws Exception {
byte[] bytes = ByteBufUtil.decodeHexDump(value);
Class<?> protocolTemplate = null;
for (Protocolable protocolable : ServiceLoader.load(Protocolable.class)) {
if (protocolable.accept(bytes)) {
protocolTemplate = protocolable.getClass();
}
}
return decode(bytes, protocolTemplate);
}
public TemplateResult decode(String value, Class<?> protocolTemplate) throws Exception {
return this.decode(ByteBufUtil.decodeHexDump(value), protocolTemplate);
}
public TemplateResult decode(byte[] value, Class<?> protocolTemplate) throws Exception {
return this.decode(value, TemplateParser.parse(protocolTemplate));
}
public TemplateResult decode(byte[] value, ContainTemplate<TemplateItem> rootTemplate) throws Exception {
TemplateResult parent = new TemplateResult(rootTemplate, value.length);
Context context = new Context(value);
for (TemplateItem child : rootTemplate.children) {
TemplateResult childResult = decode(parent, context, child);
parent.addChild(childResult);
if (context.isStop()) {
break;
}
}
parent.handleLength();
parent.handleDisplay();
return parent;
}
/**
* 计算当前限制长度,有很多变长字段受限于上级长度,当上级也是变长时,则需要递归上级获取最终长度
* 递归的最终限制长度会是value.length
*
* @param parent 上级容器解析结果
* @param offset 当前偏移量
* @param limitLength 当前允许的最大长度
* @return
*/
public int getLimitCapacity(TemplateResult parent, int offset, int limitLength) {
if (limitLength > 0) {
return offset + limitLength;
} else if (parent != null && parent.length > 0) {
return parent.offset + parent.length;
} else {
return getLimitCapacity(parent.parent, offset, limitLength);
}
}
/**
* 解析单个模板对象
*
* @param parentResult 上级解析结果,两种情况用到该字段:1、当字段的数据来自另一个属性 2、需要在上级解析结果中插入额外信息
* @param context 执行上行文,保存当前游标
* @param template 模板
* @return 模板对应的解析结果
* @throws Exception
*/
public TemplateResult decode(TemplateResult parentResult, Context context, TemplateItem template) throws Exception {
int actualLength = calcLength(template, context.value, context.offset, parentResult);
int limit = getLimitCapacity(parentResult, context.offset, actualLength);
//1.before //TODO 提取通用操作
if (actualLength > 0) {
if (template.aopProcess != null) {
template.aopProcess.beforeProcess(context.value, context.offset, actualLength);
}
}
if (template.itemType == TemplateType.DATA) {
DataTemplate dataTemplate = ((DataTemplate) template);
try {
if (dataTemplate.isBit()) {
byte[] bitStore = ByteUtils.buildBitStore(context.currentParent, dataTemplate.byteOrder == ByteOrderEnum.BIG_EDIAN);
String value = dataTemplate.decode(bitStore, context.bitOffset, actualLength);
TemplateResult result = new TemplateResult(parentResult, dataTemplate, value, context.bitOffset, actualLength);
context.increaseBit(actualLength);
return result;
} else {
String value = dataTemplate.decode(context.value, context.offset, actualLength);
TemplateResult result = new TemplateResult(parentResult, dataTemplate, value, context.offset, actualLength);
context.increase(actualLength);
return result;
}
} catch (Exception e) {
logger.warn("解析报错", e);
context.stop();
return TemplateResult.fail(dataTemplate, e.getMessage());
}
} else if (template.itemType == TemplateType.LOOP) {
LoopTemplate loopTemplate = (LoopTemplate) template;
int num = loopTemplate.getNum(parentResult);
TemplateResult result = new TemplateResult(parentResult, loopTemplate,
num == Integer.MAX_VALUE ? "(N/A)" : String.valueOf(num),
context.offset);
for (int i = 0; i < num; i++) {
if (context.isStop(limit)) {
break;
}
if (loopTemplate.loopType == LoopType.CUSTOM
&& loopTemplate.loopPredicate.test(String.valueOf(context.value[context.offset]))) {
break;
}
TemplateResult eachElement = new TemplateResult(result, loopTemplate, "", context.offset);
eachElement.name = loopTemplate.name + " " + (i + 1);
eachElement.display = loopTemplate.autoGenerateElementContain;
for (TemplateItem child : loopTemplate.children) {
if (context.isStop(limit)) {
break;
}
eachElement.addChild(decode(eachElement, context, child));
}
eachElement.handleLength();
result.addChild(eachElement);
}
result.handleLength();
return result;
} else if (template.itemType == TemplateType.SELECT) {
SelectTemplate selectTemplate = ((SelectTemplate) template);
String selectedKey = StringUtils.isNotEmpty(selectTemplate.compareKey)
? parentResult.searchChild(selectTemplate.compareKey)
: "";
ConditionTemplate matchCondition = null;
for (ConditionTemplate child : selectTemplate.children) {
if (context.isStop()) {
break;
}
String conditionKey = StringUtils.isNotEmpty(child.compareKey) ? parentResult.searchChild(child.compareKey) : "";
if (StringUtils.isEmpty(selectedKey) && StringUtils.isEmpty(conditionKey)) {
context.stop = true;
return TemplateResult.fail(selectTemplate, "未找到需要比较的值");
}
if (child.operator.test(StringUtils.isNotEmpty(conditionKey) ? conditionKey : selectedKey)) {
matchCondition = child;
break;
}
}
if (matchCondition == null) {
if (selectTemplate.throwExceptionIfNotFound) {
context.stop();
return TemplateResult.fail(selectTemplate, "未找到符合条件的解析�