package org.mvel.block;

import org.mvel.CompileException;
import org.mvel.ExecutableStatement;
import static org.mvel.MVEL.compileExpression;
import static org.mvel.MVEL.setProperty;
import org.mvel.integration.VariableResolver;
import org.mvel.integration.VariableResolverFactory;
import static org.mvel.util.ParseTools.balancedCapture;
import static org.mvel.util.ParseTools.subset;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Christopher Brock
 */
public class WithToken extends BlockToken {

    private String name;
    private ParmValuePair[] withExpressions;

    public WithToken(char[] expr, char[] block, int fields) {
        super(expr, fields, block);
        name = new String(expr).trim();

        System.out.println("<<" + new String(block) + ">>");

        compileWithExpressions();
    }


    public Object getReducedValueAccelerated(Object ctx, Object thisValue, VariableResolverFactory factory) {
        VariableResolver resolver = factory.getVariableResolver(name);
        if (resolver == null) {
            throw new CompileException("no such variable for with block: " + name);
        }

        Object ctxObject = resolver.getValue();

        for (ParmValuePair pvp : withExpressions) {
            setProperty(ctxObject, pvp.getParameter(), pvp.getStatement().getValue(ctx, thisValue, factory));
        }

        return Void.class;
    }


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

    private void compileWithExpressions() {
        List<ParmValuePair> parms = new ArrayList<ParmValuePair>();

        int start = 0;
        String parm = "";

        for (int i = 0; i < block.length; i++) {
            switch (block[i]) {
                case'{':
                case'[':
                case'(':
                    if ((i = balancedCapture(block, i, block[i])) == -1) {
                        throw new CompileException("unbalanced braces", block, i);
                    }
                    break;

                case'=':
                    parm = new String(block, start, i - start).trim();
                    start = ++i;
                    break;

                case',':
                    if (parm == null) {
                        throw new CompileException("invalid syntax, expected =", block, i);
                    }

                    parms.add(new ParmValuePair(
                            parm,
                            (ExecutableStatement) compileExpression(subset(block, start, i - start)))
                    );

                    parm = null;
                    start = ++i;

                    break;
            }
        }

        if (parm != null && start != block.length) {
            parms.add(new ParmValuePair(
                    parm,
                    (ExecutableStatement) compileExpression(subset(block, start, block.length - start)))
            );
        }

        parms.toArray(withExpressions = new ParmValuePair[parms.size()]);
    }

    public static final class ParmValuePair {
        private String parameter;
        private ExecutableStatement statement;

        public ParmValuePair() {
        }

        public ParmValuePair(String parameter, ExecutableStatement statement) {
            System.out.println("adding parm [" + parameter + "]");
            this.parameter = parameter;
            this.statement = statement;
        }

        public String getParameter() {
            return parameter;
        }

        public void setParameter(String parameter) {
            this.parameter = parameter;
        }

        public ExecutableStatement getStatement() {
            return statement;
        }

        public void setStatement(ExecutableStatement statement) {
            this.statement = statement;
        }
    }

}

@@ -89,24 +89,47 @@
 Statement;%0D%0A
+import org.mvel.MVEL;%0D%0A
 import stati
@@ -210,55 +210,8 @@
 y;%0D%0A
-import org.mvel.integration.VariableResolver;%0D%0A
 impo
@@ -525,19 +525,35 @@
 ate 
-String name
+ExecutableStatement context
 ;%0D%0A 
@@ -699,24 +699,26 @@
 lock);%0D%0A
+%0D%0A
         
 name = n
@@ -713,101 +713,86 @@
     
-name = new String(expr).trim();%0D%0A%0D%0A        System.out.println(%22%3C%3C%22 + new String(block) + %22%3E%3E%22
+context = (ExecutableStatement) MVEL.compileExpression(new String(expr).trim()
 );%0D%0A
@@ -962,248 +962,67 @@
     
-VariableResolver resolver = factory.getVariableResolver(name);%0D%0A        if (resolver == null) %7B%0D%0A            throw new CompileException(%22no such variable for with block: %22 + name);%0D%0A        %7D%0D%0A%0D%0A        Object ctxObject = resolver.getValue(
+Object ctxObject = context.getValue(ctx, thisValue, factory
 );%0D%0A
@@ -3253,76 +3253,8 @@
  %7B%0D%0A
-            System.out.println(%22adding parm %5B%22 + parameter + %22%5D%22);%0D%0A
     

fix to semantics of WITH