/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * 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 <stdio.h>
#include <signal.h>
#include <unistd.h>
#include "securec.h"
#include "hdf_base.h"
#include "hdf_io_service_if.h"
#include "hdf_service_status.h"
#include "servmgr_hdi.h"
#include "servstat_listener_hdi.h"
#include "audio_events.h"
#include "hdf_audio_events.h"

#define AUDIO_FUNC_LOGE(fmt, arg...) do { \
        printf("%s: [%s]: [%d]:[ERROR]:" fmt"\n", __FILE__, __func__, __LINE__, ##arg); \
    } while (0)

static int32_t AudioServiceDeviceVal(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_PRIMARY_DEVICE: // primary Service
            printf("*****************: Primary service valid.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_DEVICE: // Usb Service
            printf("*****************: USB service valid.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp Service
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioServiceDeviceInVal(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_PRIMARY_DEVICE: // primary Service
            printf("*****************: Primary service Invalid.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_DEVICE: // Usb Service
            printf("*****************: USB service Invalid.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp Service
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioServiceMsgParse(struct AudioEvent *svcMsg)
{
    if (svcMsg == NULL) {
        return HDF_FAILURE;
    }

    switch (svcMsg->eventType) {
        case HDF_AUDIO_EVENT_UNKOWN:
            return HDF_FAILURE;
        case HDF_AUDIO_SERVICE_VALID:
            return AudioServiceDeviceVal(svcMsg->deviceType);
        case HDF_AUDIO_SERVICE_INVALID:
            return AudioServiceDeviceInVal(svcMsg->deviceType);
        default:
            return HDF_FAILURE;
    }
}

static int AudioGetServiceStatus(const struct ServiceStatus *svcStatus)
{
    if (svcStatus == NULL) {
        return HDF_FAILURE;
    }

    struct AudioEvent serviceMsg = {
        .eventType = HDF_AUDIO_EVENT_UNKOWN,
        .deviceType = HDF_AUDIO_DEVICE_UNKOWN,
    };
    char strTemp[AUDIO_PNP_MSG_LEN_MAX] = {0};
    if (memcpy_s(strTemp, AUDIO_PNP_MSG_LEN_MAX, (char *)svcStatus->info, strlen((char *)svcStatus->info))) {
        return HDF_FAILURE;
    }
    if ((AudioPnpMsgReadValue(strTemp, "EVENT_SERVICE_TYPE", &(serviceMsg.eventType)) != HDF_SUCCESS) ||
        (AudioPnpMsgReadValue(strTemp, "DEVICE_TYPE", &(serviceMsg.deviceType)) != HDF_SUCCESS)) {
        return HDF_FAILURE;
    }
    if (AudioServiceMsgParse(&serviceMsg) != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t AudioLoadDeviceSucc(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_PRIMARY_DEVICE: // primary load
            printf("*****************: Primary load success.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_DEVICE: // Usb load
            printf("*****************: USB load success.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp load
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioLoadDeviceFail(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_PRIMARY_DEVICE: // primary load
            printf("*****************: Primary load fail.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_DEVICE: // Usb load
            printf("*****************: USB load fail.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp load
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioUnLoadDevice(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_PRIMARY_DEVICE: // primary load
            printf("*****************: Primary unload.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_DEVICE: // Usb load
            printf("*****************: USB unload.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp load
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioLoadMsgParse(struct AudioEvent *loadMsg)
{
    if (loadMsg == NULL) {
        return HDF_FAILURE;
    }

    switch (loadMsg->eventType) {
        case HDF_AUDIO_LOAD_SUCCESS:
            return AudioLoadDeviceSucc(loadMsg->deviceType);
        case HDF_AUDIO_LOAD_FAILURE:
            return AudioLoadDeviceFail(loadMsg->deviceType);
        case HDF_AUDIO_UNLOAD:
            return AudioUnLoadDevice(loadMsg->deviceType);
        default:
            return HDF_FAILURE;
    }
}

static int AudioGetLoadStatus(struct ServiceStatus *svcStatus)
{
    if (svcStatus == NULL) {
        return HDF_FAILURE;
    }

    struct AudioEvent loadMsg = {
        .eventType = HDF_AUDIO_EVENT_UNKOWN,
        .deviceType = HDF_AUDIO_DEVICE_UNKOWN,
    };
    char strTemp[AUDIO_PNP_MSG_LEN_MAX] = {0};
    if (memcpy_s(strTemp, AUDIO_PNP_MSG_LEN_MAX, (char *)svcStatus->info, strlen((char *)svcStatus->info))) {
        return HDF_FAILURE;
    }
    if ((AudioPnpMsgReadValue(strTemp, "EVENT_LOAD_TYPE", &(loadMsg.eventType)) != HDF_SUCCESS) ||
        (AudioPnpMsgReadValue(strTemp, "DEVICE_TYPE", &(loadMsg.deviceType)) != HDF_SUCCESS)) {
        return HDF_FAILURE;
    }
    if (AudioLoadMsgParse(&loadMsg) != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static int32_t AudioPnpDeviceAdd(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_USB_HEADPHONE: // USB Audio Add
        case HDF_AUDIO_USBA_HEADPHONE:
            printf("*****************: USB Audio earphone microphone add.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_HEADSET:
        case HDF_AUDIO_USBA_HEADSET:
            printf("*****************: USB Audio earphone mic&speaker add.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp Add
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioPnpDeviceRemove(enum AudioDeviceType deviceType)
{
    switch (deviceType) {
        case HDF_AUDIO_USB_HEADPHONE: // USB Audio Remove
        case HDF_AUDIO_USBA_HEADPHONE:
            printf("*****************: USB Audio earphone microphone remove.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_USB_HEADSET:
        case HDF_AUDIO_USBA_HEADSET:
            printf("*****************: USB Audio earphone mic&speaker remove.\n");
            return HDF_SUCCESS;
        case HDF_AUDIO_A2DP_DEVICE: // A2dp Remove
            return HDF_ERR_NOT_SUPPORT;
        default:
            return HDF_FAILURE;
    }
}

static int32_t AudioPnpMsgParse(struct AudioEvent *pnpMsg)
{
    if (pnpMsg == NULL) {
        return HDF_FAILURE;
    }

    switch (pnpMsg->eventType) {
        case HDF_AUDIO_EVENT_UNKOWN:
            return HDF_FAILURE;
        case HDF_AUDIO_DEVICE_ADD:
            return AudioPnpDeviceAdd(pnpMsg->deviceType);
        case HDF_AUDIO_DEVICE_REMOVE:
            return AudioPnpDeviceRemove(pnpMsg->deviceType);
        default:
            return HDF_FAILURE;
    }
}

static int AudioGetUsbPnpStatus(struct ServiceStatus *svcStatus)
{
    if (svcStatus == NULL) {
        return HDF_FAILURE;
    }

    struct AudioEvent pnpMsg = {
        .eventType = HDF_AUDIO_EVENT_UNKOWN,
        .deviceType = HDF_AUDIO_DEVICE_UNKOWN,
    };
    char strTemp[AUDIO_PNP_MSG_LEN_MAX] = {0};
    if (memcpy_s(strTemp, AUDIO_PNP_MSG_LEN_MAX, (char *)svcStatus->info, strlen((char *)svcStatus->info))) {
        return HDF_FAILURE;
    }
    if ((AudioPnpMsgReadValue(strTemp, "EVENT_TYPE", &(pnpMsg.eventType)) != HDF_SUCCESS) ||
        (AudioPnpMsgReadValue(strTemp, "DEVICE_TYPE", &(pnpMsg.deviceType)) != HDF_SUCCESS)) {
        return HDF_FAILURE;
    }
    if (AudioPnpMsgParse(&pnpMsg) != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    return HDF_SUCCESS;
}

static void AudioUsbPnpOnSvcStatusReceived(struct ServiceStatusListener *listener, struct ServiceStatus *svcStatus)
{
    if (listener == NULL || svcStatus == NULL) {
        AUDIO_FUNC_LOGE("listener or svcStatus is NULL!");
        return;
    }

    printf("\n===============================================================================\n"
           "@@@@@ serviceName: %s\n"
           "@@@@@ deviceClass: %d\n"
           "@@@@@ status     : %d\n"
           "@@@@@ info       : %s"
           "\n===============================================================================\n",
        svcStatus->serviceName, svcStatus->deviceClass, svcStatus->status, svcStatus->info);

    (void)AudioGetUsbPnpStatus(svcStatus);
    (void)AudioGetLoadStatus(svcStatus);
    (void)AudioGetServiceStatus(svcStatus);
}

static struct HDIServiceManager *g_servmgr = NULL;
static struct ServiceStatusListener *g_listener = NULL;
static bool g_listenerState = false;

static void StopListenerBySig(int32_t sig)
{
    printf("%s: Signal = %d\n", __func__, sig);
    if (g_servmgr == NULL || g_listener == NULL) {
        AUDIO_FUNC_LOGE("g_servmgr or g_listener is null!\n");
        return;
    }

    int32_t ret = g_servmgr->UnregisterServiceStatusListener(g_servmgr, g_listener);
    if (ret != HDF_SUCCESS) {
        AUDIO_FUNC_LOGE("UnregisterServiceStatusListener fail! ret = %d.\n", ret);
        return;
    }
    HdiServiceStatusListenerFree(g_listener);
    HDIServiceManagerRelease(g_servmgr);
    g_listenerState = false;
    g_servmgr = NULL;
    return;
}

int main(void)
{
    printf("%s: system audio listener start \n", __func__);
    g_servmgr = HDIServiceManagerGet();
    if (g_servmgr == NULL) {
        AUDIO_FUNC_LOGE("HDIServiceManagerGet failed.\n");
        return HDF_FAILURE;
    }
    g_listener = HdiServiceStatusListenerNewInstance();
    if (g_listener == NULL) {
        AUDIO_FUNC_LOGE("HdiServiceStatusListenerNewInstance failed.\n");
        HDIServiceManagerRelease(g_servmgr);
        g_servmgr = NULL;
        return HDF_FAILURE;
    }
    g_listener->callback = AudioUsbPnpOnSvcStatusReceived;
    int32_t status = g_servmgr->RegisterServiceStatusListener(g_servmgr, g_listener, DEVICE_CLASS_AUDIO);
    if (status != HDF_SUCCESS) {
        AUDIO_FUNC_LOGE("RegisterServiceStatusListener fail! ret = %d.\n", status);
        HDIServiceManagerRelease(g_servmgr);
        g_servmgr = NULL;
        HdiServiceStatusListenerFree(g_listener);
        return HDF_FAILURE;
    }
    g_listenerState = true;
    (void)signal(SIGINT, StopListenerBySig);
    (void)signal(SIGTERM, StopListenerBySig);
    while (g_listenerState) {
        sleep(1); // Wait for 1 second
    }

    return HDF_SUCCESS;
}