package org.mvel2.tests.core;

import org.mvel2.tests.core.res.Base;
import org.mvel2.integration.PropertyHandlerFactory;
import org.mvel2.integration.PropertyHandler;
import org.mvel2.integration.VariableResolverFactory;
import org.mvel2.PropertyAccessor;
import org.mvel2.MVEL;
import org.mvel2.asm.MethodVisitor;
import org.mvel2.asm.Label;
import org.mvel2.optimizers.OptimizerFactory;
import org.mvel2.optimizers.impl.asm.ProducesBytecode;
import junit.framework.TestCase;

import java.util.List;
import java.util.Map;
import java.lang.reflect.Array;
import java.io.Serializable;

import static org.mvel2.asm.Opcodes.*;


public class PropertyHandlerTests extends TestCase {
    Base base = new Base();

    public class TestPropertyHandler implements PropertyHandler, ProducesBytecode {
        public Object getProperty(String name, Object contextObj,
                                  VariableResolverFactory variableFactory) {
            assertNotNull(contextObj);
            assertEquals("0", name);
            assertTrue(contextObj instanceof List);
            return "gotcalled";
        }

        public Object setProperty(String name, Object contextObj,
                                  VariableResolverFactory variableFactory, Object value) {
            assertNotNull(contextObj);
            assertEquals("0", name);
            assertTrue(contextObj instanceof List);
            ((List) contextObj).set(0, "set");
            return null;
        }

        public void produceBytecodeGet(MethodVisitor mv, String propertyName, VariableResolverFactory factory) {
            mv.visitLdcInsn("gotcalled");
        }

        public void produceBytecodePut(MethodVisitor mv, String propertyName, VariableResolverFactory factory) {
            mv.visitTypeInsn(CHECKCAST, "java/util/List");
            mv.visitInsn(ICONST_0);
            mv.visitLdcInsn("set");
            mv.visitMethodInsn(INVOKEINTERFACE, "java/util/List", "set", "(ILjava/lang/Object;)Ljava/lang/Object;");
            mv.visitInsn(POP);
            mv.visitInsn(ACONST_NULL);
        }
    }


    @Override
    protected void setUp() throws Exception {
        PropertyHandlerFactory.registerPropertyHandler(List.class, new TestPropertyHandler());
    }

    public void testListPropertyHandler() {
        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;


        assertEquals("gotcalled", PropertyAccessor.get("list[0]", base));

        PropertyAccessor.set(base, "list[0]", "hey you");
        assertEquals("set", base.list.get(0));

        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = false;
    }

    public void testListPropertyHandler2() {
        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;

        Serializable s = MVEL.compileSetExpression("list[0]");

        Base b;
        MVEL.executeSetExpression(s, new Base(), "hey you");
        MVEL.executeSetExpression(s, b = new Base(), "hey you");

        assertEquals("set", b.list.get(0));
    }

    public void testListPropertyHandler3() {
        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;

        OptimizerFactory.setDefaultOptimizer("ASM");

        Serializable s = MVEL.compileSetExpression("list[0]");

        Base b;
        MVEL.executeSetExpression(s, new Base(), "hey you");
        MVEL.executeSetExpression(s, b = new Base(), "hey you");

        assertEquals("set", b.list.get(0));
    }


    public void testMapPropertyHandler() {
        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;


        PropertyHandlerFactory.registerPropertyHandler(Map.class, new
                PropertyHandler() {
                    public Object getProperty(String name, Object contextObj,
                                              VariableResolverFactory variableFactory) {
                        assertNotNull(contextObj);
                        assertEquals("'key'", name);
                        assertTrue(contextObj instanceof Map);
                        return "gotcalled";
                    }

                    public Object setProperty(String name, Object contextObj,
                                              VariableResolverFactory variableFactory, Object value) {
                        assertNotNull(contextObj);
                        assertEquals("'key'", name);
                        assertTrue(contextObj instanceof Map);
                        ((Map) contextObj).put("key", "set");
                        return null;
                    }
                });

        assertEquals("gotcalled", PropertyAccessor.get("funMap['key']", base));

        PropertyAccessor.set(base, "funMap['key']", "hey you");
        assertEquals("set", base.funMap.get("key"));

        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = false;

    }

    public void testArrayPropertyHandler() {

        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;

        PropertyHandlerFactory.registerPropertyHandler(Array.class, new
                PropertyHandler() {
                    public Object getProperty(String name, Object contextObj,
                                              VariableResolverFactory variableFactory) {
                        assertNotNull(contextObj);
                        assertEquals("0", name);
                        assertTrue(contextObj.getClass().isArray());
                        return "gotcalled";
                    }

                    public Object setProperty(String name, Object contextObj,
                                              VariableResolverFactory variableFactory, Object value) {
                        assertNotNull(contextObj);
                        assertEquals("0", name);
                        assertTrue(contextObj.getClass().isArray());
                        Array.set(contextObj, 0, "set");
                        return null;
                    }
                });

        assertEquals("gotcalled", PropertyAccessor.get("stringArray[0]", base));

        PropertyAccessor.set(base, "stringArray[0]", "hey you");
        assertEquals("set", base.stringArray[0]);

        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = false;
    }
}
@@ -95,130 +95,9 @@
 ion.
-PropertyHandlerFactory;%0Aimport org.mvel2.integration.PropertyHandler;%0Aimport org.mvel2.integration.VariableResolverFactory
+*
 ;%0Aim
@@ -3281,24 +3281,883 @@
 0));%0A    %7D%0A%0A
+    public void testListPropertyHandler4() %7B%0A        MVEL.COMPILER_OPT_ALLOW_OVERRIDE_ALL_PROPHANDLING = true;%0A%0A        OptimizerFactory.setDefaultOptimizer(%22ASM%22);%0A%0A        final String%5B%5D res = new String%5B1%5D;%0A%0A        GlobalListenerFactory.registerGetListener(new Listener() %7B%0A            public void onEvent(Object context, String contextName, VariableResolverFactory variableFactory, Object value) %7B%0A                System.out.println(%22Listener Fired:%22 + contextName);%0A                res%5B0%5D = contextName;%0A            %7D%0A        %7D);%0A%0A%0A        Serializable s = MVEL.compileSetExpression(%22list%5B0%5D%22);%0A%0A        Base b;%0A        MVEL.executeSetExpression(s, new Base(), %22hey you%22);%0A        res%5B0%5D = null;%0A%0A        MVEL.executeSetExpression(s, b = new Base(), %22hey you%22);%0A%0A        assertEquals(%22set%22, b.list.get(0));%0A        assertEquals(%22list%22, res%5B0%5D);%0A    %7D%0A%0A%0A
 %0A    public 

add more unit tests