package com.hubspot.jinjava.el;

import static org.apache.commons.lang3.exception.ExceptionUtils.getRootCauseMessage;

import java.util.List;

import javax.el.ELException;
import javax.el.ELResolver;
import javax.el.ExpressionFactory;
import javax.el.PropertyNotFoundException;
import javax.el.ValueExpression;

import org.apache.commons.lang3.StringUtils;

import com.hubspot.jinjava.interpret.InterpretException;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.interpret.TemplateError;
import com.hubspot.jinjava.interpret.TemplateError.ErrorReason;
import com.hubspot.jinjava.interpret.TemplateError.ErrorType;
import com.hubspot.jinjava.interpret.TemplateSyntaxException;
import com.hubspot.jinjava.lib.fn.ELFunctionDefinition;
import de.odysseus.el.tree.TreeBuilderException;

public class ExpressionResolver {

  private final JinjavaInterpreter interpreter;
  private final ExpressionFactory expressionFactory;
  private final JinjavaELContext elContext;

  public ExpressionResolver(JinjavaInterpreter interpreter, ExpressionFactory expressionFactory) {
    this.interpreter = interpreter;
    this.expressionFactory = expressionFactory;

    this.elContext = new JinjavaELContext(new JinjavaInterpreterResolver(interpreter));
    for (ELFunctionDefinition fn : interpreter.getContext().getAllFunctions()) {
      this.elContext.setFunction(fn.getNamespace(), fn.getLocalName(), fn.getMethod());
    }
  }

  public Object resolveExpression(String expr) {
    if (StringUtils.isBlank(expr)) {
      return "";
    }

    try {
      String elExpression = "#{" + expr.trim() + "}";
      ValueExpression valueExp = expressionFactory.createValueExpression(elContext, elExpression, Object.class);
      return valueExp.getValue(elContext);

    } catch (PropertyNotFoundException e) {
      interpreter.addError(new TemplateError(ErrorType.WARNING, ErrorReason.UNKNOWN, e.getMessage(), "", interpreter.getLineNumber(), e));
    } catch (TreeBuilderException e) {
      interpreter.addError(TemplateError.fromException(new TemplateSyntaxException(expr,
          "Error parsing '" + expr + "': " + StringUtils.substringAfter(e.getMessage(), "': "), interpreter.getLineNumber(), e)));
    } catch (ELException e) {
      interpreter.addError(TemplateError.fromException(new TemplateSyntaxException(expr, e.getMessage(), interpreter.getLineNumber(), e)));
    } catch (Exception e) {
      interpreter.addError(TemplateError.fromException(new InterpretException(
          String.format("Error resolving expression [%s]: " + getRootCauseMessage(e), expr), e, interpreter.getLineNumber())));
    }

    return "";
  }

  public Object resolveProperty(Object base, List<String> chain) {
    ELResolver resolver = elContext.getELResolver();

    Object value = base;
    for (String name : chain) {
      if (value == null) {
        return null;
      }

      value = resolver.getValue(elContext, value, name);
    }

    return value;
  }
}

@@ -811,16 +811,55 @@
 ption;%0A%0A
+/**%0A * Resolves Jinja expressions.%0A */%0A
 public c
@@ -1479,24 +1479,165 @@
 %0A    %7D%0A  %7D%0A%0A
+  /**%0A   * Resolve expression against current context.%0A   *%0A   * @param expression Jinja expression.%0A   * @return Value of expression.%0A   */%0A
   public Obj
@@ -1669,16 +1669,22 @@
 ing expr
+ession
 ) %7B%0A    
@@ -1711,16 +1711,22 @@
 ank(expr
+ession
 )) %7B%0A   
@@ -1795,16 +1795,22 @@
 %22 + expr
+ession
 .trim() 
@@ -2282,16 +2282,22 @@
 ion(expr
+ession
 ,%0A      
@@ -2324,16 +2324,22 @@
 %22 + expr
+ession
  + %22': %22
@@ -2544,16 +2544,22 @@
 ion(expr
+ession
 , e.getM
@@ -2800,16 +2800,22 @@
 e), expr
+ession
 ), e, in
@@ -2871,16 +2871,191 @@
 %22;%0A  %7D%0A%0A
+  /**%0A   * Resolve property of bean.%0A   *%0A   * @param object Bean.%0A   * @param propertyNames Names of properties to resolve recursively.%0A   * @return Value of property.%0A   */%0A
   public
@@ -3085,20 +3085,22 @@
 (Object 
-base
+object
 , List%3CS
@@ -3106,21 +3106,29 @@
 String%3E 
-chain
+propertyNames
 ) %7B%0A    
@@ -3200,12 +3200,14 @@
 e = 
-base
+object
 ;%0A  
@@ -3224,20 +3224,36 @@
 ing 
-name : chain
+propertyName : propertyNames
 ) %7B%0A
@@ -3359,17 +3359,25 @@
  value, 
-n
+propertyN
 ame);%0A  

Add javadoc