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 value, Object iterable) {
    if (iterable == null) {
      return Boolean.FALSE;
    }

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

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

      for (Object element : collection) {
        if (element == null) {
          if (value == null) {
            return Boolean.TRUE;
          }
        } else {
          try {
            return collection.contains(converter.convert(value, element.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,51 @@
 Collection;%0A
+import java.util.Iterator;%0A
 import java.
@@ -684,17 +684,22 @@
  Object 
-i
+maybeI
 terable)
@@ -709,17 +709,22 @@
     if (
-i
+maybeI
 terable 
@@ -805,33 +805,38 @@
 sAssignableFrom(
-i
+maybeI
 terable.getClass
@@ -876,16 +876,25 @@
 ontains(
+%0A        
 (CharSeq
@@ -904,17 +904,22 @@
 ce) 
-i
+maybeI
 terable,
  Obj
@@ -914,16 +914,24 @@
 terable,
+%0A       
  Objects
@@ -950,16 +950,23 @@
 lue, %22%22)
+%0A      
 );%0A    %7D
@@ -1009,17 +1009,22 @@
 bleFrom(
-i
+maybeI
 terable.
@@ -1087,17 +1087,22 @@
 ion%3C?%3E) 
-i
+maybeI
 terable;
@@ -1472,24 +1472,543 @@
      %7D%0A    %7D
+ else if (maybeIterable instanceof Iterable) %7B%0A      for (Object element : (Iterable) maybeIterable) %7B%0A        if (element == null) %7B%0A          if (value == null) %7B%0A            return true;%0A          %7D%0A        %7D else %7B%0A          try %7B%0A            Object castedValue = converter.convert(value, element.getClass());%0A            if (element.equals(castedValue)) %7B%0A              return true;%0A            %7D%0A          %7D catch (ELException e) %7B%0A            return false;%0A          %7D%0A        %7D%0A      %7D%0A      return false;%0A    %7D
 %0A%0A    return

Allow membership to work with iterables like dicts