<commit_before>//******************************************************************
//
// Copyright 2015 Samsung Electronics All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// 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 "resourcehandler.h"

#include "ocpayload.h"
#include "oic_string.h"
#include "oic_malloc.h"

/**
 * @var ES_RH_TAG
 * @brief Logging tag for module name.
 */
#define ES_RH_TAG "ES_RH"
//-----------------------------------------------------------------------------
// Private variables
//-----------------------------------------------------------------------------

/**
 * @var gProvResource
 * @brief Structure for holding the Provisioning status and target information required to
 * connect to the target network
 */
static ProvResource gProvResource;
static WiFiResource gWiFiResource;
static CloudResource gCloudResource;
static DevConfResource gDevConfResource;

//-----------------------------------------------------------------------------
// Private internal function prototypes
//-----------------------------------------------------------------------------
OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest *ehRequest,
        void *callback);
OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload** payload);
OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload** payload);
OCEntityHandlerResult ProcessPostRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload** payload);
void updateProvResource(OCEntityHandlerRequest* ehRequest, OCRepPayload* input);
void updateWiFiResource(OCRepPayload* input);
void updateCloudResource(OCRepPayload* input);
void updateDevConfResource(OCRepPayload* input);
const char *getResult(OCStackResult result);

ESWiFiCB gWifiRsrcEvtCb = NULL;
ESCloudCB gCloudRsrcEvtCb = NULL;
ESDevConfCB gDevConfRsrcEvtCb = NULL;

ESReadUserdataCb gReadUserdataCb = NULL;
ESWriteUserdataCb gWriteUserdataCb = NULL;

ESResult SetCallbackForUserData(ESReadUserdataCb readCb, ESWriteUserdataCb writeCb)
{
    if(!readCb && !writeCb)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Both of callbacks for user data are null");
        return ES_ERROR;
    }
    gReadUserdataCb = readCb;
    gWriteUserdataCb = writeCb;
    return ES_OK;
}

void RegisterWifiRsrcEventCallBack(ESWiFiCB cb)
{
    gWifiRsrcEvtCb = cb;
}

void RegisterCloudRsrcEventCallBack(ESCloudCB cb)
{
    gCloudRsrcEvtCb = cb;
}

void RegisterDevConfRsrcEventCallBack(ESDevConfCB cb)
{
    gDevConfRsrcEvtCb = cb;
}

void UnRegisterResourceEventCallBack()
{
    if (gWifiRsrcEvtCb)
    {
        gWifiRsrcEvtCb = NULL;
    }
    if (gCloudRsrcEvtCb)
    {
        gCloudRsrcEvtCb = NULL;
    }
    if (gDevConfRsrcEvtCb)
    {
        gDevConfRsrcEvtCb = NULL;
    }
}

void GetTargetNetworkInfoFromProvResource(char *name, char *pass)
{
    if (name != NULL && pass != NULL)
    {
        OICStrcpy(name, MAX_SSIDLEN, gWiFiResource.ssid);
        OICStrcpy(pass, MAX_CREDLEN, gWiFiResource.cred);
    }
}

OCStackResult initProvResource(bool isSecured)
{
    gProvResource.status = ES_STATE_INIT;
    gProvResource.lastErrCode = ES_ERRCODE_NO_ERROR;
    OICStrcpy(gProvResource.ocfWebLinks, MAX_WEBLINKLEN, "");

    OCStackResult res = OC_STACK_ERROR;
    if (isSecured)
    {
        res = OCCreateResource(&gProvResource.handle, OC_RSRVD_ES_RES_TYPE_PROV,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_PROV, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gProvResource.handle, OC_RSRVD_ES_RES_TYPE_PROV,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_PROV, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }
    if(res)
    {
        OIC_LOG_V(INFO, ES_RH_TAG, "Created Prov resource with result: %s", getResult(res));
        return res;
    }

    res = OCBindResourceInterfaceToResource(gProvResource.handle, OC_RSRVD_INTERFACE_LL);
    if(res)
    {
        OIC_LOG_V(INFO, ES_RH_TAG, "Binding Resource interface with result: %s", getResult(res));
        return res;
    }
    res = OCBindResourceInterfaceToResource(gProvResource.handle, OC_RSRVD_INTERFACE_BATCH);
    if(res)
    {
        OIC_LOG_V(INFO, ES_RH_TAG, "Binding Resource interface with result: %s", getResult(res));
        return res;
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created Prov resource with result: %s", getResult(res));
    return res;
}

OCStackResult initWiFiResource(bool isSecured)
{
    OCStackResult res = OC_STACK_ERROR;

    gWiFiResource.supportedFreq = WIFI_BOTH;
    gWiFiResource.supportedMode[0] = WIFI_11A;
    gWiFiResource.supportedMode[1] = WIFI_11B;
    gWiFiResource.supportedMode[2] = WIFI_11G;
    gWiFiResource.supportedMode[3] = WIFI_11N;
    gWiFiResource.numMode = 4;
    gWiFiResource.authType = NONE_AUTH;
    gWiFiResource.encType = NONE_ENC;
    OICStrcpy(gWiFiResource.ssid, sizeof(gWiFiResource.ssid), "");
    OICStrcpy(gWiFiResource.cred, sizeof(gWiFiResource.cred), "");

    if (isSecured)
    {
        res = OCCreateResource(&gWiFiResource.handle, OC_RSRVD_ES_RES_TYPE_WIFI,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_WIFI, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gWiFiResource.handle, OC_RSRVD_ES_RES_TYPE_WIFI,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_WIFI, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created WiFi resource with result: %s", getResult(res));
    return res;

}

OCStackResult initCloudServerResource(bool isSecured)
{
    OCStackResult res = OC_STACK_ERROR;

    OICStrcpy(gCloudResource.authCode, sizeof(gCloudResource.authCode), "");
    OICStrcpy(gCloudResource.authProvider, sizeof(gCloudResource.authProvider), "");
    OICStrcpy(gCloudResource.ciServer, sizeof(gCloudResource.ciServer), "");

    if (isSecured)
    {
        res = OCCreateResource(&gCloudResource.handle, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_CLOUDSERVER, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gCloudResource.handle, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_CLOUDSERVER, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created CloudServer resource with result: %s", getResult(res));
    return res;

}

OCStackResult initDevConfResource(bool isSecured)
{
    OCStackResult res = OC_STACK_ERROR;

    OICStrcpy(gDevConfResource.devName, sizeof(gDevConfResource.devName), "");
    OICStrcpy(gDevConfResource.country, sizeof(gDevConfResource.country), "");
    OICStrcpy(gDevConfResource.language, sizeof(gDevConfResource.language), "");

    if (isSecured)
    {
        res = OCCreateResource(&gDevConfResource.handle, OC_RSRVD_ES_RES_TYPE_DEVCONF,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_DEVCONF, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gDevConfResource.handle, OC_RSRVD_ES_RES_TYPE_DEVCONF,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_DEVCONF, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created DevConf resource with result: %s", getResult(res));
    return res;

}

void updateProvResource(OCEntityHandlerRequest* ehRequest, OCRepPayload* input)
{
    OIC_LOG_V(INFO, ES_RH_TAG, "gProvResource.status %d", gProvResource.status);

    if(ehRequest->query)
    {
        if(strstr(ehRequest->query, OC_RSRVD_INTERFACE_BATCH))
        {
        // When Provisioning resource has a POST with BatchInterface
            updateCloudResource(input);
            updateWiFiResource(input);
            updateDevConfResource(input);
        }
    }
}

void updateWiFiResource(OCRepPayload* input)
{
    ESWiFiProvData* wiFiData = (ESWiFiProvData*)OICMalloc(sizeof(ESWiFiProvData));

    if(wiFiData == NULL)
    {
        OIC_LOG(DEBUG, ES_RH_TAG, "OICMalloc is failed");
        return ;
    }

    memset(wiFiData->ssid, 0, MAX_SSIDLEN);
    memset(wiFiData->pwd, 0, MAX_CREDLEN);
    wiFiData->authtype = NONE_AUTH;
    wiFiData->enctype = NONE_AUTH;
    wiFiData->userdata = NULL;

    char* ssid = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_SSID, &ssid))
    {
        OICStrcpy(gWiFiResource.ssid, sizeof(gWiFiResource.ssid), ssid);
        OICStrcpy(wiFiData->ssid, sizeof(wiFiData->ssid), ssid);
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.ssid : %s", gWiFiResource.ssid);
    }

    char* cred = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CRED, &cred))
    {
        OICStrcpy(gWiFiResource.cred, sizeof(gWiFiResource.cred), cred);
        OICStrcpy(wiFiData->pwd, sizeof(wiFiData->pwd), cred);
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.cred %s", gWiFiResource.cred);
    }

    int64_t authType = -1;
    if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_AUTHTYPE, &authType))
    {
        gWiFiResource.authType = authType;
        wiFiData->authtype = gWiFiResource.authType;
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.authType %u", gWiFiResource.authType);
    }

    int64_t encType = -1;
    if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_ENCTYPE, &encType))
    {
        gWiFiResource.encType = encType;
        wiFiData->enctype = gWiFiResource.encType;
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.encType %u", gWiFiResource.encType);
    }

    if(gReadUserdataCb)
    {
        gReadUserdataCb(input, OC_RSRVD_ES_RES_TYPE_WIFI, &wiFiData->userdata);
    }

    if(ssid || cred || authType!= -1 || encType != -1)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Send WiFiRsrc Callback To ES");

        // TODO : Need to check appropriateness of gWiFiData
        if(gWifiRsrcEvtCb != NULL)
        {
            gWifiRsrcEvtCb(ES_OK, wiFiData);
        }
        else
        {
            OIC_LOG(ERROR, ES_RH_TAG, "gWifiRsrcEvtCb is NULL");
        }
    }

    OICFree(wiFiData);
}

void updateCloudResource(OCRepPayload* input)
{
    ESCloudProvData* cloudData = (ESCloudProvData*)OICMalloc(sizeof(ESCloudProvData));

    if(cloudData == NULL)
    {
        OIC_LOG(DEBUG, ES_RH_TAG, "OICMalloc is failed");
        return;
    }

    memset(cloudData->authCode, 0, OIC_STRING_MAX_VALUE);
    memset(cloudData->authProvider, 0, OIC_STRING_MAX_VALUE);
    memset(cloudData->ciServer, 0, OIC_STRING_MAX_VALUE);
    cloudData->userdata = NULL;

    char *authCode = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_AUTHCODE, &authCode))
    {
        OICStrcpy(gCloudResource.authCode, sizeof(gCloudResource.authCode), authCode);
        OICStrcpy(cloudData->authCode, sizeof(cloudData->authCode), authCode);
        OIC_LOG_V(INFO, ES_RH_TAG, "gCloudResource.authCode %s", gCloudResource.authCode);
    }

    char *authProvider = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_AUTHPROVIDER, &authProvider))
    {
        OICStrcpy(gCloudResource.authProvider, sizeof(gCloudResource.authProvider), authProvider);
        OICStrcpy(cloudData->authProvider, sizeof(cloudData->authProvider), authProvider);
        OIC_LOG_V(INFO, ES_RH_TAG, "gCloudResource.authServerUrl %s", gCloudResource.authProvider);
    }

    char *ciServer = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CISERVER, &ciServer))
    {
        OICStrcpy(gCloudResource.ciServer, sizeof(gCloudResource.ciServer), ciServer);
        OICStrcpy(cloudData->ciServer, sizeof(cloudData->ciServer), ciServer);
        OIC_LOG_V(INFO, ES_RH_TAG, "gCloudResource.ciServer %s", gCloudResource.ciServer);
    }

    if(gReadUserdataCb)
    {
        gReadUserdataCb(input, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER, &cloudData->userdata);
    }

    if(authCode || authProvider || ciServer)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Send CloudRsrc Callback To ES");

        // TODO : Need to check appropriateness of gCloudData
        if(gCloudRsrcEvtCb != NULL)
        {
            gCloudRsrcEvtCb(ES_OK, cloudData);
        }
        else
        {
            OIC_LOG(ERROR, ES_RH_TAG, "gCloudRsrcEvtCb is NULL");
        }
    }

    OICFree(cloudData);
}

void updateDevConfResource(OCRepPayload* input)
{
    ESDevConfProvData* devConfData = (ESDevConfProvData*)OICMalloc(sizeof(ESDevConfProvData));

    if(devConfData == NULL)
    {
        OIC_LOG(DEBUG, ES_RH_TAG, "OICMalloc is failed");
        return;
    }
    memset(devConfData->language, 0, OIC_STRING_MAX_VALUE);
    memset(devConfData->country, 0, OIC_STRING_MAX_VALUE);
    devConfData->userdata = NULL;

    char *country = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_COUNTRY, &country))
    {
        OICStrcpy(gDevConfResource.country, sizeof(gDevConfResource.country), country);
        OICStrcpy(devConfData->country, sizeof(devConfData->country), country);
        OIC_LOG_V(INFO, ES_RH_TAG, "gDevConfResource.country %s", gDevConfResource.country);
    }

    char *language = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_LANGUAGE, &language))
    {
        OICStrcpy(gDevConfResource.language, sizeof(gDevConfResource.language), language);
        OICStrcpy(devConfData->language, sizeof(devConfData->language), language);
        OIC_LOG_V(INFO, ES_RH_TAG, "gDevConfResource.language %s", gDevConfResource.language);
    }

    if(gReadUserdataCb)
    {
        gReadUserdataCb(input, OC_RSRVD_ES_RES_TYPE_DEVCONF, &devConfData->userdata);
    }

    if(country || language)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Send DevConfRsrc Callback To ES");

        // TODO : Need to check appropriateness of gDevConfData
        if(gDevConfRsrcEvtCb != NULL)
        {
            gDevConfRsrcEvtCb(ES_OK, devConfData);
        }
        else
        {
            OIC_LOG(ERROR, ES_RH_TAG, "gDevConfRsrcEvtCb is NULL");
        }
    }

    OICFree(devConfData);
}

OCRepPayload* constructResponseOfWiFi()
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse wifi res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_WIFI);

    size_t dimensions[MAX_REP_ARRAY_DEPTH] = {gWiFiResource.numMode, 0, 0};
    int64_t *modes_64 = (int64_t *)OICMalloc(gWiFiResource.numMode * sizeof(int64_t));
    for(int i = 0 ; i < gWiFiResource.numMode ; ++i)
    {
        modes_64[i] = gWiFiResource.supportedMode[i];
    }
    OCRepPayloadSetIntArray(payload, OC_RSRVD_ES_SUPPORTEDWIFIMODE, (int64_t *)modes_64, dimensions);

    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_SUPPORTEDWIFIFREQ, gWiFiResource.supportedFreq);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_SSID, gWiFiResource.ssid);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CRED, gWiFiResource.cred);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_AUTHTYPE, (int) gWiFiResource.authType);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_ENCTYPE, (int) gWiFiResource.encType);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_WIFI);
    }

    return payload;
}

OCRepPayload* constructResponseOfCloud()
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse prov res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_CLOUDSERVER);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_AUTHCODE, gCloudResource.authCode);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_AUTHPROVIDER, gCloudResource.authProvider);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CISERVER, gCloudResource.ciServer);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER);
    }

    return payload;
}

OCRepPayload* constructResponseOfDevConf()
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse prov res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_DEVCONF);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_DEVNAME, gDevConfResource.devName);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_LANGUAGE, gDevConfResource.language);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_COUNTRY, gDevConfResource.country);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_DEVCONF);
    }

    return payload;
}

OCRepPayload* constructResponseOfProv(OCEntityHandlerRequest *ehRequest)
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse prov res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_PROV);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_PROVSTATUS, gProvResource.status);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_LAST_ERRORCODE, gProvResource.lastErrCode);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_LINKS, gProvResource.ocfWebLinks);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_PROV);
    }

    if(ehRequest->query)
    {
        if(strstr(ehRequest->query, OC_RSRVD_INTERFACE_BATCH))
        {// When Provisioning resource has a GET with BatchInterface
            payload->next = constructResponseOfWiFi();

            if(payload->next)
            {
                payload->next->next = constructResponseOfCloud();
            }
            else
            {
                return payload;
            }

            if(payload->next->next)
            {
                payload->next->next->next = constructResponseOfDevConf();
            }
            else
            {
                return payload;
            }
        }
    }

    return payload;
}<commit_msg>Fix a logic in linking child representation payload in batch interface<commit_after>//******************************************************************
//
// Copyright 2015 Samsung Electronics All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// 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 "resourcehandler.h"

#include "ocpayload.h"
#include "oic_string.h"
#include "oic_malloc.h"

/**
 * @var ES_RH_TAG
 * @brief Logging tag for module name.
 */
#define ES_RH_TAG "ES_RH"
//-----------------------------------------------------------------------------
// Private variables
//-----------------------------------------------------------------------------

/**
 * @var gProvResource
 * @brief Structure for holding the Provisioning status and target information required to
 * connect to the target network
 */
static ProvResource gProvResource;
static WiFiResource gWiFiResource;
static CloudResource gCloudResource;
static DevConfResource gDevConfResource;

//-----------------------------------------------------------------------------
// Private internal function prototypes
//-----------------------------------------------------------------------------
OCEntityHandlerResult OCEntityHandlerCb(OCEntityHandlerFlag flag, OCEntityHandlerRequest *ehRequest,
        void *callback);
OCEntityHandlerResult ProcessGetRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload** payload);
OCEntityHandlerResult ProcessPutRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload** payload);
OCEntityHandlerResult ProcessPostRequest(OCEntityHandlerRequest *ehRequest, OCRepPayload** payload);
void updateProvResource(OCEntityHandlerRequest* ehRequest, OCRepPayload* input);
void updateWiFiResource(OCRepPayload* input);
void updateCloudResource(OCRepPayload* input);
void updateDevConfResource(OCRepPayload* input);
const char *getResult(OCStackResult result);

ESWiFiCB gWifiRsrcEvtCb = NULL;
ESCloudCB gCloudRsrcEvtCb = NULL;
ESDevConfCB gDevConfRsrcEvtCb = NULL;

ESReadUserdataCb gReadUserdataCb = NULL;
ESWriteUserdataCb gWriteUserdataCb = NULL;

ESResult SetCallbackForUserData(ESReadUserdataCb readCb, ESWriteUserdataCb writeCb)
{
    if(!readCb && !writeCb)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Both of callbacks for user data are null");
        return ES_ERROR;
    }
    gReadUserdataCb = readCb;
    gWriteUserdataCb = writeCb;
    return ES_OK;
}

void RegisterWifiRsrcEventCallBack(ESWiFiCB cb)
{
    gWifiRsrcEvtCb = cb;
}

void RegisterCloudRsrcEventCallBack(ESCloudCB cb)
{
    gCloudRsrcEvtCb = cb;
}

void RegisterDevConfRsrcEventCallBack(ESDevConfCB cb)
{
    gDevConfRsrcEvtCb = cb;
}

void UnRegisterResourceEventCallBack()
{
    if (gWifiRsrcEvtCb)
    {
        gWifiRsrcEvtCb = NULL;
    }
    if (gCloudRsrcEvtCb)
    {
        gCloudRsrcEvtCb = NULL;
    }
    if (gDevConfRsrcEvtCb)
    {
        gDevConfRsrcEvtCb = NULL;
    }
}

void GetTargetNetworkInfoFromProvResource(char *name, char *pass)
{
    if (name != NULL && pass != NULL)
    {
        OICStrcpy(name, MAX_SSIDLEN, gWiFiResource.ssid);
        OICStrcpy(pass, MAX_CREDLEN, gWiFiResource.cred);
    }
}

OCStackResult initProvResource(bool isSecured)
{
    gProvResource.status = ES_STATE_INIT;
    gProvResource.lastErrCode = ES_ERRCODE_NO_ERROR;
    OICStrcpy(gProvResource.ocfWebLinks, MAX_WEBLINKLEN, "");

    OCStackResult res = OC_STACK_ERROR;
    if (isSecured)
    {
        res = OCCreateResource(&gProvResource.handle, OC_RSRVD_ES_RES_TYPE_PROV,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_PROV, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gProvResource.handle, OC_RSRVD_ES_RES_TYPE_PROV,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_PROV, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }
    if(res)
    {
        OIC_LOG_V(INFO, ES_RH_TAG, "Created Prov resource with result: %s", getResult(res));
        return res;
    }

    res = OCBindResourceInterfaceToResource(gProvResource.handle, OC_RSRVD_INTERFACE_LL);
    if(res)
    {
        OIC_LOG_V(INFO, ES_RH_TAG, "Binding Resource interface with result: %s", getResult(res));
        return res;
    }
    res = OCBindResourceInterfaceToResource(gProvResource.handle, OC_RSRVD_INTERFACE_BATCH);
    if(res)
    {
        OIC_LOG_V(INFO, ES_RH_TAG, "Binding Resource interface with result: %s", getResult(res));
        return res;
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created Prov resource with result: %s", getResult(res));
    return res;
}

OCStackResult initWiFiResource(bool isSecured)
{
    OCStackResult res = OC_STACK_ERROR;

    gWiFiResource.supportedFreq = WIFI_BOTH;
    gWiFiResource.supportedMode[0] = WIFI_11A;
    gWiFiResource.supportedMode[1] = WIFI_11B;
    gWiFiResource.supportedMode[2] = WIFI_11G;
    gWiFiResource.supportedMode[3] = WIFI_11N;
    gWiFiResource.numMode = 4;
    gWiFiResource.authType = NONE_AUTH;
    gWiFiResource.encType = NONE_ENC;
    OICStrcpy(gWiFiResource.ssid, sizeof(gWiFiResource.ssid), "");
    OICStrcpy(gWiFiResource.cred, sizeof(gWiFiResource.cred), "");

    if (isSecured)
    {
        res = OCCreateResource(&gWiFiResource.handle, OC_RSRVD_ES_RES_TYPE_WIFI,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_WIFI, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gWiFiResource.handle, OC_RSRVD_ES_RES_TYPE_WIFI,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_WIFI, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created WiFi resource with result: %s", getResult(res));
    return res;

}

OCStackResult initCloudServerResource(bool isSecured)
{
    OCStackResult res = OC_STACK_ERROR;

    OICStrcpy(gCloudResource.authCode, sizeof(gCloudResource.authCode), "");
    OICStrcpy(gCloudResource.authProvider, sizeof(gCloudResource.authProvider), "");
    OICStrcpy(gCloudResource.ciServer, sizeof(gCloudResource.ciServer), "");

    if (isSecured)
    {
        res = OCCreateResource(&gCloudResource.handle, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_CLOUDSERVER, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gCloudResource.handle, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_CLOUDSERVER, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created CloudServer resource with result: %s", getResult(res));
    return res;

}

OCStackResult initDevConfResource(bool isSecured)
{
    OCStackResult res = OC_STACK_ERROR;

    OICStrcpy(gDevConfResource.devName, sizeof(gDevConfResource.devName), "");
    OICStrcpy(gDevConfResource.country, sizeof(gDevConfResource.country), "");
    OICStrcpy(gDevConfResource.language, sizeof(gDevConfResource.language), "");

    if (isSecured)
    {
        res = OCCreateResource(&gDevConfResource.handle, OC_RSRVD_ES_RES_TYPE_DEVCONF,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_DEVCONF, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE);
    }else
    {
        res = OCCreateResource(&gDevConfResource.handle, OC_RSRVD_ES_RES_TYPE_DEVCONF,
        OC_RSRVD_INTERFACE_DEFAULT,
        OC_RSRVD_ES_URI_DEVCONF, OCEntityHandlerCb,
        NULL, OC_DISCOVERABLE | OC_OBSERVABLE);
    }

    OIC_LOG_V(INFO, ES_RH_TAG, "Created DevConf resource with result: %s", getResult(res));
    return res;

}

void updateProvResource(OCEntityHandlerRequest* ehRequest, OCRepPayload* input)
{
    OIC_LOG_V(INFO, ES_RH_TAG, "gProvResource.status %d", gProvResource.status);

    if(ehRequest->query)
    {
        if(strstr(ehRequest->query, OC_RSRVD_INTERFACE_BATCH))
        {
        // When Provisioning resource has a POST with BatchInterface
            updateCloudResource(input);
            updateWiFiResource(input);
            updateDevConfResource(input);
        }
    }
}

void updateWiFiResource(OCRepPayload* input)
{
    ESWiFiProvData* wiFiData = (ESWiFiProvData*)OICMalloc(sizeof(ESWiFiProvData));

    if(wiFiData == NULL)
    {
        OIC_LOG(DEBUG, ES_RH_TAG, "OICMalloc is failed");
        return ;
    }

    memset(wiFiData->ssid, 0, MAX_SSIDLEN);
    memset(wiFiData->pwd, 0, MAX_CREDLEN);
    wiFiData->authtype = NONE_AUTH;
    wiFiData->enctype = NONE_AUTH;
    wiFiData->userdata = NULL;

    char* ssid = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_SSID, &ssid))
    {
        OICStrcpy(gWiFiResource.ssid, sizeof(gWiFiResource.ssid), ssid);
        OICStrcpy(wiFiData->ssid, sizeof(wiFiData->ssid), ssid);
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.ssid : %s", gWiFiResource.ssid);
    }

    char* cred = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CRED, &cred))
    {
        OICStrcpy(gWiFiResource.cred, sizeof(gWiFiResource.cred), cred);
        OICStrcpy(wiFiData->pwd, sizeof(wiFiData->pwd), cred);
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.cred %s", gWiFiResource.cred);
    }

    int64_t authType = -1;
    if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_AUTHTYPE, &authType))
    {
        gWiFiResource.authType = authType;
        wiFiData->authtype = gWiFiResource.authType;
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.authType %u", gWiFiResource.authType);
    }

    int64_t encType = -1;
    if (OCRepPayloadGetPropInt(input, OC_RSRVD_ES_ENCTYPE, &encType))
    {
        gWiFiResource.encType = encType;
        wiFiData->enctype = gWiFiResource.encType;
        OIC_LOG_V(INFO, ES_RH_TAG, "gWiFiResource.encType %u", gWiFiResource.encType);
    }

    if(gReadUserdataCb)
    {
        gReadUserdataCb(input, OC_RSRVD_ES_RES_TYPE_WIFI, &wiFiData->userdata);
    }

    if(ssid || cred || authType!= -1 || encType != -1)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Send WiFiRsrc Callback To ES");

        // TODO : Need to check appropriateness of gWiFiData
        if(gWifiRsrcEvtCb != NULL)
        {
            gWifiRsrcEvtCb(ES_OK, wiFiData);
        }
        else
        {
            OIC_LOG(ERROR, ES_RH_TAG, "gWifiRsrcEvtCb is NULL");
        }
    }

    OICFree(wiFiData);
}

void updateCloudResource(OCRepPayload* input)
{
    ESCloudProvData* cloudData = (ESCloudProvData*)OICMalloc(sizeof(ESCloudProvData));

    if(cloudData == NULL)
    {
        OIC_LOG(DEBUG, ES_RH_TAG, "OICMalloc is failed");
        return;
    }

    memset(cloudData->authCode, 0, OIC_STRING_MAX_VALUE);
    memset(cloudData->authProvider, 0, OIC_STRING_MAX_VALUE);
    memset(cloudData->ciServer, 0, OIC_STRING_MAX_VALUE);
    cloudData->userdata = NULL;

    char *authCode = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_AUTHCODE, &authCode))
    {
        OICStrcpy(gCloudResource.authCode, sizeof(gCloudResource.authCode), authCode);
        OICStrcpy(cloudData->authCode, sizeof(cloudData->authCode), authCode);
        OIC_LOG_V(INFO, ES_RH_TAG, "gCloudResource.authCode %s", gCloudResource.authCode);
    }

    char *authProvider = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_AUTHPROVIDER, &authProvider))
    {
        OICStrcpy(gCloudResource.authProvider, sizeof(gCloudResource.authProvider), authProvider);
        OICStrcpy(cloudData->authProvider, sizeof(cloudData->authProvider), authProvider);
        OIC_LOG_V(INFO, ES_RH_TAG, "gCloudResource.authServerUrl %s", gCloudResource.authProvider);
    }

    char *ciServer = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_CISERVER, &ciServer))
    {
        OICStrcpy(gCloudResource.ciServer, sizeof(gCloudResource.ciServer), ciServer);
        OICStrcpy(cloudData->ciServer, sizeof(cloudData->ciServer), ciServer);
        OIC_LOG_V(INFO, ES_RH_TAG, "gCloudResource.ciServer %s", gCloudResource.ciServer);
    }

    if(gReadUserdataCb)
    {
        gReadUserdataCb(input, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER, &cloudData->userdata);
    }

    if(authCode || authProvider || ciServer)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Send CloudRsrc Callback To ES");

        // TODO : Need to check appropriateness of gCloudData
        if(gCloudRsrcEvtCb != NULL)
        {
            gCloudRsrcEvtCb(ES_OK, cloudData);
        }
        else
        {
            OIC_LOG(ERROR, ES_RH_TAG, "gCloudRsrcEvtCb is NULL");
        }
    }

    OICFree(cloudData);
}

void updateDevConfResource(OCRepPayload* input)
{
    ESDevConfProvData* devConfData = (ESDevConfProvData*)OICMalloc(sizeof(ESDevConfProvData));

    if(devConfData == NULL)
    {
        OIC_LOG(DEBUG, ES_RH_TAG, "OICMalloc is failed");
        return;
    }
    memset(devConfData->language, 0, OIC_STRING_MAX_VALUE);
    memset(devConfData->country, 0, OIC_STRING_MAX_VALUE);
    devConfData->userdata = NULL;

    char *country = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_COUNTRY, &country))
    {
        OICStrcpy(gDevConfResource.country, sizeof(gDevConfResource.country), country);
        OICStrcpy(devConfData->country, sizeof(devConfData->country), country);
        OIC_LOG_V(INFO, ES_RH_TAG, "gDevConfResource.country %s", gDevConfResource.country);
    }

    char *language = NULL;
    if (OCRepPayloadGetPropString(input, OC_RSRVD_ES_LANGUAGE, &language))
    {
        OICStrcpy(gDevConfResource.language, sizeof(gDevConfResource.language), language);
        OICStrcpy(devConfData->language, sizeof(devConfData->language), language);
        OIC_LOG_V(INFO, ES_RH_TAG, "gDevConfResource.language %s", gDevConfResource.language);
    }

    if(gReadUserdataCb)
    {
        gReadUserdataCb(input, OC_RSRVD_ES_RES_TYPE_DEVCONF, &devConfData->userdata);
    }

    if(country || language)
    {
        OIC_LOG(INFO, ES_RH_TAG, "Send DevConfRsrc Callback To ES");

        // TODO : Need to check appropriateness of gDevConfData
        if(gDevConfRsrcEvtCb != NULL)
        {
            gDevConfRsrcEvtCb(ES_OK, devConfData);
        }
        else
        {
            OIC_LOG(ERROR, ES_RH_TAG, "gDevConfRsrcEvtCb is NULL");
        }
    }

    OICFree(devConfData);
}

OCRepPayload* constructResponseOfWiFi()
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse wifi res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_WIFI);

    size_t dimensions[MAX_REP_ARRAY_DEPTH] = {gWiFiResource.numMode, 0, 0};
    int64_t *modes_64 = (int64_t *)OICMalloc(gWiFiResource.numMode * sizeof(int64_t));
    for(int i = 0 ; i < gWiFiResource.numMode ; ++i)
    {
        modes_64[i] = gWiFiResource.supportedMode[i];
    }
    OCRepPayloadSetIntArray(payload, OC_RSRVD_ES_SUPPORTEDWIFIMODE, (int64_t *)modes_64, dimensions);

    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_SUPPORTEDWIFIFREQ, gWiFiResource.supportedFreq);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_SSID, gWiFiResource.ssid);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CRED, gWiFiResource.cred);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_AUTHTYPE, (int) gWiFiResource.authType);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_ENCTYPE, (int) gWiFiResource.encType);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_WIFI);
    }

    return payload;
}

OCRepPayload* constructResponseOfCloud()
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse prov res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_CLOUDSERVER);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_AUTHCODE, gCloudResource.authCode);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_AUTHPROVIDER, gCloudResource.authProvider);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_CISERVER, gCloudResource.ciServer);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_CLOUDSERVER);
    }

    return payload;
}

OCRepPayload* constructResponseOfDevConf()
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse prov res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_DEVCONF);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_DEVNAME, gDevConfResource.devName);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_LANGUAGE, gDevConfResource.language);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_COUNTRY, gDevConfResource.country);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_DEVCONF);
    }

    return payload;
}

OCRepPayload* constructResponseOfProv(OCEntityHandlerRequest *ehRequest)
{
    OCRepPayload* payload = OCRepPayloadCreate();
    if (!payload)
    {
        OIC_LOG(ERROR, ES_RH_TAG, "Failed to allocate Payload");
        return NULL;
    }

    OIC_LOG(INFO, ES_RH_TAG, "constructResponse prov res");
    OCRepPayloadSetUri(payload, OC_RSRVD_ES_URI_PROV);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_PROVSTATUS, gProvResource.status);
    OCRepPayloadSetPropInt(payload, OC_RSRVD_ES_LAST_ERRORCODE, gProvResource.lastErrCode);
    OCRepPayloadSetPropString(payload, OC_RSRVD_ES_LINKS, gProvResource.ocfWebLinks);

    if(gWriteUserdataCb)
    {
        gWriteUserdataCb(payload, OC_RSRVD_ES_RES_TYPE_PROV);
    }

    if(ehRequest->query)
    {
        if(strstr(ehRequest->query, OC_RSRVD_INTERFACE_BATCH))
        {// When Provisioning resource has a GET with BatchInterface
            OCRepPayload* head = payload;
            OCRepPayload* nextPayload = NULL;

            nextPayload = constructResponseOfWiFi();
            if(nextPayload != NULL)
            {
                payload->next = nextPayload;
                payload = payload->next;
            }

            nextPayload = constructResponseOfCloud();
            if(nextPayload != NULL)
            {
                payload->next = nextPayload;
                payload = payload->next;
            }

            nextPayload = constructResponseOfDevConf();
            if(nextPayload != NULL)
            {
                payload->next = nextPayload;
                payload = payload->next;
            }

            payload = head;
        }
    }

    return payload;
}
{'fraction_non_alphanumeric': 0.12030391460945922, 'fraction_numerical': 0.0027867602597470885, 'mean_word_length': 3.3671641791044777, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 88, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '669428', 'n_tokens_mistral': 13772, 'n_tokens_neox': 13295, 'n_words': 2142}