/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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 "sync.h"
#include <utils/Log.h>
#include "nan.h"
#include "wifi_hal.h"
#include "nan_i.h"
#include "nancommand.h"


int NanCommand::isNanResponse()
{
    if (mNanVendorEvent == NULL) {
        ALOGE("NULL check failed");
        return WIFI_ERROR_INVALID_ARGS;
    }

    NanMsgHeader *pHeader = (NanMsgHeader *)mNanVendorEvent;

    switch (pHeader->msgId) {
    case NAN_MSG_ID_ERROR_RSP:
    case NAN_MSG_ID_CONFIGURATION_RSP:
    case NAN_MSG_ID_PUBLISH_SERVICE_CANCEL_RSP:
    case NAN_MSG_ID_PUBLISH_SERVICE_RSP:
    case NAN_MSG_ID_SUBSCRIBE_SERVICE_RSP:
    case NAN_MSG_ID_SUBSCRIBE_SERVICE_CANCEL_RSP:
    case NAN_MSG_ID_TRANSMIT_FOLLOWUP_RSP:
    case NAN_MSG_ID_STATS_RSP:
    case NAN_MSG_ID_ENABLE_RSP:
    case NAN_MSG_ID_DISABLE_RSP:
    case NAN_MSG_ID_TCA_RSP:
#ifdef NAN_2_0
    case NAN_MSG_ID_BEACON_SDF_RSP:
#endif /* NAN_2_0 */
        return 1;
    default:
        return 0;
    }
}


int NanCommand::getNanResponse(NanResponseMsg *pRsp)
{
    if (mNanVendorEvent == NULL || pRsp == NULL) {
        ALOGE("NULL check failed");
        return WIFI_ERROR_INVALID_ARGS;
    }

    NanMsgHeader *pHeader = (NanMsgHeader *)mNanVendorEvent;

    switch (pHeader->msgId) {
        case NAN_MSG_ID_ERROR_RSP:
        {
            pNanErrorRspMsg pFwRsp = \
                (pNanErrorRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_ERROR;
            break;
        }
        case NAN_MSG_ID_CONFIGURATION_RSP:
        {
            pNanConfigurationRspMsg pFwRsp = \
                (pNanConfigurationRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_CONFIG;
        }
        break;
        case NAN_MSG_ID_PUBLISH_SERVICE_CANCEL_RSP:
        {
            pNanPublishServiceCancelRspMsg pFwRsp = \
                (pNanPublishServiceCancelRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_PUBLISH_CANCEL;
            break;
        }
        case NAN_MSG_ID_PUBLISH_SERVICE_RSP:
        {
            pNanPublishServiceRspMsg pFwRsp = \
                (pNanPublishServiceRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_PUBLISH;
            break;
        }
        case NAN_MSG_ID_SUBSCRIBE_SERVICE_RSP:
        {
            pNanSubscribeServiceRspMsg pFwRsp = \
                (pNanSubscribeServiceRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_SUBSCRIBE;
        }
        break;
        case NAN_MSG_ID_SUBSCRIBE_SERVICE_CANCEL_RSP:
        {
            pNanSubscribeServiceCancelRspMsg pFwRsp = \
                (pNanSubscribeServiceCancelRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_SUBSCRIBE_CANCEL;
            break;
        }
        case NAN_MSG_ID_TRANSMIT_FOLLOWUP_RSP:
        {
            pNanTransmitFollowupRspMsg pFwRsp = \
                (pNanTransmitFollowupRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_TRANSMIT_FOLLOWUP;
            break;
        }
        case NAN_MSG_ID_STATS_RSP:
        {
            pNanStatsRspMsg pFwRsp = \
                (pNanStatsRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->statsRspParams.status;
            pRsp->value = pFwRsp->statsRspParams.value;
            pRsp->response_type = NAN_RESPONSE_STATS;
            pRsp->body.stats_response.stats_id = \
                (NanStatsId)pFwRsp->statsRspParams.statsId;
            ALOGI("%s: stats_id:%d",__func__,
                  pRsp->body.stats_response.stats_id);
            u8 *pInputTlv = pFwRsp->ptlv;
            NanTlv outputTlv;
            memset(&outputTlv, 0, sizeof(outputTlv));
            u16 readLen = 0;
            int remainingLen = (mNanDataLen -  \
                (sizeof(NanMsgHeader) + sizeof(NanStatsRspParams)));

            if (remainingLen > 0) {
                readLen = NANTLV_ReadTlv(pInputTlv, &outputTlv);
                ALOGI("%s: Remaining Len:%d readLen:%d type:%d length:%d",
                      __func__, remainingLen, readLen, outputTlv.type,
                      outputTlv.length);
                if (outputTlv.length <= \
                    sizeof(pRsp->body.stats_response.data)) {
                    memcpy(&pRsp->body.stats_response.data, outputTlv.value,
                           outputTlv.length);
                    hexdump((char*)&pRsp->body.stats_response.data, outputTlv.length);
                }
                else {
                    ALOGE("%s:copying only sizeof(pRsp->body.stats_response.data):%d",
                          __func__, sizeof(pRsp->body.stats_response.data));
                    memcpy(&pRsp->body.stats_response.data, outputTlv.value,
                           sizeof(pRsp->body.stats_response.data));
                    hexdump((char*)&pRsp->body.stats_response.data,
                            sizeof(pRsp->body.stats_response.data));
                }
            }
            else
                ALOGI("%s: No TLV's present",__func__);
            break;
        }
        case NAN_MSG_ID_ENABLE_RSP:
        {
            pNanEnableRspMsg pFwRsp = \
                (pNanEnableRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_ENABLED;
            break;
        }
        case NAN_MSG_ID_DISABLE_RSP:
        {
            pNanDisableRspMsg pFwRsp = \
                (pNanDisableRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = 0;
            pRsp->response_type = NAN_RESPONSE_DISABLED;
            break;
        }
        case NAN_MSG_ID_TCA_RSP:
        {
            pNanTcaRspMsg pFwRsp = \
                (pNanTcaRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = pFwRsp->value;
            pRsp->response_type = NAN_RESPONSE_TCA;
            break;
        }
#ifdef NAN_2_0
        case NAN_MSG_ID_BEACON_SDF_RSP:
        {
            pNanBeaconSdfPayloadRspMsg pFwRsp = \
                (pNanBeaconSdfPayloadRspMsg)mNanVendorEvent;
            pRsp->header.handle = pFwRsp->fwHeader.handle;
            pRsp->header.transaction_id = pFwRsp->fwHeader.transactionId;
            pRsp->status = pFwRsp->status;
            pRsp->value = 0;
            pRsp->response_type = NAN_RESPONSE_BEACON_SDF_PAYLOAD;
            break;
        }
#endif /* NAN_2_0 */
        default:
            return  -1;
    }
    return  0;
}

int NanCommand::handleNanResponse()
{
    //parse the data and call
    //the response callback handler with the populated
    //NanResponseMsg
    NanResponseMsg  rsp_data;
    int ret;

    ALOGV("handleNanResponse called %p", this);
    memset(&rsp_data, 0, sizeof(rsp_data));
    //get the rsp_data
    ret = getNanResponse(&rsp_data);

    ALOGI("handleNanResponse ret:%d status:%u value:%u response_type:%u",
          ret, rsp_data.status, rsp_data.value, rsp_data.response_type);
    if (ret == 0 && (rsp_data.response_type == NAN_RESPONSE_STATS) &&
        (mStaParam != NULL) &&
        (rsp_data.body.stats_response.stats_id == NAN_STATS_ID_DE_TIMING_SYNC)) {
        /*
           Fill the staParam with appropriate values and return from here.
           No need to call NotifyResponse as the request is for getting the
           STA response
        */
        NanSyncStats *pSyncStats = &rsp_data.body.stats_response.data.sync_stats;
        mStaParam->master_rank = pSyncStats->myRank;
        mStaParam->master_pref = (pSyncStats->myRank & 0xFF00000000000000) >> 56;
        mStaParam->random_factor = (pSyncStats->myRank & 0x00FF000000000000) >> 48;
        mStaParam->hop_count = pSyncStats->currAmHopCount;
        mStaParam->beacon_transmit_time = pSyncStats->currAmBTT;

        return ret;
    }
    //Call the NotifyResponse Handler
    if (ret == 0 && mHandler.NotifyResponse) {
        (*mHandler.NotifyResponse)(&rsp_data, mUserData);
    }
    return ret;
}