#include "android/com_funambol_omadmclient_android_service_OmaDmClinetService.h"
#include "android/com_funambol_omadmclient_android_service_NotificationCallbackInterface.h"

#include "mockDaemonEngine.h"

#include "daemon/IDaemonEngine.h"
#include "common/FileSystemUtils.h"

#include "DaemonDM/MessageListener.h"

#include <jni.h>
////#include <android/log.h>

#include <signal.h>

#include <pthread.h>

#include "Logger/androidlog.h"

static const char* LOG_TAG = "OmaDmClientService";

using namespace NS_DM_Client;

const size_t c_blockSignalsCount = 5;
int BlockSignals[c_blockSignalsCount] = {SIGUSR2, SIGALRM, SIGTSTP, SIGPROF, SIGCHLD};

const size_t c_handleSignalsCount = 16;
int HandleSignals[c_handleSignalsCount] = {SIGPIPE, SIGUSR1, SIGHUP, SIGTERM, SIGILL, SIGTRAP, SIGQUIT, SIGABRT, SIGIOT, SIGBUS, SIGFPE, SIGSEGV, SIGSTKFLT, SIGCONT, SIGPWR, SIGSYS};

struct sigaction SignalAction;
sigset_t SigMask;

//--------------------------------------------------------------------------------------------------

void Handler(int Signal)
{
    LOGI("enter >> Handler. Signal:%d", Signal);

    int tID = static_cast<int>(pthread_self());

    if (Signal == SIGPIPE)
    {
        LOGE("signal Handler, Received signal: SIGPIPE, thread ID: %d", tID);
    }
    else if (Signal == SIGSEGV)
    {
        LOGE("signal Handler, Received signal: SIGSEGV, thread ID: %d", tID);
        //sleep(3);
        LOGI("exit << Handler");
        exit(-1);
    }
    else
    {
        LOGE("signal Handler, Received signal: %d, thread ID: %d", Signal, tID);
        sleep(3);
    }

    LOGI("exit << Handler");
}

//--------------------------------------------------------------------------------------------------

int ConfigureSignalHandlers (void)
{
    LOGI("enter >> ConfigureSignalHandlers");

    size_t i;
    sigemptyset (&SigMask);
    for (i = 0; i < c_blockSignalsCount; i++)
    {
        sigaddset (&SigMask, *(BlockSignals + i));
    }

    SignalAction.sa_handler = Handler;
    SignalAction.sa_mask    = SigMask;
    SignalAction.sa_flags    = 0;
    sigaction (SIGUSR1, &SignalAction, NULL);
    for (i = 0; i < c_handleSignalsCount; i++)
    {
        sigaction(*(HandleSignals + i), &SignalAction, NULL);
    }

    LOGI("leave << ConfigureSignalHandlers");
    return EXIT_SUCCESS;
}

//--------------------------------------------------------------------------------------------------

IDaemonEngine* GetDaemonEngine(bool deleteEngine = false)
{
    LOGI("enter >> GetDaemonEngine. For delete: %s", (deleteEngine ? "Yes" : "No"));

    static IDaemonEngine* engine = (IDaemonEngine*)NULL;

    if (deleteEngine)
    {
        if (engine != (IDaemonEngine*)NULL)
        {
            engine->Release();
            engine = (IDaemonEngine*)NULL;
        }
        return 0;
    }

    if (engine == (IDaemonEngine*)NULL)
    {
        engine = IDaemonEngine::GetInstance();
    }

    LOGI("leave << GetDaemonEngine. Result: %s", ((engine != NULL) ? "Success" : "Fail"));
    return engine;
}

//--------------------------------------------------------------------------------------------------

MessageListener* GetMessageListener(bool deleteListener = false)
{
    LOGI("enter >> GetMessageListener. For delete: %s", (deleteListener ? "Yes" : "No"));

    static MessageListener* listener = (MessageListener*)NULL;

    if (deleteListener)
    {
        if (listener != (MessageListener*)NULL)
        {
            listener->Release();
            listener = (MessageListener*)NULL;
        }
        return 0;
    }

    if (listener == (MessageListener*)NULL)
    {
        IMessageHandler* handler = new AndroidMessageHandler;
        if (handler != (IMessageHandler*)NULL)
        {
            listener = CreateMessageListener(handler);
        }
        else
        {
            LOGE("Failed to create AndroidMessageHandler instance");
        }
    }

    LOGI("leave << GetMessageListener. Result: %s", ((listener != (MessageListener*)NULL) ? "Success" : "Fail"));
    return listener;
}

//--------------------------------------------------------------------------------------------------

JNIEXPORT jlong JNICALL Java_com_funambol_omadmclient_android_service_OmaDmClinetService_CreateEngine(JNIEnv *, jclass)
{
    LOGI("enter >> CreateEngine");
    ConfigureSignalHandlers();

/****** 2013.06.09 ************************
    if (!NS_DM_Client::CreatePath("/data/data/com.funambol.omadmclient.android.service/Logs"))
    {
    }
    if (!NS_DM_Client::CreatePath("/data/data/com.funambol.omadmclient.android.service/DataStorage"))
    {
    }
    if (!NS_DM_Client::CreatePath("/data/data/com.funambol.omadmclient.android.service/DataStorage/WiMAX_Profile"))
    {
    }
    if (!NS_DM_Client::CreatePath("/data/data/com.funambol.omadmclient.android.service/DataStorage/WiMAX_Profile/DMAcc"))
    {
    }
******************************************/

    LOGI("exit << CreateEngine. Ret:%d", 1);
    return 1;
}

//--------------------------------------------------------------------------------------------------

JNIEXPORT jlong JNICALL Java_com_funambol_omadmclient_android_service_OmaDmClinetService_StartEngine(JNIEnv *, jclass)
{
    LOGI("enter >> StartEngine");
    IDaemonEngine* engine = GetDaemonEngine();
    if (engine != (IDaemonEngine*)NULL)
    {
        int res = engine->Start();
        int ret = res ? 1: 0;
        LOGI("exit << StartEngine. Res:%d", ret);
        return ret;
    }

    LOGI("exit << StartEngine. Ret:%d", 0);
    return 0;
}

//--------------------------------------------------------------------------------------------------

JNIEXPORT jlong JNICALL Java_com_funambol_omadmclient_android_service_OmaDmClinetService_StopEngine(JNIEnv *, jclass)
{
    LOGI("enter >> StopEngine");
    IDaemonEngine* engine = GetDaemonEngine();
    if (engine != (IDaemonEngine*)NULL)
    {
        int res = engine->Stop();
        int ret = res ? 1: 0;
        LOGI("exit << StopEngine. Res:%d", ret);
        return ret;
    }

    GetDaemonEngine(true); // delete DaemonEngine singleton
    LOGI("exit << StopEngine. Res:%d",0);
    return 0;
}

//--------------------------------------------------------------------------------------------------

JNIEXPORT jlong JNICALL Java_com_funambol_omadmclient_android_service_OmaDmClinetService_CreateMessageListener(JNIEnv *, jclass)
{
    LOGI("enter >> CreateMessageListener");

    jlong res = GetMessageListener() ? 1 : -1;

    LOGI("leave << CreateMessageListener. Res: %d", res);
    return res;
}

//--------------------------------------------------------------------------------------------------

JNIEXPORT jlong JNICALL Java_com_funambol_omadmclient_android_service_OmaDmClinetService_StartMessageListener(JNIEnv *, jclass)
{
    LOGI("enter >> StartMessageListener");
    jlong res = -1;

    MessageListener* listner = GetMessageListener();
    if (listner != (MessageListener*)NULL)
    {
        res = (listner->WaitMessages() == e_Ok) ? 1 : -1; 
        if (res < 0)
        {
            LOGE("Error: MessageListener::WaitMessages() failed");
        }
    }

    LOGI("leave << StartMessageListener. Res: %s", ((res > 0) ? "Success" : "Fail"));
    return res;
}

//--------------------------------------------------------------------------------------------------

JNIEXPORT jlong JNICALL Java_com_funambol_omadmclient_android_service_OmaDmClinetService_StopMessageListener(JNIEnv *, jclass)
{
    LOGI("enter >> StopMessageListener");
    jlong res = -1;

    MessageListener* listner = GetMessageListener();
    if (listner != (MessageListener*)NULL)
    {
        res = (listner->StopWaitingMessages() == e_Ok) ? 1 : -1; 
        if (res < 0)
        {
            LOGE("Error: MessageListener::StopWaitingMessages() failed");
        }

        GetMessageListener(true); // release listener
    }

    LOGI("leave << StopMessageListener. Res: %s", ((res > 0) ? "Success" : "Fail"));
    return res;
}

//--------------------------------------------------------------------------------------------------

