/*
 * Copyright 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "jni_helper.h"
#include "jnictx.h"

namespace tuningfork {

namespace jni {

static jmethodID find_class_;
static LocalObject activity_class_loader_;

void InitActivityClassLoader() {
    if (activity_class_loader_.IsNull()) {
        jobject activity = AppContextGlobalRef();
        jclass activity_clazz = Env()->GetObjectClass(activity);
        jmethodID get_class_loader = Env()->GetMethodID(
            activity_clazz, "getClassLoader", "()Ljava/lang/ClassLoader;");
        activity_class_loader_ =
                Env()->CallObjectMethod(activity, get_class_loader);

        jclass class_loader = Env()->FindClass("java/lang/ClassLoader");

        find_class_ = Env()->GetMethodID(
            class_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
        Env()->DeleteLocalRef(activity_clazz);
        Env()->DeleteLocalRef(class_loader);
    }
}

void Init(JNIEnv* env, jobject ctx) {
    Ctx::Init(env, ctx);
}
bool IsValid() {
    return Ctx::Instance()!=nullptr && Ctx::Instance()->IsValid();
}
JNIEnv* Env() {
    return Ctx::Instance()->Env();
}
void DetachThread() {
    return Ctx::Instance()->DetachThread();
}
jobject AppContextGlobalRef() {
    return Ctx::Instance()->AppCtx();
}

jclass FindClass(const char* class_name) {
    jclass jni_class = Env()->FindClass(class_name);

    if (jni_class == NULL) {
        InitActivityClassLoader();
        // FindClass would have thrown.
        Env()->ExceptionClear();
        jstring class_jname = Env()->NewStringUTF(class_name);
        jni_class =
                (jclass)(Env()->CallObjectMethod(activity_class_loader_, find_class_, class_jname));
        Env()->DeleteLocalRef(class_jname);
    }
    return jni_class;
}

LocalObject NewObjectV(const char * cclz, const char* ctorSig, va_list argptr) {
    jclass clz = FindClass(cclz);
    jmethodID constructor = Env()->GetMethodID(clz, "<init>", ctorSig);
    jobject o = Env()->NewObjectV(clz, constructor, argptr);
    return LocalObject(o, clz);
}
LocalObject NewObject(const char * cclz, const char* ctorSig, ...) {
    va_list argptr;
    va_start(argptr, ctorSig);
    auto o = NewObjectV(cclz, ctorSig, argptr);
    va_end(argptr);
    return o;
}
jobject LocalObject::CallObjectMethod(const char* name, const char* sig, ...) const {
    jmethodID mid = Env()->GetMethodID(clz_, name, sig);
    va_list argptr;
    va_start(argptr, sig);
    jobject o = Env()->CallObjectMethodV(obj_, mid, argptr);
    va_end(argptr);
    return o;
}
jobject LocalObject::CallStaticObjectMethod(const char* name, const char* sig, ...) const {
    jmethodID mid = Env()->GetStaticMethodID(clz_, name, sig);
    va_list argptr;
    va_start(argptr, sig);
    jobject o = Env()->CallStaticObjectMethodV(clz_, mid, argptr);
    va_end(argptr);
    return o;
}
String LocalObject::CallStringMethod(const char* name, const char* sig, ...) const {
    jmethodID mid = Env()->GetMethodID(clz_, name, sig);
    va_list argptr;
    va_start(argptr, sig);
    jobject o = Env()->CallObjectMethodV(obj_, mid, argptr);
    va_end(argptr);
    String s((jstring)o);
    return s;
}
void LocalObject::CallVoidMethod(const char* name, const char* sig, ...) const {
    jmethodID mid = Env()->GetMethodID(clz_, name, sig);
    va_list argptr;
    va_start(argptr, sig);
    Env()->CallVoidMethodV(obj_, mid, argptr);
    va_end(argptr);
}
int LocalObject::CallIntMethod(const char* name, const char* sig, ...) const {
    jmethodID mid = Env()->GetMethodID(clz_, name, sig);
    va_list argptr;
    va_start(argptr, sig);
    int r = Env()->CallIntMethodV(obj_, mid, argptr);
    va_end(argptr);
        return r;
}
std::string GetExceptionMessage() {
    std::string msg;
    jthrowable exception = Env()->ExceptionOccurred();
    Env()->ExceptionClear();
    jclass oclass = FindClass("java/lang/Object");
    jmethodID toString = Env()->GetMethodID(oclass,
                                           "toString", "()Ljava/lang/String;");
    jstring s = (jstring)Env()->CallObjectMethod(exception, toString);
    const char* utf = Env()->GetStringUTFChars(s, nullptr);
    msg = utf;
    Env()->ReleaseStringUTFChars(s, utf);
    Env()->DeleteLocalRef(oclass);
    Env()->DeleteLocalRef(s);
    Env()->DeleteLocalRef(exception);
    return msg;
}
bool CheckForException(std::string& msg) {
    if(Env()->ExceptionCheck()) {
        msg = GetExceptionMessage();
        return true;
    }
    return false;
}
LocalObject LocalObject::GetObjectField(const char* field_name,
                                         const char* sig) const {
    jfieldID fid = Env()->GetFieldID(clz_, field_name, sig);
    if(!RawExceptionCheck()) {
        auto out = Env()->GetObjectField(obj_, fid);
        return LocalObject(out, nullptr);
    } else {
        return LocalObject(nullptr, nullptr);
    }
}
int LocalObject::GetIntField(const char* field_name) const {
    jfieldID fid = Env()->GetFieldID(clz_, field_name, "I");
    if(!RawExceptionCheck())
        return Env()->GetIntField(obj_, fid);
    else
        return BAD_FIELD;
}
std::vector<char> GetByteArrayBytesAndDeleteRef(jbyteArray jbs) {
    jbyte* bs = Env()->GetByteArrayElements(jbs, 0);
    std::vector<char> ret(bs, bs + Env()->GetArrayLength(jbs));
    Env()->ReleaseByteArrayElements(jbs, bs, JNI_ABORT);
    Env()->DeleteLocalRef(jbs);
    return ret;
}

#ifndef NDEBUG
void DumpLocalRefTable()
{
    JNIEnv* env = Env();
    jclass vm_class = env->FindClass("dalvik/system/VMDebug");
    jmethodID dump_mid = env->GetStaticMethodID( vm_class, "dumpReferenceTables", "()V" );
    env->CallStaticVoidMethod( vm_class, dump_mid );
    env->DeleteLocalRef(vm_class);
}
#endif

} // namespace jni

} // namespace tuningfork
