package cn.axzo.msg.center.common.template;

import cn.axzo.basics.common.exception.ServiceException;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.expression.Expression;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;

/**
 * 支持级联: person.addresses[1].info
 *
 * @author yanglin
 */
@Slf4j
public class TemplateParser {

    public static String parseNumberSign(String expression, Object root) {
        return parseImpl("#{", "}", expression, root);
    }

    public static String parseDollarSign(String expression, Object root) {
        return parseImpl("${", "}", expression, root);
    }

    @SuppressWarnings("SameParameterValue")
    private static String parseImpl(String openToken, String closeToken, String expression, Object root) {
        if (expression == null || root == null)
            return expression;
        try {
            StandardEvaluationContext evalContext = new StandardEvaluationContext(root);
            evalContext.addPropertyAccessor(AbsentKeyMapAccessor.INSTANCE);
            evalContext.addPropertyAccessor(new ReflectivePropertyAccessor(false));
            evalContext.addPropertyAccessor(NullPropertyAccessor.INSTANCE);
            TemplateParserContext templateContext = new TemplateParserContext(openToken, closeToken);
            // turn off java native
            SpelParserConfiguration parseCfg = new SpelParserConfiguration(
                    SpelCompilerMode.OFF, TemplateParser.class.getClassLoader());
            Expression exp = new SpelExpressionParser(parseCfg).parseExpression(expression, templateContext);
            Object value = exp.getValue(evalContext);
            // 不返回空字符串, 返回null形象点
            if (value == null)
                return "null";
            return value instanceof String ? (String) value : String.valueOf(value);
        } catch (Exception e) {
            log.warn("无效的模版内容, 请检查格式是否正确. expression={}, value={}",
                    expression, JSON.toJSONString(root), e);
            throw new ServiceException(String.format("无效的模版内容, 请检查格式是否正确. expression=%s, value=%s",
                    expression, JSON.toJSONString(root)));
        }
    }

}