# Copyright (c) 2004-2022 Adam Karpierz
# Licensed under CC BY-NC-ND 4.0
# Licensed under proprietary License
# Please refer to the accompanying LICENSE file.

import jni

from .....jframe import JFrame
from .....jhost  import JHost
from .....jvm    import JVMException
from .....java   import throwJavaException


# Class: org.jt.reflect.ProxyHandler

# Method: native Object invoke(long target, Object proxy, java.lang.reflect.Method method, Object[] args);

@jni.method("(JLjava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;")
def invoke(env, this,
           target, jproxy, jmethod, jargs):
    proxy = jni.from_oid(target)
    jt_jvm = proxy._state.jt_jvm
    jvm, jenv = jt_jvm._jvm, env[0]
    try:
        method, args = None, []
        try:
            method = jt_jvm.JMethod(None, jmethod, own=False) if jmethod else None
            argcnt = jenv.GetArrayLength(jargs) if jargs else 0
            with JFrame(jenv, argcnt):
                for idx in range(argcnt):
                    jarg = jenv.GetObjectArrayElement(jargs, idx)
                    args.append(jt_jvm.JObject(None, jarg, own=False) if jarg else None)

                with JHost.CallbackState((jvm, jenv)):
                    result = proxy(method, *args)
                    if result is None:
                        return None
                    else:
                        if not isinstance(result, jt_jvm.JObject):
                            raise TypeError("Must be jvm.JObject")
                        return jenv.NewGlobalRef(result.handle)
        finally:
            del method, args
    except jni.Throwable as exc:
        jexc = jt_jvm.JException(exc)
        jexc.throw()
    except jni.JNIException as exc:
        throwJavaException(jenv, "java.lang.RuntimeException", exc.getMessage())
    except jt_jvm.JavaException as exc:
        jenv.Throw(jni.cast(exc.__javaobject__.handle, jni.jthrowable))
    except JVMException as exc:
        throwJavaException(jenv, "java.lang.RuntimeException", exc.args[1])
    except UnboundLocalError as exc:
        throwJavaException(jenv, "java.lang.NoSuchMethodError", exc)
    except Exception as exc:
        throwJavaException(jenv, "java.lang.RuntimeException",
                                 f"Python exception thrown: {exc}")
    return None

# Method: native void initialize(long target);

@jni.method("(J)V")
def initialize(env, this,
               target):
    proxy = jni.from_oid(target)
    jt_jvm = proxy._state.jt_jvm
    jvm, jenv = jt_jvm._jvm, env[0]
    with JHost.CallbackState((jvm, jenv)):
        JHost.incRef(proxy)

# Method: native void release(long target);

@jni.method("(J)V")
def release(env, this,
            target):
    proxy = jni.from_oid(target)
    jt_jvm = proxy._state.jt_jvm
    jvm, jenv = jt_jvm._jvm, env[0]
    with JHost.CallbackState((jvm, jenv)):
        JHost.decRef(proxy)


__jnimethods__ = (
    invoke,
    initialize,
    release,
)

__javacode__ = bytearray(  # Auto-generated; DO NOT EDIT!
    b"\xca\xfe\xba\xbe\x00\x00\x00\x34\x00\x24\x0a\x00\x08\x00\x1a\x0a\x00\x07\x00\x1b"
    b"\x09\x00\x07\x00\x1c\x0a\x00\x07\x00\x1d\x0a\x00\x07\x00\x1e\x0a\x00\x08\x00\x1f"
    b"\x07\x00\x20\x07\x00\x21\x07\x00\x22\x01\x00\x06\x74\x61\x72\x67\x65\x74\x01\x00"
    b"\x01\x4a\x01\x00\x06\x3c\x69\x6e\x69\x74\x3e\x01\x00\x04\x28\x4a\x29\x56\x01\x00"
    b"\x04\x43\x6f\x64\x65\x01\x00\x06\x69\x6e\x76\x6f\x6b\x65\x01\x00\x53\x28\x4c\x6a"
    b"\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x4c\x6a\x61\x76"
    b"\x61\x2f\x6c\x61\x6e\x67\x2f\x72\x65\x66\x6c\x65\x63\x74\x2f\x4d\x65\x74\x68\x6f"
    b"\x64\x3b\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74"
    b"\x3b\x29\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b"
    b"\x01\x00\x0a\x45\x78\x63\x65\x70\x74\x69\x6f\x6e\x73\x07\x00\x23\x01\x00\x08\x66"
    b"\x69\x6e\x61\x6c\x69\x7a\x65\x01\x00\x03\x28\x29\x56\x01\x00\x0d\x53\x74\x61\x63"
    b"\x6b\x4d\x61\x70\x54\x61\x62\x6c\x65\x07\x00\x23\x01\x00\x54\x28\x4a\x4c\x6a\x61"
    b"\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x4c\x6a\x61\x76\x61"
    b"\x2f\x6c\x61\x6e\x67\x2f\x72\x65\x66\x6c\x65\x63\x74\x2f\x4d\x65\x74\x68\x6f\x64"
    b"\x3b\x5b\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b"
    b"\x29\x4c\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63\x74\x3b\x01"
    b"\x00\x0a\x69\x6e\x69\x74\x69\x61\x6c\x69\x7a\x65\x01\x00\x07\x72\x65\x6c\x65\x61"
    b"\x73\x65\x0c\x00\x0c\x00\x14\x0c\x00\x18\x00\x0d\x0c\x00\x0a\x00\x0b\x0c\x00\x0f"
    b"\x00\x17\x0c\x00\x19\x00\x0d\x0c\x00\x13\x00\x14\x01\x00\x1b\x6f\x72\x67\x2f\x6a"
    b"\x74\x2f\x72\x65\x66\x6c\x65\x63\x74\x2f\x50\x72\x6f\x78\x79\x48\x61\x6e\x64\x6c"
    b"\x65\x72\x01\x00\x10\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x4f\x62\x6a\x65\x63"
    b"\x74\x01\x00\x23\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x72\x65\x66\x6c\x65\x63"
    b"\x74\x2f\x49\x6e\x76\x6f\x63\x61\x74\x69\x6f\x6e\x48\x61\x6e\x64\x6c\x65\x72\x01"
    b"\x00\x13\x6a\x61\x76\x61\x2f\x6c\x61\x6e\x67\x2f\x54\x68\x72\x6f\x77\x61\x62\x6c"
    b"\x65\x00\x31\x00\x07\x00\x08\x00\x01\x00\x09\x00\x01\x00\x01\x00\x0a\x00\x0b\x00"
    b"\x00\x00\x06\x00\x01\x00\x0c\x00\x0d\x00\x01\x00\x0e\x00\x00\x00\x1b\x00\x03\x00"
    b"\x03\x00\x00\x00\x0f\x2a\xb7\x00\x01\x2a\x1f\xb7\x00\x02\x2a\x1f\xb5\x00\x03\xb1"
    b"\x00\x00\x00\x00\x00\x01\x00\x0f\x00\x10\x00\x02\x00\x0e\x00\x00\x00\x18\x00\x06"
    b"\x00\x04\x00\x00\x00\x0c\x2a\x2a\xb4\x00\x03\x2b\x2c\x2d\xb7\x00\x04\xb0\x00\x00"
    b"\x00\x00\x00\x11\x00\x00\x00\x04\x00\x01\x00\x12\x00\x04\x00\x13\x00\x14\x00\x02"
    b"\x00\x0e\x00\x00\x00\x3d\x00\x03\x00\x02\x00\x00\x00\x1c\x2a\x2a\xb4\x00\x03\xb7"
    b"\x00\x05\x2a\x09\xb5\x00\x03\x2a\xb7\x00\x06\xa7\x00\x0a\x4c\x2a\xb7\x00\x06\x2b"
    b"\xbf\xb1\x00\x01\x00\x00\x00\x0d\x00\x14\x00\x00\x00\x01\x00\x15\x00\x00\x00\x07"
    b"\x00\x02\x54\x07\x00\x16\x06\x00\x11\x00\x00\x00\x04\x00\x01\x00\x12\x01\x02\x00"
    b"\x0f\x00\x17\x00\x00\x01\x02\x00\x18\x00\x0d\x00\x00\x01\x02\x00\x19\x00\x0d\x00"
    b"\x00\x00\x00"
)
