/**
 * Function to save the result of provisioning.
 *
 * @param[in,out] otmCtx   Context value of ownership transfer.
 * @param[in] res   result of provisioning
 */
static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
{
    OC_LOG_V(DEBUG, TAG, "IN SetResult : %d ", res);

    if(!otmCtx)
    {
        OC_LOG(WARNING, TAG, "OTMContext is NULL");
        return;
    }

    if(otmCtx->selectedDeviceInfo)
    {
        for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
        {
            if(memcmp(otmCtx->selectedDeviceInfo->doxm->deviceID.id,
                      otmCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0)
            {
                otmCtx->ctxResultArray[i].res = res;
                if(OC_STACK_OK != res)
                {
                    otmCtx->ctxHasError = true;
                }
            }
        }

        g_otmCtx = NULL;

        //If all request is completed, invoke the user callback.
        if(IsComplete(otmCtx))
        {
            otmCtx->ctxResultCallback(otmCtx->userCtx, otmCtx->ctxResultArraySize,
                                       otmCtx->ctxResultArray, otmCtx->ctxHasError);
            OICFree(otmCtx->ctxResultArray);
            OICFree(otmCtx);
        }
        else
        {
            if(OC_STACK_OK != StartOwnershipTransfer(otmCtx,
                                                     otmCtx->selectedDeviceInfo->next))
            {
                OC_LOG(ERROR, TAG, "Failed to StartOwnershipTransfer");
            }
        }
    }

    OC_LOG(DEBUG, TAG, "OUT SetResult");
}
/**
 * NOTE : Unowned discovery should be done before performing OTMDoOwnershipTransfer
 */
OCStackResult OTMDoOwnershipTransfer(void* ctx,
                                     OCProvisionDev_t *selectedDevicelist,
                                     OCProvisionResultCB resultCallback)
{
    OC_LOG(DEBUG, TAG, "IN OTMDoOwnershipTransfer");

    if (NULL == selectedDevicelist || NULL == resultCallback )
    {
        return OC_STACK_INVALID_PARAM;
    }

    OTMContext_t* otmCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t));
    if(!otmCtx)
    {
        OC_LOG(ERROR, TAG, "Failed to create OTM Context");
        return OC_STACK_NO_MEMORY;
    }
    otmCtx->ctxResultCallback = resultCallback;
    otmCtx->ctxHasError = false;
    otmCtx->userCtx = ctx;
    OCProvisionDev_t* pCurDev = selectedDevicelist;

    //Counting number of selected devices.
    otmCtx->ctxResultArraySize = 0;
    while(NULL != pCurDev)
    {
        otmCtx->ctxResultArraySize++;
        pCurDev = pCurDev->next;
    }

    otmCtx->ctxResultArray =
        (OCProvisionResult_t*)OICCalloc(otmCtx->ctxResultArraySize, sizeof(OCProvisionResult_t));
    if(NULL == otmCtx->ctxResultArray)
    {
        OC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Failed to memory allocation");
        OICFree(otmCtx);
        return OC_STACK_NO_MEMORY;
    }
    pCurDev = selectedDevicelist;

    //Fill the device UUID for result array.
    for(size_t devIdx = 0; devIdx < otmCtx->ctxResultArraySize; devIdx++)
    {
        //Checking duplication of Device ID.
        bool isDuplicate = true;
        OCStackResult res = PDMIsDuplicateDevice(&pCurDev->doxm->deviceID, &isDuplicate);
        if (OC_STACK_OK != res)
        {
            OICFree(otmCtx->ctxResultArray);
            OICFree(otmCtx);
            return res;
        }
        if (isDuplicate)
        {
            OC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Device ID is duplicated");
            OICFree(otmCtx->ctxResultArray);
            OICFree(otmCtx);
            return OC_STACK_INVALID_PARAM;
        }
        memcpy(otmCtx->ctxResultArray[devIdx].deviceId.id,
               pCurDev->doxm->deviceID.id,
               UUID_LENGTH);
        otmCtx->ctxResultArray[devIdx].res = OC_STACK_CONTINUE;
        pCurDev = pCurDev->next;
    }
    StartOwnershipTransfer(otmCtx, selectedDevicelist);

    OC_LOG(DEBUG, TAG, "OUT OTMDoOwnershipTransfer");
    return OC_STACK_OK;
}
/**
 * Function to handle the handshake result in OTM.
 * This function will be invoked after DTLS handshake
 * @param   endPoint  [IN] The remote endpoint.
 * @param   errorInfo [IN] Error information from the endpoint.
 * @return  NONE
 */
void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
{
    if(g_otmCtx && endpoint && info)
    {
        OC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
                 endpoint->addr, endpoint->port, info->result);

        //Make sure the address matches.
        if(strncmp(g_otmCtx->selectedDeviceInfo->endpoint.addr,
           endpoint->addr,
           sizeof(endpoint->addr)) == 0 &&
           g_otmCtx->selectedDeviceInfo->securePort == endpoint->port)
        {
            OCStackResult res;

            CARegisterDTLSHandshakeCallback(NULL);

            //In case of success, send next coaps request.
            if(CA_STATUS_OK == info->result)
            {
                //Send request : PUT /oic/sec/doxm [{"Owned":"True", .. , "Owner":"PT's UUID"}]
                res = PutOwnershipInformation(g_otmCtx);
                if(OC_STACK_OK != res)
                {
                    OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to send owner information");
                    SetResult(g_otmCtx, res);
                }
            }
            //In case of failure, re-start the ownership transfer in case of PIN OxM
            else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)
            {
                g_otmCtx->selectedDeviceInfo->doxm->owned = false;
                g_otmCtx->attemptCnt++;

                if(g_otmCtx->selectedDeviceInfo->doxm->oxmSel == OIC_RANDOM_DEVICE_PIN)
                {
                    res = RemoveCredential(&g_otmCtx->subIdForPinOxm);
                    if(OC_STACK_RESOURCE_DELETED != res)
                    {
                        OC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);
                        SetResult(g_otmCtx, res);
                        return;
                    }

                    if(WRONG_PIN_MAX_ATTEMP > g_otmCtx->attemptCnt)
                    {
                        res = StartOwnershipTransfer(g_otmCtx, g_otmCtx->selectedDeviceInfo);
                        if(OC_STACK_OK != res)
                        {
                            SetResult(g_otmCtx, res);
                            OC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
                        }
                    }
                    else
                    {
                        SetResult(g_otmCtx, OC_STACK_AUTHENTICATION_FAILURE);
                    }
                }
                else
                {
                    SetResult(g_otmCtx, OC_STACK_AUTHENTICATION_FAILURE);
                }
            }
        }
    }
}