/*
 * Copyright 2022 NXP.
 * This software is owned or controlled by NXP and may only be used strictly in accordance with the
 * license terms that accompany it. By expressly accepting such terms or by downloading, installing,
 * activating and/or otherwise using the software, you are agreeing that you have read, and that you
 * agree to comply with and are bound by, such license terms. If you do not agree to be bound by the
 * applicable license terms, then you may not retain, install, activate or otherwise use the software.
 */

/*
 * @brief Ui coffee machine output HAL device implementation.
 */

#include "board_define.h"
#ifdef ENABLE_OUTPUT_DEV_UiSliderProgress

#include "FreeRTOS.h"
#include "board.h"

#include "app_config.h"

#include "fwk_graphics.h"
#include "fwk_log.h"
#include "fwk_timer.h"
#include "fwk_output_manager.h"
#include "fwk_lpm_manager.h"
#include "hal_output_dev.h"
#include "hal_vision_algo.h"
#include "hal_voice_algo_asr_local.h"
#include "hal_event_descriptor_common.h"
#include "hal_event_descriptor_face_rec.h"
#include "hal_event_descriptor_voice.h"

#include "smart_tlhmi_event_descriptor.h"

#include "custom.h"

/*******************************************************************************
 * Definitions
 ******************************************************************************/

/*
     |<------------640------------------>|
___  ____________________________________   ____
 |   |                                   |    |
 |   |-----------------------------------|  --|<--- UI_TOPINFO_Y
 |   |       Top Info                    |    |
 |   |-----------------------------------|  --|<--- UI_MAINWINDOW_Y = UI_TOPINFO_Y+UI_TOPINFO_H
 |   |                                   |    |
 |   |                                   |    |
480  |      Main Window                  |    |
 |   |                                   |    |
 |   |                                   |    |
 |   |                                   |    |
 |   |-----------------------------------|  --|<--- UI_BOTTOMINFO_H = UI_MAINWINDOW_Y+UI_MAINWINDOW_H
 |   |        Bottom Info                |    |
_|_  |___________________________________|  __|_

*/

#define UI_BUFFER_WIDTH  640
#define UI_BUFFER_HEIGHT 480
#define UI_BUFFER_BPP    2
#define UI_BUFFER_PITCH  (UI_BUFFER_WIDTH * UI_BUFFER_BPP)
#define UI_SCALE_W       (640 / UI_BUFFER_WIDTH)
#define UI_SCALE_H       (480 / UI_BUFFER_HEIGHT)

#define UI_GUIDE_RECT_W 360
#define UI_GUIDE_RECT_H 300

#define UI_TOPINFO_W    UI_BUFFER_WIDTH
#define UI_TOPINFO_H    30
#define UI_TOPINFO_X    0
#define UI_TOPINFO_Y    (4 / UI_SCALE_H)
#define UI_BOTTOMINFO_W UI_BUFFER_WIDTH
#define UI_BOTTOMINFO_H 20
#define UI_MAINWINDOW_W UI_BUFFER_WIDTH
#define UI_MAINWINDOW_H (UI_BUFFER_HEIGHT - UI_TOPINFO_H - UI_BOTTOMINFO_H - UI_TOPINFO_Y)
#define UI_MAINWINDOW_X 0
#define UI_MAINWINDOW_Y (UI_TOPINFO_Y + UI_TOPINFO_H)
#define UI_BOTTOMINFO_X 0
#define UI_BOTTOMINFO_Y (UI_MAINWINDOW_Y + UI_MAINWINDOW_H)

#define UI_MAINWINDOW_PROCESS_FG_X_OFFSET ((PROCESS_BAR_BG_W - PROCESS_BAR_FG_W) / 2)
#define UI_MAINWINDOW_PROCESS_FG_Y_OFFSET ((PROCESS_BAR_BG_H - PROCESS_BAR_FG_H) / 2)

#define SESSION_TIMER_IN_MS           (15000)
#define Elevator_MOTION_TIMEOUT_IN_MS (1000)

#if LVGL_MULTITHREAD_LOCK
#define LVGL_LOCK()   _takeLVGLMutex()
#define LVGL_UNLOCK() _giveLVGLMutex()
#else
#define LVGL_LOCK()
#define LVGL_UNLOCK()
#endif /* LVGL_MULTITHREAD_LOCK */

static gfx_surface_t s_UiSurface;

SDK_ALIGN(static char s_AsBuffer[UI_BUFFER_WIDTH * UI_BUFFER_HEIGHT * UI_BUFFER_BPP], 32);

/*******************************************************************************
 * Prototypes
 ******************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif

static hal_output_status_t _InferComplete_Vision(const output_dev_t *dev, void *inferResult);
static hal_output_status_t _InferComplete_Voice(const output_dev_t *dev, void *inferResult);

static hal_output_status_t HAL_OutputDev_UiSliderProgress_Init(output_dev_t *dev, output_dev_callback_t callback);
static hal_output_status_t HAL_OutputDev_UiSliderProgress_Deinit(const output_dev_t *dev);
static hal_output_status_t HAL_OutputDev_UiSliderProgress_Start(const output_dev_t *dev);
static hal_output_status_t HAL_OutputDev_UiSliderProgress_Stop(const output_dev_t *dev);
static void _StopFaceRec(int stop);
static void _SetVoiceModel(asr_inference_t modelId, asr_language_t lang, uint8_t ptt);

__attribute__((weak)) uint32_t APP_OutputDev_UiSliderProgress_InferCompleteDecode(output_algo_source_t source,
                                                                            void *inferResult)
{
    return 0;
}
__attribute__((weak)) uint32_t APP_OutputDev_UiSliderProgress_InputNotifyDecode(event_base_t *inputData)
{
    return 0;
}

static hal_output_status_t HAL_OutputDev_UiSliderProgress_InferComplete(const output_dev_t *dev,
                                                                  output_algo_source_t source,
                                                                  void *inferResult);
static hal_output_status_t HAL_OutputDev_UiSliderProgress_InputNotify(const output_dev_t *dev, void *data);

#if defined(__cplusplus)
}
#endif

/*******************************************************************************
 * Variables
 ******************************************************************************/

const static output_dev_operator_t s_OutputDev_UiSliderProgressOps = {
    .init   = HAL_OutputDev_UiSliderProgress_Init,
    .deinit = HAL_OutputDev_UiSliderProgress_Deinit,
    .start  = HAL_OutputDev_UiSliderProgress_Start,
    .stop   = HAL_OutputDev_UiSliderProgress_Stop,
};

static output_dev_t s_OutputDev_UiSliderProgress = {
    .name          = "UiSliderProgress",
    .attr.type     = kOutputDevType_UI,
    .attr.pSurface = &s_UiSurface,
    .ops           = &s_OutputDev_UiSliderProgressOps,
};

const static output_dev_event_handler_t s_OutputDev_UiSliderProgressHandler = {
    .inferenceComplete = HAL_OutputDev_UiSliderProgress_InferComplete,
    .inputNotify       = HAL_OutputDev_UiSliderProgress_InputNotify,
};

/*******************************************************************************
 * Code
 ******************************************************************************/
static hal_output_status_t HAL_OutputDev_UiSliderProgress_Init(output_dev_t *dev, output_dev_callback_t callback)
{
    hal_output_status_t error = kStatus_HAL_OutputSuccess;
    LOGD("++HAL_OutputDev_UiSliderProgress_Init");

    dev->cap.callback = callback;

    /* Add initialization code here */
    s_UiSurface.left   = 0;
    s_UiSurface.top    = 0;
    s_UiSurface.right  = UI_BUFFER_WIDTH - 1;
    s_UiSurface.bottom = UI_BUFFER_HEIGHT - 1;
    s_UiSurface.height = UI_BUFFER_HEIGHT;
    s_UiSurface.width  = UI_BUFFER_WIDTH;
    s_UiSurface.pitch  = UI_BUFFER_WIDTH * 2;
    s_UiSurface.format = kPixelFormat_RGB565;
    s_UiSurface.buf    = s_AsBuffer;
    s_UiSurface.lock   = xSemaphoreCreateMutex();

    LOGD("--HAL_OutputDev_UiSliderProgress_Init");
    return error;
}

static hal_output_status_t HAL_OutputDev_UiSliderProgress_Deinit(const output_dev_t *dev)
{
    hal_output_status_t error = kStatus_HAL_OutputSuccess;
    LOGD("++HAL_OutputDev_UiLvgl_Deinit");

    /* Add de-initialization code here */

    LOGD("--HAL_OutputDev_UiLvgl_Deinit");
    return error;
}

static hal_output_status_t HAL_OutputDev_UiSliderProgress_Start(const output_dev_t *dev)
{
    hal_output_status_t error = kStatus_HAL_OutputSuccess;
    LOGD("++HAL_OutputDev_UiSliderProgress_Start");

    /* Add start code here */
    if (FWK_OutputManager_RegisterEventHandler(dev, &s_OutputDev_UiSliderProgressHandler) != 0)
    {
        error = kStatus_HAL_OutputError;
    }

    LOGD("--HAL_OutputDev_UiSliderProgress_Start");
    return error;
}

static hal_output_status_t HAL_OutputDev_UiSliderProgress_Stop(const output_dev_t *dev)
{
    hal_output_status_t error = kStatus_HAL_OutputSuccess;
    LOGD("++HAL_OutputDev_UiSliderProgress_Stop");

    /* Add stop code here */

    LOGD("--HAL_OutputDev_UiSliderProgress_Stop");
    return error;
}

static hal_output_status_t HAL_OutputDev_UiSliderProgress_InferComplete(const output_dev_t *dev,
                                                                  output_algo_source_t source,
                                                                  void *inferResult)
{
    hal_output_status_t error = kStatus_HAL_OutputSuccess;

    if (inferResult == NULL)
    {
        return error;
    }

    LVGL_LOCK();
    if (source == kOutputAlgoSource_Vision)
    {

    }
    else if (source == kOutputAlgoSource_Voice)
    {

    }
    LVGL_UNLOCK();

    return error;
}

static hal_output_status_t HAL_OutputDev_UiSliderProgress_InputNotify(const output_dev_t *dev, void *data)
{
    hal_output_status_t error = kStatus_HAL_OutputSuccess;
    event_base_t *pEventBase  = (event_base_t *)data;

    /* Add 'inputNotify' event handler code here */
    APP_OutputDev_UiSliderProgress_InputNotifyDecode(pEventBase);

    return error;
}

int HAL_OutputDev_UiSliderProgress_Register()
{
    int error = 0;
    LOGD("++HAL_OutputDev_UiSliderProgress_Register");

    error = FWK_OutputManager_DeviceRegister(&s_OutputDev_UiSliderProgress);

    LOGD("--HAL_OutputDev_UiSliderProgress_Register");
    return error;
}

#endif /* ENABLE_OUTPUT_DEV_UiSliderProgress */
