package com.hubspot.jinjava.el.ext;

import de.odysseus.el.misc.TypeConverter;
import de.odysseus.el.tree.impl.Parser.ExtensionHandler;
import de.odysseus.el.tree.impl.Parser.ExtensionPoint;
import de.odysseus.el.tree.impl.Scanner;
import de.odysseus.el.tree.impl.ast.AstBinary;
import de.odysseus.el.tree.impl.ast.AstBinary.SimpleOperator;
import de.odysseus.el.tree.impl.ast.AstNode;
import java.util.Collection;
import java.util.Objects;
import javax.el.ELException;
import org.apache.commons.lang3.StringUtils;

public class CollectionMembershipOperator extends SimpleOperator {

  @Override
  public Object apply(TypeConverter converter, Object o1, Object o2) {
    if (o2 == null) {
      return Boolean.FALSE;
    }

    if (CharSequence.class.isAssignableFrom(o2.getClass())) {
      return StringUtils.contains((CharSequence) o2, Objects.toString(o1, ""));
    }

    if (Collection.class.isAssignableFrom(o2.getClass())) {
      Collection<?> collection = (Collection<?>) o2;

      for (Object value : collection) {
        if (value == null) {
          if (o1 == null) {
            return Boolean.TRUE;
          }
        } else {
          try {
            return collection.contains(converter.convert(o1, value.getClass()));
          } catch (ELException e) {
            return Boolean.FALSE;
          }
        }
      }
    }

    return Boolean.FALSE;
  }

  public static final CollectionMembershipOperator OP = new CollectionMembershipOperator();
  public static final Scanner.ExtensionToken TOKEN = new Scanner.ExtensionToken("in");

  public static final ExtensionHandler HANDLER = new ExtensionHandler(
    ExtensionPoint.CMP
  ) {

    @Override
    public AstNode createAstNode(AstNode... children) {
      return new AstBinary(children[0], children[1], OP);
    }
  };
}

@@ -404,24 +404,46 @@
 Collection;%0A
+import java.util.Map;%0A
 import java.
@@ -1361,24 +1361,376 @@
    %7D%0A    %7D%0A%0A
+    if (Map.class.isAssignableFrom(o2.getClass())) %7B%0A      Map map = (Map) o2;%0A      if (!map.isEmpty()) %7B%0A        try %7B%0A          Class%3C?%3E keyClass = map.keySet().iterator().next().getClass();%0A          return map.containsKey(converter.convert(o1, keyClass));%0A        %7D catch (ELException e) %7B%0A          return Boolean.FALSE;%0A        %7D%0A      %7D%0A    %7D%0A%0A
     return B

Support IN operator for dictionaries