//
// Created by #Suyghur, on 2021/06/12.
//

#include <logger.h>
#include "include/toolkit.h"
#include <sstream>

jbyteArray ToolKit::GetJByteArray(JNIEnv *env, const char *src) {
    return nullptr;
}

jstring ToolKit::GetJString(JNIEnv *env, const char *src) {
    jclass clz = env->FindClass("java/lang/String");
    jmethodID methodID = env->GetMethodID(clz, "<init>", "([BLjava/lang/String;)V");
    jstring encoding = env->NewStringUTF("utf-8");

    auto length = static_cast<jsize>(strlen(src));
    jbyteArray bytes = env->NewByteArray(length);
    env->SetByteArrayRegion(bytes, 0, length, (jbyte *) src);
    auto result = (jstring) env->NewObject(clz, methodID, bytes, encoding);

    env->DeleteLocalRef(clz);
    env->DeleteLocalRef(encoding);
    env->DeleteLocalRef(bytes);

    return result;
}

std::string ToolKit::JString2String(JNIEnv *env, jstring jstr) {
    if (env == nullptr || jstr == nullptr) {
        return "";
    }
    char *tmp_ptr = nullptr;
    jclass clz = env->FindClass("java/lang/String");
    jstring encode_mode = env->NewStringUTF("UTF-8");
    jmethodID mid = env->GetMethodID(clz, "getBytes", "(Ljava/lang/String;)[B");
    auto byte_array = (jbyteArray) (env->CallObjectMethod(jstr, mid, encode_mode));
    jsize len = env->GetArrayLength(byte_array);
    if (len == 0) {
        free(tmp_ptr);
        return "";
    }
    jbyte *byte = env->GetByteArrayElements(byte_array, JNI_FALSE);
    if (len > 0) {
        tmp_ptr = (char *) malloc(len + 1);
        memcpy(tmp_ptr, byte, len);
        tmp_ptr[len] = 0;
    }
    env->ReleaseByteArrayElements(byte_array, byte, JNI_FALSE);
    std::string result(tmp_ptr);
    free(tmp_ptr);
    env->DeleteLocalRef(clz);
    env->DeleteLocalRef(encode_mode);
    env->DeleteLocalRef(byte_array);
    return result;
}

int ToolKit::String2Int(const std::string &s) {
    int value = 0;
    std::stringstream ss;
    ss << s;
    ss >> value;
    return value;
}

std::string ToolKit::GetPackageName(JNIEnv *env, jobject context) {
    jclass clz = env->GetObjectClass(context);
    if (clz == nullptr) {
        Logger::E(env, "Context clz is null");
        return "";
    }
    const char *method_name = "getPackageName";
    const char *sig = "()Ljava/lang/String;";
    jmethodID mid = env->GetMethodID(clz, method_name, sig);
    auto result = (jstring) env->CallObjectMethod(context, mid);
    env->DeleteLocalRef(clz);
//    free((void *) method_name);
//    free((void *) sig);
    return JString2String(env, result);
}

std::string ToolKit::GetServerVersion(JNIEnv *env) {
    jclass clz = env->FindClass("cn/yyxx/eyuangame/Version");
    if (clz == nullptr) {
        Logger::E(env, "Version clz is null");
        return "";
    }
    const char *field_name = "SERVER_VERSION";
    const char *sig = "Ljava/lang/String;";
    jfieldID fid = env->GetStaticFieldID(clz, field_name, sig);
    auto result = (jstring) env->GetStaticObjectField(clz, fid);
    env->DeleteLocalRef(clz);
//    free((void *) field_name);
//    free((void *) sig);
    return JString2String(env, result);
}

std::string ToolKit::GetClientVersion(JNIEnv *env) {
    jclass clz = env->FindClass("cn/yyxx/eyuangame/Version");
    if (clz == nullptr) {
        Logger::E(env, "Version clz is null");
        return "";
    }
    const char *field_name = "VERSION_NAME";
    const char *sig = "Ljava/lang/String;";
    jfieldID fid = env->GetStaticFieldID(clz, field_name, sig);
    auto result = (jstring) env->GetStaticObjectField(clz, fid);
    env->DeleteLocalRef(clz);
//    free((void *) field_name);
//    free((void *) sig);
    return JString2String(env, result);
}

std::string ToolKit::GetVersionName(JNIEnv *env, jobject context) {
    jclass clz = env->FindClass("cn/yyxx/support/AppUtils");
    if (clz == nullptr) {
        Logger::E(env, "AppUtils clz is null");
        return "";
    }
    const char *method_name = "getVersionName";
    const char *sig = "(Landroid/content/Context;)Ljava/lang/String;";
    jmethodID mid = env->GetStaticMethodID(clz, method_name, sig);
    auto result = (jstring) env->CallStaticObjectMethod(clz, mid, context);
    env->DeleteLocalRef(clz);
//    free((void *) method_name);
//    free((void *) sig);
    return JString2String(env, result);
}

std::string ToolKit::GetVersionCode(JNIEnv *env, jobject context) {
    jclass clz = env->FindClass("cn/yyxx/support/AppUtils");
    if (clz == nullptr) {
        Logger::E(env, "AppUtils clz is null");
        return "";
    }
    const char *method_name = "getVersionCodeStr";
    const char *sig = "(Landroid/content/Context;)Ljava/lang/String;";
    jmethodID mid = env->GetStaticMethodID(clz, method_name, sig);
    auto result = (jstring) env->CallStaticObjectMethod(clz, mid, context);
    env->DeleteLocalRef(clz);
//    free((void *) method_name);
//    free((void *) sig);
    return JString2String(env, result);
}

std::string ToolKit::GetAndroidDeviceId(JNIEnv *env, jobject context) {
    jclass clz = env->FindClass("cn/yyxx/support/device/DeviceInfoUtils");
    if (clz == nullptr) {
        Logger::E(env, "UUIDUtils clz is null");
        return "";
    }
    const char *method_name = "getAndroidDeviceId";
    const char *sig = "(Landroid/content/Context;)Ljava/lang/String;";
    jmethodID mid = env->GetStaticMethodID(clz, method_name, sig);
    auto result = (jstring) env->CallStaticObjectMethod(clz, mid, context);
    env->DeleteLocalRef(clz);
//    free((void *) method_name);
//    free((void *) sig);
    return JString2String(env, result);
}

int ToolKit::GetNetworkType(JNIEnv *env, jobject context) {
    jclass clz = env->FindClass("cn/yyxx/support/device/DeviceInfoUtils");
    if (clz == nullptr) {
        Logger::E(env, "DeviceInfoUtils clz is null");
        return 0;
    }
    const char *method_name = "getNetworkClass";
    const char *sig = "(Landroid/content/Context;)Ljava/lang/String;";
    jmethodID mid = env->GetStaticMethodID(clz, method_name, sig);
    auto result = (jstring) env->CallStaticObjectMethod(clz, mid, context);
    env->DeleteLocalRef(clz);
//    free((void *) method_name);
//    free((void *) sig);
    return String2Int(JString2String(env, result));
}

std::string ToolKit::GetDeviceManufacturer() {
    char *manufacturer = (char *) malloc(128 * sizeof(char));
    __system_property_get("ro.product.manufacturer", manufacturer);
    std::string result = manufacturer;
    free(manufacturer);
    return std::string(result);
}

std::string ToolKit::GetDeviceModel() {
    char *model = (char *) malloc(128 * sizeof(char));
    __system_property_get("ro.product.model", model);
    std::string result = model;
    free(model);
    return result;
}

std::string ToolKit::GetMobileBrand() {
    char *brand = (char *) malloc(128 * sizeof(char));
    __system_property_get("ro.product.brand", brand);
    std::string result = brand;
    free(brand);
    return result;
}

std::string ToolKit::GetDeviceSoftwareVersion() {
    char *version = (char *) malloc(128 * sizeof(char));
    __system_property_get("ro.build.version.release", version);
    std::string result = version;
    free(version);
    return result;
}

bool ToolKit::IsEmulator(JNIEnv *env, jobject context) {
    jclass clz = env->FindClass("cn/yyxx/support/device/DeviceInfoUtils");
    if (clz == nullptr) {
        Logger::E(env, "DeviceInfoUtils clz is null");
        return "";
    }
    const char *method_name = "isEmulator";
    const char *sig = "(Landroid/content/Context;)Z";
    jmethodID mid = env->GetStaticMethodID(clz, method_name, sig);
    auto result = (jboolean) env->CallStaticBooleanMethod(clz, mid, context);
    env->DeleteLocalRef(clz);
//    free((void *) method_name);
//    free((void *) sig);
    return result == JNI_TRUE;
}

std::string ToolKit::ToJsonString(const Json::Value &root) {
    Json::StreamWriterBuilder builder;
    std::ostringstream oss;
    //无格式输出
    builder.settings_["indentation"] = "";
    std::unique_ptr<Json::StreamWriter> json_writer(builder.newStreamWriter());
    json_writer->write(root, &oss);
    return oss.str();
}

Json::Value ToolKit::ToJsonObject(const std::string &json) {
    Json::CharReaderBuilder builder;
    Json::CharReader *reader_ptr(builder.newCharReader());
    JSONCPP_STRING errs;
    Json::Value root;
    reader_ptr->parse(json.c_str(), json.c_str() + json.length(), &root, &errs);
    return root;
}

char *ToolKit::StrReverse(const char *src) {
    char *tmp = new char[strlen(src)];
    strcpy(tmp, src);
    //用来最后返回数组指针
    char *ret = tmp;
    char *p = tmp + strlen(src) - 1;
    while (p > tmp) {
        char t = *tmp;
        *tmp++ = *p;
        *p-- = t;
    }
//    free(p);
    return ret;
}






