// Write C++ code here.
//
// Do not forget to dynamically load the C++ library into your application.
//
// For instance,
//
// In MainActivity.java:
//    static {
//       System.loadLibrary("mpmaster");
//    }
//
// Or, in MainActivity.kt:
//    companion object {
//      init {
//         System.loadLibrary("mpmaster")
//      }
//    }
#include <jni.h>
#include <fcntl.h>
#include <thread>
#include <chrono>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <sys/system_properties.h>
#include <android/log.h>

#include <Client/Database.h>

#define IOT_PARAM_WRITE 0xAE
#define IOT_PARAM_READ 0xAF
#define MAX_STRING_LEN 32

#define PATH_MPAPP_STATS        "/sdcard/com.xypower.mpapp/data/stats/"
#define PATH_MPAPP_RUNNING      "/sdcard/com.xypower.mpapp/running"

typedef struct
{
    int cmd;
    int value;
    int result;
    long value2;
    char str[MAX_STRING_LEN];
}IOT_PARAM;

extern "C" JNIEXPORT jint JNICALL
Java_com_xypower_mpmaster_MpMasterService_getInt(JNIEnv* env, jclass cls, jint cmd) {
    int fd = open("/dev/mtkgpioctrl", O_RDONLY);
    // LOGE("get_int fd=%d,cmd=%d\r\n",fd, cmd);
    if( fd > 0 )
    {
        IOT_PARAM param;
        param.cmd = cmd;
        ioctl(fd, IOT_PARAM_READ, &param);
#ifdef _DEBUG
        ALOGI("getInt cmd=%d,value=%d,result=%d\r\n",param.cmd, param.value, param.result);
#endif
        close(fd);
        return param.value;
    }
    return -1;
}

int setGpioInt(int cmd, int val)
{
    int fd = open("/dev/mtkgpioctrl", O_RDONLY);
    // LOGE("set_int fd=%d,cmd=%d,value=%d\r\n",fd, cmd, value);
    if( fd > 0 )
    {
        IOT_PARAM param;
        param.cmd = cmd;
        param.value = val;
        int res = ioctl(fd, IOT_PARAM_WRITE, &param);
        // LOGE("set_int22 cmd=%d,value=%d,result=%d\r\n",param.cmd, param.value, param.result);
        close(fd);
        return 0;
    }
    return -1;
}

extern "C" JNIEXPORT jint JNICALL
Java_com_xypower_mpmaster_MpMasterService_setInt(JNIEnv* env, jclass cls, jint cmd, jint val) {

    return setGpioInt(cmd, val);
}

extern "C" JNIEXPORT void JNICALL
Java_com_xypower_mpmaster_MpMasterService_rebootDevice(JNIEnv* env, jclass cls) {
    // setInt(CMD_SET_SYSTEM_RESET, 1);
    std::thread t([]()
      {
          std::this_thread::sleep_for(std::chrono::milliseconds(1000));
          for (int idx = 0; idx < 3; idx++) {
              if (setGpioInt(202, 1) == 0) {
                  break;
              }
          }
      });
    t.detach();
}

extern "C" JNIEXPORT jintArray JNICALL
Java_com_xypower_mpmaster_MpMasterService_getStats(JNIEnv* env, jclass cls, jlong ts) {
    std::string path = PATH_MPAPP_STATS;
    path += std::to_string(ts);

    FILE* file = NULL;

    for (int idx = 0; idx < 3; idx++)
    {
        file = fopen(path.c_str(), "r");
        if (file != NULL)
        {
            break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(16));
    }

    if (file == NULL)
    {
        return NULL;
    }
    MP_STATS stats = { 0 };
    size_t length = fread(&stats, 1, sizeof(stats), file);
    fclose(file);
    if (length < sizeof(stats))
    {
        return NULL;
    }

    size_t intLength = sizeof(stats) / sizeof(jint);
    jintArray result = env->NewIntArray(intLength);
    env->SetIntArrayRegion(result, 0, intLength, (const jint*)&stats);
    return result;
}


extern "C" JNIEXPORT jstring JNICALL
Java_com_xypower_mpmaster_MpMasterService_getSystemProperty(
        JNIEnv* env,
        jclass cls, jstring key) {

    const char *keyStr = env->GetStringUTFChars(key, 0);

    char value[PROP_VALUE_MAX] = { 0 };
    __system_property_get(keyStr, value);

    env->ReleaseStringUTFChars(key, keyStr);

    return env->NewStringUTF(value);
}

extern "C" JNIEXPORT jboolean JNICALL
Java_com_xypower_mpmaster_MpMasterService_isMpAppRunning(
        JNIEnv* env, jclass cls) {

    jboolean res = JNI_FALSE;
    int fd = open(PATH_MPAPP_RUNNING, O_RDWR, 0444);
    if (fd != -1)
    {
        __android_log_print(ANDROID_LOG_INFO, "MP_TAG", "fd != -1");

        if (flock(fd, LOCK_EX) == 0)
        {
            __android_log_print(ANDROID_LOG_INFO, "MP_TAG", "locked");

        } else
        {
            __android_log_print(ANDROID_LOG_INFO, "MP_TAG", "can't locked");
            res = JNI_TRUE;
        }
        close(fd);
        return res;
    }
    else
    {
        __android_log_print(ANDROID_LOG_INFO, "MP_TAG", "can't open");
    }

    return JNI_FALSE;

}

