package com.ninty.nativee.lang.invoke;

import com.ninty.nativee.INativeMethod;
import com.ninty.nativee.NaMethodManager;
import com.ninty.runtime.NiFrame;
import com.ninty.runtime.heap.NiClass;
import com.ninty.runtime.heap.NiObject;
import com.ninty.runtime.heap.NiString;

public class NaMethodHandleNatives {
    private final static String className = "java/lang/invoke/MethodHandleNatives";

    public static void init() {
        NaMethodManager.register(className, "getConstant", "(I)I", new
                getConstant());
        NaMethodManager.register(className, "resolve", "(Ljava/lang/invoke/MemberName;Ljava/lang/Class;)Ljava/lang/invoke/MemberName;", new
                resolve());
    }

    public static class getConstant implements INativeMethod {

        @Override
        public void invoke(NiFrame frame) {
            int which = frame.getLocalVars().getInt(0);
            frame.getOperandStack().pushInt(which == 4 ? 1 : 0);
        }
    }

    public static class resolve implements INativeMethod {

        @Override
        public void invoke(NiFrame frame) {
            NiObject memberName = frame.getLocalVars().getRef(0);
            NiObject caller = frame.getLocalVars().getRef(1);
            if (caller == null) {
                caller = memberName.getFieldRef("clazz", "Ljava/lang/Class;");
            }
            // TODO: getMethod with name and desc
//            NiObject type = memberName.getFieldRef("type", "Ljava/lang/Object;");
//            NiObject rtypes = type.getFieldRef("rtype", "Ljava/lang/Class;");
//            NiObject ptypes = type.getFieldRef("ptypes", "[Ljava/lang/Class;");
            NiClass callerClz = caller.getClzByExtra();
            int flags = memberName.getFieldInt("flags");
            String name = NiString.getString(memberName.getFieldRef("name", "Ljava/lang/String;"));
            memberName.setFieldInt("flags", flags | callerClz.getMethodByName(name).getAccessFlags());
            frame.getOperandStack().pushRef(memberName);
        }
    }
}

@@ -140,23 +140,25 @@
 runtime.
-NiFrame
+LocalVars
 ;%0Aimport
@@ -180,20 +180,15 @@
 ime.
-heap.NiClass
+NiFrame
 ;%0Aim
@@ -214,20 +214,46 @@
 ime.
-heap.NiObjec
+NiThread;%0Aimport com.ninty.runtime.Slo
 t;%0Ai
@@ -281,24 +281,17 @@
 me.heap.
-NiString
+*
 ;%0A%0Apubli
@@ -706,24 +706,159 @@
 resolve());%0A
+        NaMethodManager.register(className, %22init%22, %22(Ljava/lang/invoke/MemberName;Ljava/lang/Object;)V%22, new%0A                init());%0A
     %7D%0A%0A    p
@@ -2101,24 +2101,24 @@
 ssFlags());%0A
-
             
@@ -2177,11 +2177,1807 @@
  %7D%0A    %7D
+%0A%0A    public static class init implements INativeMethod %7B%0A%0A        @Override%0A        public void invoke(NiFrame frame) %7B%0A            LocalVars localVars = frame.getLocalVars();%0A            NiObject self = localVars.getRef(0);%0A            NiObject ref = localVars.getRef(1);%0A            if (ref.getClz().getClassName().equals(%22java/lang/reflect/Method%22)) %7B%0A                NiObject clazz = ref.getFieldRef(%22clazz%22, %22Ljava/lang/Class;%22);%0A                self.setFieldRef(%22clazz%22, %22Ljava/lang/Class;%22, clazz);%0A%0A                NiObject name = ref.getFieldRef(%22name%22, %22Ljava/lang/String;%22);%0A                self.setFieldRef(%22name%22, %22Ljava/lang/String;%22, name);%0A%0A                NiObject rtype = ref.getFieldRef(%22returnType%22, %22Ljava/lang/Class;%22);%0A                NiObject ptypes = ref.getFieldRef(%22parameterTypes%22, %22%5BLjava/lang/Class;%22);%0A                NiObject type = getMethodType(frame, rtype, ptypes);%0A                self.setFieldRef(%22type%22, %22Ljava/lang/Object;%22, type);%0A                self.setFieldInt(%22flags%22, 100728840);%0A                return;%0A            %7D%0A            throw new UnsupportedOperationException(%22need to implement : %22 + ref.getClz().getClassName());%0A        %7D%0A%0A        private NiObject getMethodType(NiFrame frame, NiObject rClz, NiObject pClzs) %7B%0A            NiClassLoader loader = frame.getMethod().getClz().getLoader();%0A            NiClass clzMethodType = loader.loadClass(%22java/lang/invoke/MethodType%22);%0A            NiMethod methodTypeMethod = clzMethodType.getMethod(%22methodType%22,%0A                    %22(Ljava/lang/Class;%5BLjava/lang/Class;)Ljava/lang/invoke/MethodType;%22);%0A            Slot mt = NiThread.execMethodAtCurrent(frame, methodTypeMethod,%0A                    new Slot(rClz),%0A                    new Slot(pClzs));%0A            return mt.getRef();%0A        %7D%0A    %7D
 %0A%7D%0A

add native method: java.lang.invoke.init(Ljava/lang/invoke/MemberName;Ljava/lang/Object;)V