package itn.com.utl.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.ui.ModelMap;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class AopExpressionHelper {

    private static final ExpressionParser PARSER = new SpelExpressionParser();
    private static final Map<String, Expression> EXPRESSION_CACHE = new ConcurrentHashMap<String, Expression>();

    private AopExpressionHelper() {
    }

    public static EvaluationContext createContext(JoinPoint joinPoint, MethodSignature signature) {

        StandardEvaluationContext context = new StandardEvaluationContext();

        Object[] args = joinPoint.getArgs();
        String[] names = signature.getParameterNames();

        if (names != null) {
            for (int i = 0; i < names.length; i++) {
                context.setVariable(names[i], args[i]);
            }
        }

        for (Object arg : args) {
            if (arg instanceof ModelMap) {
                ModelMap model = (ModelMap) arg;

                for (Map.Entry<String, Object> entry : model.entrySet()) {
                    context.setVariable(entry.getKey(), entry.getValue());
                }
            }
        }

        return context;
    }

    public static Object evaluate(EvaluationContext context, String expression) {

        if (!hasText(expression)) {
            return null;
        }

        Expression compiled = EXPRESSION_CACHE.get(expression);

        if (compiled == null) {
            Expression parsed = PARSER.parseExpression(expression);

            Expression existing = EXPRESSION_CACHE.putIfAbsent(expression, parsed);

            compiled = existing != null
                    ? existing
                    : parsed;
        }

        return compiled.getValue(context);
    }

    public static boolean hasText(String value) {
        return value != null && !value.trim().isEmpty();
    }
}
