#ifdef U_PLATFORM_ANDROID

#include <jni.h>
#include <string>
#include <map>
#include <string>
#include <cstdlib>
#include "NativeUtils.hpp"
#include "CCookMenu.hpp"
#include "../../include/CookMenuPrepare.h"


static CCookMenu* toInstance(jlong instanceId)
{
    CCookMenu* pMenu = reinterpret_cast<CCookMenu* >(instanceId);

    if (0 ==  pMenu)
    {
        COOK_LOG_ERROR("failed to get instance, instanceId=0", instanceId);
        return 0;
    }

    return pMenu;
}

static void CateringLog(const char* pStr)
{
    if (0 == pStr)
    {
        return;
    }
    if (strstr(pStr, "err"))
    {
        U_LOGE("%s", pStr);
    }
    else
    {
        U_LOGD("%s", pStr);
    }
}

// 创建菜谱实例
extern "C"
JNIEXPORT jlong
JNICALL
Java_com_utcloud_cookengine_CookEngine_createInstance(JNIEnv* env, jobject jThis, jbyteArray binData, jstring params)
{
    COOKLOG.InitHook(CateringLog);

    COOK_LOG_INFO("call %s.", __FUNCTION__);

    // TODO:
    if (0 == binData)
    {
        COOK_LOG_ERROR("call %s, bin is null", __FUNCTION__);
        return 0;
    }
    COOK_LOG_INFO("call %s, bin length=%d", __FUNCTION__, env->GetArrayLength(binData));
    // 获取回调对象
    jobject callbackObj = callVoidObjectMethod(env, jThis, "getCallback",
                                       "()Lcom/utcloud/cookengine/CookCallBack;");
    if (0 == callbackObj)
    {
        return 0;
    }
    // 获取bin数据
    int32_t  iBinLen = 0;
    uint8_t* pBinData = u_jbytearray_tobytes(env, binData, 0, &iBinLen);
    if (0 == pBinData || iBinLen <= 0)
    {
        return 0;
    }
    // 创建菜谱对象，并保存全局jvm
    JavaVM* jvm = 0;
    env->GetJavaVM(&jvm);
    CCookMenu* pMenu = new CCookMenu(jvm, env, callbackObj);
    env->DeleteLocalRef(callbackObj);
    // 转化得到参数配置，参数的格式为： key1=value1;key2=value2
    std::map<std::string, std::string> paramsMap;
    if (!jstringToMap(env, params, paramsMap))
    {
        free(pBinData);
        delete(pMenu);
        return 0;
    }
    if (!pMenu->Init(pBinData, iBinLen, paramsMap))
    {
        free(pBinData);
        delete(pMenu);
        return 0;
    }
    free(pBinData);

    COOK_LOG_INFO("call %s, create instance success, instanceid=%x", __FUNCTION__, (jlong)pMenu);
    return reinterpret_cast<jlong >(pMenu);
}

// 销毁菜谱实例对象
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_destroyInstance(JNIEnv* env, jobject jThis, jlong instanceId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;

    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }
    pMenu->Cleanup();
    // TODO: 做其他的清理
    delete pMenu;

    return 1;
}

// 获取扩展区数据
extern "C"
JNIEXPORT jbyteArray
JNICALL
Java_com_utcloud_cookengine_CookEngine_getExternData(JNIEnv* env, jobject jThis, jlong instanceId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }
    const std::vector<unsigned char>* pXmlData = pMenu->GetRecipeData();
    jbyteArray  retBytes = u_bytes_to_jbytearray(env, pXmlData->data(), pXmlData->size());

    return retBytes;
}

// 发送事件
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_postEvent(JNIEnv* env, jobject jThis, jlong jinstanceId,
                    jlong jtrueProductId, jstring jproductFieldName, jobject jval)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, jinstanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(jinstanceId)))
    {
        return 0;
    }
    CCookVariant productFieldValue = jobjectToVaraint(env, jval);
    if (CCookVariant::TYPE_INVALID == productFieldValue.Type())
    {
        return 0;
    }
    std::string productFieldName = javaStrToCStr(env, jproductFieldName);

    return pMenu->PostEvent(jtrueProductId, productFieldName, &productFieldValue);
}

// 开始任务
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_startTask(JNIEnv* env, jobject jThis, jlong instanceId,
                                                 jstring taskId, jobject trueProductMap)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }
    std::map<long, std::string> bindedProducts = javaMapToCMap(env, trueProductMap);
    return pMenu->StartTask(javaStrToCStr(env, taskId), bindedProducts)  ?  1 : 0;
}

// 暂停任务
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_pauseTask(JNIEnv* env, jobject jThis, jlong instanceId,
                                                 jstring taskId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }

    return pMenu->PauseTask(javaStrToCStr(env, taskId));
}

// 恢复任务
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_resumeTask(JNIEnv* env, jobject jThis, jlong instanceId,
                                                 jstring taskId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }

    return pMenu->RestoreTask(javaStrToCStr(env, taskId));
}

// 终止任务
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_terminateTask(JNIEnv* env, jobject jThis, jlong instanceId,
                                                  jstring taskId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }
    return pMenu->TerminateTask(javaStrToCStr(env, taskId));
}


// 跳过当前步
extern "C"
JNIEXPORT jboolean
JNICALL
Java_com_utcloud_cookengine_CookEngine_skipCurrentStep(JNIEnv* env, jobject jThis, jlong instanceId,
                                                     jstring taskId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }

    return pMenu->SkipCurrentStep(javaStrToCStr(env, taskId));
}

// 获取任务信息
extern "C"
JNIEXPORT jbyteArray
JNICALL
Java_com_utcloud_cookengine_CookEngine_getTaskInfo(JNIEnv* env, jobject jThis, jlong instanceId)
{
    COOK_LOG_INFO("call %s, instanceid=%x.", __FUNCTION__, instanceId);

    CCookMenu* pMenu = 0;
    if (0 == (pMenu = toInstance(instanceId)))
    {
        return 0;
    }

    std::list<task_item_t> taskItemList;
    bool ret = pMenu->GetTaskInfo(taskItemList);

    if(!ret)
    {
        return 0;
    }

    return cTaskInfoToJTaskInfoTo(env, taskItemList);

}


// 获取任务信息
extern "C"
JNIEXPORT jbyteArray
JNICALL
Java_com_utcloud_cookengine_CookEngine_prepareGetExternData(JNIEnv* env, jobject jThis, jbyteArray binData )
{
    COOKLOG.InitHook(CateringLog);

    COOK_LOG_INFO("call %s.", __FUNCTION__);

    // TODO:
    if (0 == binData)
    {
        COOK_LOG_ERROR("call %s, bin is null", __FUNCTION__);
        return 0;
    }
    COOK_LOG_INFO("call %s, bin length=%d", __FUNCTION__, env->GetArrayLength(binData));

    // 获取bin数据
    int32_t  iBinLen = 0;
    uint8_t* pBinData = u_jbytearray_tobytes(env, binData, 0, &iBinLen);
    if (0 == pBinData || iBinLen <= 0)
    {
        return 0;
    }

    // 创建菜谱对象，并保存全局jvm
    JavaVM* jvm = 0;
    env->GetJavaVM(&jvm);
    ICookMenuPrepare* pMenuPrepare = new ICookMenuPrepare();
    bool ok = pMenuPrepare->Init(pBinData, iBinLen);
    if(!ok){
        delete(pMenuPrepare);
        free(pBinData);
        return 0;
    }

    const std::vector<unsigned char>* pXmlData = pMenuPrepare->GetRecipeData();
    jbyteArray  retBytes = u_bytes_to_jbytearray(env, pXmlData->data(), pXmlData->size());

    delete(pMenuPrepare);
    free(pBinData);

    return retBytes;

}

// 获取任务信息
extern "C"
JNIEXPORT jbyteArray
JNICALL
Java_com_utcloud_cookengine_CookEngine_prepareGetTaskInfo(JNIEnv* env, jobject jThis, jbyteArray binData )
{
    COOKLOG.InitHook(CateringLog);

    COOK_LOG_INFO("call %s.", __FUNCTION__);

    // TODO:
    if (0 == binData)
    {
        COOK_LOG_ERROR("call %s, bin is null", __FUNCTION__);
        return 0;
    }
    COOK_LOG_INFO("call %s, bin length=%d", __FUNCTION__, env->GetArrayLength(binData));

    // 获取bin数据
    int32_t  iBinLen = 0;
    uint8_t* pBinData = u_jbytearray_tobytes(env, binData, 0, &iBinLen);
    if (0 == pBinData || iBinLen <= 0)
    {
        return 0;
    }

    // 创建菜谱对象，并保存全局jvm
    JavaVM* jvm = 0;
    env->GetJavaVM(&jvm);
    ICookMenuPrepare* pMenuPrepare = new ICookMenuPrepare();
    bool ok = pMenuPrepare->Init(pBinData, iBinLen);
    if(!ok){
        delete(pMenuPrepare);
        free(pBinData);
        return 0;
    }

    std::list<task_item_t> taskItemList;
    ok = pMenuPrepare->GetTaskInfo(taskItemList);

    delete(pMenuPrepare);
    free(pBinData);

    if(!ok)
    {
        return 0;
    }

    return cTaskInfoToJTaskInfoTo(env, taskItemList);
}

#endif