package org.mvel.ast;

import org.mvel.CompileException;
import org.mvel.ExecutableStatement;
import org.mvel.integration.VariableResolverFactory;
import org.mvel.integration.impl.DefaultLocalVariableResolverFactory;
import org.mvel.integration.impl.ItemResolverFactory;
import static org.mvel.util.ParseTools.subCompileExpression;
import static org.mvel.util.ParseTools.subset;

/**
 * @author Christopher Brock
 */
public class ForEachNode extends BlockNode {
    protected String item;
    protected ExecutableStatement condition;
    protected ExecutableStatement compiledBlock;

    public ForEachNode(char[] condition, char[] block, int fields) {
        super(condition, fields);
        handleCond(condition);
        this.compiledBlock = (ExecutableStatement) subCompileExpression(this.block = block);
    }

    public Object getReducedValueAccelerated(Object ctx, Object thisValue, VariableResolverFactory factory) {
        //   Object ret = null;

        ItemResolverFactory.ItemResolver itemR = new ItemResolverFactory.ItemResolver(item);
        ItemResolverFactory itemFactory = new ItemResolverFactory(itemR, new DefaultLocalVariableResolverFactory(factory));

        Object iterCond = condition.getValue(ctx, thisValue, factory);

        if (iterCond instanceof Iterable) {
            for (Object o : (Iterable) iterCond) {
                itemR.setValue(o);
                compiledBlock.getValue(ctx, thisValue, itemFactory);
            }
        }
        else if (iterCond instanceof Object[]) {
            for (Object o : (Object[]) iterCond) {
                itemR.setValue(o);
                compiledBlock.getValue(ctx, thisValue, itemFactory);
            }
        }
        else if (iterCond instanceof CharSequence) {
            for (Object o : iterCond.toString().toCharArray()) {
                itemR.setValue(o);
                compiledBlock.getValue(ctx, thisValue, itemFactory);
            }
        }
        else if (iterCond instanceof Integer) {
            int max = (Integer) iterCond + 1;
            for (int i = 1; i != max; i++) {
                itemR.setValue(i);
                compiledBlock.getValue(ctx, thisValue, itemFactory);
            }
        }
        else {
            throw new CompileException("non-iterable type: " + iterCond.getClass().getName());
        }

        return null;
    }

    public Object getReducedValue(Object ctx, Object thisValue, VariableResolverFactory factory) {
        return getReducedValueAccelerated(ctx, thisValue, factory);
    }

    private void handleCond(char[] condition) {
        int cursor = 0;
        while (cursor < condition.length && condition[cursor] != ':') cursor++;

        if (cursor == condition.length || condition[cursor] != ':')
            throw new CompileException("expected : in foreach");

        item = new String(condition, 0, cursor).trim();

        //  cursor++;

        this.condition = (ExecutableStatement) subCompileExpression(subset(condition, ++cursor));
    }
}

@@ -91,16 +91,39 @@
 ement;%0D%0A
+import org.mvel.MVEL;%0D%0A
 import o
@@ -160,32 +160,32 @@
 solverFactory;%0D%0A
-
 import org.mvel.
@@ -519,16 +519,44 @@
 g item;%0D
+%0A%0D%0A    private char%5B%5D cond;%0D
 %0A    pro
@@ -2564,32 +2564,34 @@
 ory factory) %7B%0D%0A
+//
         return g
@@ -2638,24 +2638,1449 @@
 , factory);%0D
+%0A%0D%0A        ItemResolverFactory.ItemResolver itemR = new ItemResolverFactory.ItemResolver(item);%0D%0A        ItemResolverFactory itemFactory = new ItemResolverFactory(itemR, new DefaultLocalVariableResolverFactory(factory));%0D%0A%0D%0A        Object iterCond = MVEL.eval(cond, thisValue, factory);%0D%0A%0D%0A        if (iterCond instanceof Iterable) %7B%0D%0A            for (Object o : (Iterable) iterCond) %7B%0D%0A                itemR.setValue(o);%0D%0A                compiledBlock.getValue(ctx, thisValue, itemFactory);%0D%0A            %7D%0D%0A        %7D%0D%0A        else if (iterCond instanceof Object%5B%5D) %7B%0D%0A            for (Object o : (Object%5B%5D) iterCond) %7B%0D%0A                itemR.setValue(o);%0D%0A                compiledBlock.getValue(ctx, thisValue, itemFactory);%0D%0A            %7D%0D%0A        %7D%0D%0A        else if (iterCond instanceof CharSequence) %7B%0D%0A            for (Object o : iterCond.toString().toCharArray()) %7B%0D%0A                itemR.setValue(o);%0D%0A                compiledBlock.getValue(ctx, thisValue, itemFactory);%0D%0A            %7D%0D%0A        %7D%0D%0A        else if (iterCond instanceof Integer) %7B%0D%0A            int max = (Integer) iterCond + 1;%0D%0A            for (int i = 1; i != max; i++) %7B%0D%0A                itemR.setValue(i);%0D%0A                compiledBlock.getValue(ctx, thisValue, itemFactory);%0D%0A            %7D%0D%0A        %7D%0D%0A        else %7B%0D%0A            throw new CompileException(%22non-iterable type: %22 + iterCond.getClass().getName());%0D%0A        %7D%0D%0A%0D%0A        return null;%0D
 %0A    %7D%0D%0A%0D%0A  
@@ -4447,32 +4447,32 @@
 /  cursor++;%0D%0A%0D%0A
-
         this.con
@@ -4523,16 +4523,28 @@
 ression(
+this.cond = 
 subset(c

disable JIT compiler for interpreted foreach loops.