from ctypes import *
from ctypes import util
import os

import sys
PY3K = sys.version_info >= (3, 0)

from .types import *

# If we're on Android, the SO file isn't on the LD_LIBRARY_PATH,
# so we have to manually specify it using the environment.
java = cdll.LoadLibrary(os.environ.get('RUBICON_LIBRARY', util.find_library('rubicon')))

JNI_VERSION_1_1 = 0x00010001
JNI_VERSION_1_2 = 0x00010002
JNI_VERSION_1_4 = 0x00010004
JNI_VERSION_1_6 = 0x00010006

# Standard JNI API

java.GetVersion.restype = jint
java.GetVersion.argtypes = []

java.DefineClass.restype = jclass
java.DefineClass.argtypes = [c_char_p, jobject, jbyte_p, jsize]
java.FindClassB = getattr(java, "FindClass")
java.FindClassB.restype = jclass
java.FindClassB.argtypes = [c_char_p]
def FindClass(x):
    if isinstance(x, str):
        x = x.encode("utf-8")
    return java.FindClassB(x)
if PY3K:
    java.FindClass = FindClass
else:
    java.FindClass = java.FindClassB

java.FromReflectedMethod.restype = jmethodID
java.FromReflectedMethod.argtypes = [jobject]
java.FromReflectedField.restype = jfieldID
java.FromReflectedField.argtypes = [jobject]
java.ToReflectedMethod.restype = jobject
java.ToReflectedMethod.argtypes = [jclass, jmethodID, jboolean]

java.GetSuperclass.restype = jclass
java.GetSuperclass.argtypes = [jclass]
java.IsAssignableFrom.restype = jboolean
java.IsAssignableFrom.argtypes = [jclass, jclass]

java.ToReflectedField.restype = jobject
java.ToReflectedField.argtypes = [jclass, jfieldID, jboolean]

java.Throw.restype = jint
java.Throw.argtypes = [jthrowable]
java.ThrowNew.restype = jint
java.ThrowNew.argtypes = [jclass, c_char_p]
java.ExceptionOccurred.restype = jthrowable
java.ExceptionOccurred.argtypes = []
java.ExceptionDescribe.restype = None
java.ExceptionDescribe.argtypes = []
java.ExceptionClear.restype = None
java.ExceptionClear.argtypes = []
java.FatalError.restype = None
java.FatalError.argtypes = [c_char_p]

java.PushLocalFrame.restype = jint
java.PushLocalFrame.argtypes = [jint]
java.PopLocalFrame.restype = jobject
java.PopLocalFrame.argtypes = [jobject]

java.NewGlobalRef.restype = jobject
java.NewGlobalRef.argtypes = [jobject]
java.DeleteGlobalRef.restype = None
java.DeleteGlobalRef.argtypes = [jobject]
java.DeleteLocalRef.restype = None
java.DeleteLocalRef.argtypes = [jobject]

java.IsSameObject.restype = jboolean
java.IsSameObject.argtypes = [jobject, jobject]

java.NewLocalRef.restype = jobject
java.NewLocalRef.argtypes = [jobject]
java.EnsureLocalCapacity.restype = jint
java.EnsureLocalCapacity.argtypes = [jint]

java.AllocObject.restype = jobject
java.AllocObject.argtypes = [jclass]
java.NewObject.restype = jobject
java.NewObject.argtypes = [jclass, jmethodID]

java.GetObjectClass.restype = jclass
java.GetObjectClass.argtypes = [jobject]
java.IsInstanceOf.restype = jboolean
java.IsInstanceOf.argtypes = [jobject, jclass]

java.GetMethodIDB = getattr(java, "GetMethodID")
java.GetMethodIDB.restype = jmethodID
java.GetMethodIDB.argtypes = [jclass, c_char_p, c_char_p]
def GetMethodID(x, y, z):
    if isinstance(y, str):
        y = y.encode("utf-8")
    if isinstance(z, str):
        z = z.encode("utf-8")
    return java.GetMethodIDB(x, y, z)
if PY3K:
    java.GetMethodID = GetMethodID
else:
    java.GetMethodID = java.GetMethodIDB


java.CallObjectMethod.restype = jobject
java.CallObjectMethod.argtypes = [jobject, jmethodID]
java.CallBooleanMethod.restype = jboolean
java.CallBooleanMethod.argtypes = [jobject, jmethodID]
java.CallByteMethod.restype = jbyte
java.CallByteMethod.argtypes = [jobject, jmethodID]
java.CallCharMethod.restype = jchar
java.CallCharMethod.argtypes = [jobject, jmethodID]
java.CallShortMethod.restype = jshort
java.CallShortMethod.argtypes = [jobject, jmethodID]
java.CallIntMethod.restype = jint
java.CallIntMethod.argtypes = [jobject, jmethodID]
java.CallLongMethod.restype = jlong
java.CallLongMethod.argtypes = [jobject, jmethodID]
java.CallFloatMethod.restype = jfloat
java.CallFloatMethod.argtypes = [jobject, jmethodID]
java.CallDoubleMethod.restype = jdouble
java.CallDoubleMethod.argtypes = [jobject, jmethodID]
java.CallVoidMethod.restype = None
java.CallVoidMethod.argtypes = [jobject, jmethodID]

java.CallNonvirtualObjectMethod.restype = jobject
java.CallNonvirtualObjectMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualBooleanMethod.restype = jboolean
java.CallNonvirtualBooleanMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualByteMethod.restype = jbyte
java.CallNonvirtualByteMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualCharMethod.restype = jchar
java.CallNonvirtualCharMethod.argtypes = [jobject, jclass,jmethodID]
java.CallNonvirtualShortMethod.restype = jshort
java.CallNonvirtualShortMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualIntMethod.restype = jint
java.CallNonvirtualIntMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualLongMethod.restype = jlong
java.CallNonvirtualLongMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualFloatMethod.restype = jfloat
java.CallNonvirtualFloatMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualDoubleMethod.restype = jdouble
java.CallNonvirtualDoubleMethod.argtypes = [jobject, jclass, jmethodID]
java.CallNonvirtualVoidMethod.restype = None
java.CallNonvirtualVoidMethod.argtypes = [jobject, jclass, jmethodID]

java.GetFieldIDB = getattr(java, "GetFieldID")
java.GetFieldIDB.restype = jfieldID
java.GetFieldIDB.argtypes = [jclass, c_char_p, c_char_p]
def GetFieldID(x, y, z):
    if isinstance(y, str):
        y = y.encode("utf-8")
    if isinstance(z, str):
        z = z.encode("utf-8")
    return java.GetFieldIDB(x, y, z)
if PY3K:
    java.GetFieldID = GetFieldID
else:
    java.GetFieldID = java.GetFieldIDB

java.GetObjectField.restype = jobject
java.GetObjectField.argtypes = [jobject, jfieldID]
java.GetBooleanField.restype = jboolean
java.GetBooleanField.argtypes = [jobject, jfieldID]
java.GetByteField.restype = jbyte
java.GetByteField.argtypes = [jobject, jfieldID]
java.GetCharField.restype = jchar
java.GetCharField.argtypes = [jobject, jfieldID]
java.GetShortField.restype = jshort
java.GetShortField.argtypes = [jobject, jfieldID]
java.GetIntField.restype = jint
java.GetIntField.argtypes = [jobject, jfieldID]
java.GetLongField.restype = jlong
java.GetLongField.argtypes = [jobject, jfieldID]
java.GetFloatField.restype = jfloat
java.GetFloatField.argtypes = [jobject, jfieldID]
java.GetDoubleField.restype = jdouble
java.GetDoubleField.argtypes = [jobject, jfieldID]

java.SetObjectField.restype = None
java.SetObjectField.argtypes = [jobject, jfieldID, jobject]
java.SetBooleanField.restype = None
java.SetBooleanField.argtypes = [jobject, jfieldID, jboolean]
java.SetByteField.restype = None
java.SetByteField.argtypes = [jobject, jfieldID, jbyte]
java.SetCharField.restype = None
java.SetCharField.argtypes = [jobject, jfieldID, jchar]
java.SetShortField.restype = None
java.SetShortField.argtypes = [jobject, jfieldID, jshort]
java.SetIntField.restype = None
java.SetIntField.argtypes = [jobject, jfieldID, jint]
java.SetLongField.restype = None
java.SetLongField.argtypes = [jobject, jfieldID, jlong]
java.SetFloatField.restype = None
java.SetFloatField.argtypes = [jobject, jfieldID, jfloat]
java.SetDoubleField.restype = None
java.SetDoubleField.argtypes = [jobject, jfieldID, jdouble]

java.GetStaticMethodIDB = getattr(java, "GetStaticMethodID")
java.GetStaticMethodIDB.restype = jmethodID
java.GetStaticMethodIDB.argtypes = [jclass, c_char_p, c_char_p]
def GetStaticMethodID(x, y, z):
    if isinstance(y, str):
        y = y.encode("utf-8")
    if isinstance(z, str):
        z = z.encode("utf-8")
    return java.GetStaticMethodIDB(x, y, z)
if PY3K:
    java.GetStaticMethodID = GetStaticMethodID
else:
    java.GetStaticMethodID = java.GetStaticMethodIDB

java.CallStaticObjectMethod.restype = jobject
java.CallStaticObjectMethod.argtypes = [jclass, jmethodID]
java.CallStaticBooleanMethod.restype = jboolean
java.CallStaticBooleanMethod.argtypes = [jclass, jmethodID]
java.CallStaticByteMethod.restype = jbyte
java.CallStaticByteMethod.argtypes = [jclass, jmethodID]
java.CallStaticCharMethod.restype = jchar
java.CallStaticCharMethod.argtypes = [jclass, jmethodID]
java.CallStaticShortMethod.restype = jshort
java.CallStaticShortMethod.argtypes = [jclass, jmethodID]
java.CallStaticIntMethod.restype = jint
java.CallStaticIntMethod.argtypes = [jclass, jmethodID]
java.CallStaticLongMethod.restype = jlong
java.CallStaticLongMethod.argtypes = [jclass, jmethodID]
java.CallStaticFloatMethod.restype = jfloat
java.CallStaticFloatMethod.argtypes = [jclass, jmethodID]
java.CallStaticDoubleMethod.restype = jdouble
java.CallStaticDoubleMethod.argtypes = [jclass, jmethodID]
java.CallStaticVoidMethod.restype = None
java.CallStaticVoidMethod.argtypes = [jclass, jmethodID]

java.GetStaticFieldIDB = getattr(java, "GetStaticFieldID")
java.GetStaticFieldIDB.restype = jfieldID
java.GetStaticFieldIDB.argtypes = [jclass, c_char_p, c_char_p]
def GetStaticFieldID(x, y, z):
    if isinstance(y, str):
        y = y.encode("utf-8")
    if isinstance(z, str):
        z = z.encode("utf-8")
    return java.GetStaticFieldIDB(x, y, z)
if PY3K:
    java.GetStaticFieldID = GetStaticFieldID
else:
    java.GetStaticFieldID = java.GetStaticFieldIDB

java.GetStaticObjectField.restype = jobject
java.GetStaticObjectField.argtypes = [jclass, jfieldID]
java.GetStaticBooleanField.restype = jboolean
java.GetStaticBooleanField.argtypes = [jclass, jfieldID]
java.GetStaticByteField.restype = jbyte
java.GetStaticByteField.argtypes = [jclass, jfieldID]
java.GetStaticCharField.restype = jchar
java.GetStaticCharField.argtypes = [jclass, jfieldID]
java.GetStaticShortField.restype = jshort
java.GetStaticShortField.argtypes = [jclass, jfieldID]
java.GetStaticIntField.restype = jint
java.GetStaticIntField.argtypes = [jclass, jfieldID]
java.GetStaticLongField.restype = jlong
java.GetStaticLongField.argtypes = [jclass, jfieldID]
java.GetStaticFloatField.restype = jfloat
java.GetStaticFloatField.argtypes = [jclass, jfieldID]
java.GetStaticDoubleField.restype = jdouble
java.GetStaticDoubleField.argtypes = [jclass, jfieldID]

java.SetStaticObjectField.restype = None
java.SetStaticObjectField.argtypes = [jclass, jfieldID, jobject]
java.SetStaticBooleanField.restype = None
java.SetStaticBooleanField.argtypes = [jclass, jfieldID, jboolean]
java.SetStaticByteField.restype = None
java.SetStaticByteField.argtypes = [jclass, jfieldID, jbyte]
java.SetStaticCharField.restype = None
java.SetStaticCharField.argtypes = [jclass, jfieldID, jchar]
java.SetStaticShortField.restype = None
java.SetStaticShortField.argtypes = [jclass, jfieldID, jshort]
java.SetStaticIntField.restype = None
java.SetStaticIntField.argtypes = [jclass, jfieldID, jint]
java.SetStaticLongField.restype = None
java.SetStaticLongField.argtypes = [jclass, jfieldID, jlong]
java.SetStaticFloatField.restype = None
java.SetStaticFloatField.argtypes = [jclass, jfieldID, jfloat]
java.SetStaticDoubleField.restype = None
java.SetStaticDoubleField.argtypes = [jclass, jfieldID, jdouble]

java.NewString.restype = jstring
java.NewString.argtypes = [jchar_p, jsize]
java.GetStringLength.restype = jsize
java.GetStringLength.argtypes = [jstring]
java.GetStringChars.restype = jchar_p
java.GetStringChars.argtypes = [jstring, jboolean_p]
java.ReleaseStringChars.restype = None
java.ReleaseStringChars.argtypes = [jstring, jchar_p]

java.NewStringUTFB = getattr(java, "NewStringUTF")
java.NewStringUTFB.restype = jstring
java.NewStringUTFB.argtypes = [c_char_p]
def NewStringUTF(x):
    if isinstance(x, str):
        x = x.encode("utf-8")
    return java.NewStringUTFB(x)
if PY3K:
    java.NewStringUTF = NewStringUTF
else:
    java.NewStringUTF = java.NewStringUTFB

java.GetStringUTFLength.restype = jsize
java.GetStringUTFLength.argtypes = [jstring]
java.GetStringUTFChars.restype = c_char_p
java.GetStringUTFChars.argtypes = [jstring, jboolean_p]
java.ReleaseStringUTFChars.restype = None
java.ReleaseStringUTFChars.argtypes = [jstring, c_char_p]

java.GetArrayLength.restype = jsize
java.GetArrayLength.argtypes = [jarray]
java.NewObjectArray.restype = jobjectArray
java.NewObjectArray.argtypes = [jsize, jclass, jobject]
java.GetObjectArrayElement.restype = jobject
java.GetObjectArrayElement.argtypes = [jobjectArray, jsize]
java.SetObjectArrayElement.restype = None
java.SetObjectArrayElement.argtypes = [jobjectArray, jsize, jobject]

java.NewBooleanArray.restype = jbooleanArray
java.NewBooleanArray.argtypes = [jsize]
java.NewByteArray.restype = jbyteArray
java.NewByteArray.argtypes = [jsize]
java.NewCharArray.restype = jcharArray
java.NewCharArray.argtypes = [jsize]
java.NewShortArray.restype = jshortArray
java.NewShortArray.argtypes = [jsize]
java.NewIntArray.restype = jintArray
java.NewIntArray.argtypes = [jsize]
java.NewLongArray.restype = jlongArray
java.NewLongArray.argtypes = [jsize]
java.NewFloatArray.restype = jfloatArray
java.NewFloatArray.argtypes = [jsize]
java.NewDoubleArray.restype = jdoubleArray
java.NewDoubleArray.argtypes = [jsize]

java.GetBooleanArrayElements.restype = jboolean_p
java.GetBooleanArrayElements.argtypes = [jbooleanArray, jboolean_p]
java.GetByteArrayElements.restype = jbyte_p
java.GetByteArrayElements.argtypes = [jbyteArray, jboolean_p]
java.GetCharArrayElements.restype = jchar_p
java.GetCharArrayElements.argtypes = [jcharArray, jboolean_p]
java.GetShortArrayElements.restype = jshort_p
java.GetShortArrayElements.argtypes = [jshortArray, jboolean_p]
java.GetIntArrayElements.restype = jint_p