package com.eworkplus.dal.core.build.ognl;

import com.eworkplus.dal.core.exception.DataAccessErrorCodes;
import com.eworkplus.dal.utils.exception.InternalException;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import org.springframework.util.CollectionUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Calculate and cache OGNL parsed expressions
 * <br>
 * Created by taoping on 2017/2/10.
 */
public class OgnlCalculator {
    private static final Map<String, Object> expressionCache = new ConcurrentHashMap<String, Object>();

    private OgnlCalculator() {

    }

    public static Object getValue(String expression, Object root) {
        Object result = null;
        try {
            Map<?, ?> context = Ognl.createDefaultContext(
                    root,
                    new DefaultMemberAccess(false),
                    new OgnlClassResolver(), null);
            result = Ognl.getValue(parse(expression), context, root);
        } catch (OgnlException e) {
            throw InternalException.create(DataAccessErrorCodes.BUILD_ERROR, String.format("Get value error, ognl expression : %s. Cause : %s", expression, e.getMessage()), e);
        }
        return result;
    }

    public static Object getValue(String expression, Object root, Map<String, Object> others) {
        Object result = null;
        try {
            OgnlContext context = (OgnlContext) Ognl.createDefaultContext(
                    root,
                    new DefaultMemberAccess(false),
                    new OgnlClassResolver(), null);
            if (!CollectionUtils.isEmpty(others)) {
                context.putAll(others);
            }
            result = Ognl.getValue(parse(expression), context, context.getRoot());
        } catch (OgnlException e) {
            throw InternalException.create(DataAccessErrorCodes.BUILD_ERROR, String.format("Get value error, ognl expression : %s. Cause : %s", expression, e.getMessage()), e);
        }
        return result;
    }

    private static Object parse(String expression) throws OgnlException {
        if (expressionCache.containsKey(expression)) {
            return expressionCache.get(expression);
        } else {
            Object node = Ognl.parseExpression(expression);
            expressionCache.put(expression, node);
            return node;
        }
    }
}
