/**
 * @file hv_mw_OsdInit.c
 * @brief osd MiddleWare init c file.
 * @details This file provides the following functions: \n
 *          (1) Osd init function\n
 *          (2) Osd de-init function\n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-09-01
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author       <th>Date            <th>Change Description
 * <tr><td>shanpeng     <td>2022-09-01      <td>create
 * </table>
 */

#include "hv_vos_Memory.h"
#include "hv_app_Osd.h"
#include "hv_mw_OsdComm.h"
#include "hv_mw_OsdLog.h"
#include "hv_mw_OsdInit.h"
#include "hv_mw_OsdDraw.h"
#include "hv_mw_OsdEvent.h"
#include "hv_mw_OsdOperation.h"
#include "hv_mw_OsdInterrupt.h"
#include "hv_drv_Osd.h"

OsdScene g_astOsdSceneArray[SCENE_ID_MAX];
OsdWindow g_astOsdWindowArray[WIN_ID_MAX];
OsdItem g_astOsdItemArray[ITEM_ID_MAX];

static BOOL s_bOsdInited = HV_FALSE;

BOOL Hv_Mw_OsdIsInited(VOID)
{
    return s_bOsdInited;
}

static OsdItem* Hv_Mw_OsdCreateItemList(OsdScene* pstScene, USHORT16 usItemStartId, USHORT16 usItemNum)
{
    HV_ASSERT_VALID_PTR_RET(pstScene, NULL);
    const OsdItemProp* pstItemPropList = NULL;
    OsdItem* pstItemList = NULL;
    OsdItem* pstItem = NULL;

    if (usItemStartId + usItemNum > ITEM_ID_MAX)
    {
        OSD_LOG_ERROR("Too many items to create: item-%d to item-%d, ITEM_ID_MAX=%d",
                      usItemStartId, usItemStartId + usItemNum - 1, ITEM_ID_MAX);
        return NULL;
    }

    /* 获取item静态属性列表 */
    pstItemPropList = OSD_GET_ITEM_PROP(usItemStartId);
    HV_ASSERT_VALID_PTR_RET(pstItemPropList, NULL);

    pstItemList = &g_astOsdItemArray[usItemStartId];
    HV_MEMSET(pstItemList, 0, sizeof(OsdItem) * usItemNum);

    /* 初始化item列表中的所有item */
    for (USHORT16 usItemOffset = 0; usItemOffset < usItemNum; usItemOffset++)
    {
        pstItem = &pstItemList[usItemOffset];
        pstItem->usId = usItemStartId + usItemOffset;
        /* For item postion move */
        pstItem->usX = pstItemPropList[usItemOffset].usX;
        pstItem->usY = pstItemPropList[usItemOffset].usY;
        pstItem->ucSceneId = pstScene->ucId;
        pstItem->ucState = OSD_ITEM_NORMAL;
        pstItem->bVisable = HV_FALSE;

        //OSD_LOG_DEBUG("Item-%d, addr=0x%x", pstItem->usId, pstItem);
    }

    return pstItemList;
}

static VOID Hv_Mw_OsdDestoryItemList(USHORT16 usItemStartId)
{
    if (usItemStartId < ITEM_ID_MAX)
    {
        return;
    }
}

static OsdWindow* Hv_Mw_OsdCreateWindow(OsdScene* pstScene, UCHAR8 ucWindowId)
{
    HV_ASSERT_VALID_PTR_RET(pstScene, NULL);
    OsdWindow* pstWindow = NULL;
    const OsdWindowProp* pstWindowProp = OSD_GET_WINDOW_PROP(ucWindowId);
    HV_ASSERT_VALID_PTR_RET(pstWindowProp, NULL);

    OSD_LOG_DEBUG("Start create Window %d", ucWindowId);

    pstWindow = &g_astOsdWindowArray[ucWindowId];
    HV_MEMSET(pstWindow, 0, sizeof(OsdWindow));

    /* 初始化Component链表头 */
    HV_MEMSET(&pstWindow->stCpShowListHead, 0, sizeof(OsdNodeHead));
    HV_MEMSET(&pstWindow->stFontShowListHead, 0, sizeof(OsdNodeHead));
    HV_MEMSET(&pstWindow->stDeleteListHead, 0, sizeof(OsdNodeHead));
    HV_MEMSET(&pstWindow->stFontDeleteListHead, 0, sizeof(OsdNodeHead));

    /* 初始化window信息 */
    pstWindow->pstScene = pstScene;
    pstWindow->ucId = ucWindowId;
    pstWindow->ucPhyId = pstWindowProp->ucWindowID;
    /* For font draw */
    pstWindow->usFontAreaWidth = pstWindowProp->usWidth;
    pstWindow->ucFixColumns = pstWindowProp->ucFixColumns;

    pstWindow->bVisable = HV_FALSE;
    pstWindow->bModify = HV_FALSE;

    return pstWindow;
}

static VOID Hv_Mw_OsdDestoryWindow(UCHAR8 ucWindowId)
{
    OsdWindow* pstWindow = OSD_GET_WINDOW(ucWindowId);
    HV_ASSERT_VALID_PTR_VOID(pstWindow);

    Hv_Mw_OsdWindowClearShowList(pstWindow);
    Hv_Mw_OsdWindowClearDeleteList(pstWindow);
}

static OsdScene* Hv_Mw_OsdCreateScene(UCHAR8 ucSceneId)
{
    OsdScene* pstScene = NULL;
    const OsdSceneProp* pstSceneProp = OSD_GET_SCENE_PROP(ucSceneId);
    HV_ASSERT_VALID_PTR_RET(pstSceneProp, NULL);
    OsdWindow* pstWindow = NULL;
    UCHAR8 ucWindowStart = 0;
    UCHAR8 ucWindowEnd = 0;
    OsdItem* pstItemList = NULL;

    if (ucSceneId >= SCENE_ID_MAX)
    {
        OSD_LOG_ERROR("SceneId %d is larger than SCENE_ID_MAX(%d)!", ucSceneId, SCENE_ID_MAX);
        return NULL;
    }

    OSD_LOG_DEBUG("Start Create Scene %d", ucSceneId);

    pstScene = &g_astOsdSceneArray[ucSceneId];
    HV_MEMSET(pstScene, 0, sizeof(OsdScene));

    /* 初始化scene信息 */
    pstScene->ucId = ucSceneId;
    /* For scene postion move */
    pstScene->usX = pstSceneProp->usX;
    pstScene->usY = pstSceneProp->usY;
    pstScene->usWidth = pstSceneProp->usWidth;
    pstScene->usHeight = pstSceneProp->usHeight;
    pstScene->ucCurFrame = 0;
    pstScene->bVisable = HV_FALSE;
    pstScene->bModify = HV_FALSE;
#if (HV_PROJECT_CONFIG_OSD_ROTATION == HV_CONFIG_ON)
    pstScene->bSkipRotate = HV_FALSE;
#endif

    for (UCHAR8 ucPartId = 0; ucPartId < pstSceneProp->ucFramePartNum; ucPartId++)
    {
        ucWindowStart = pstSceneProp->astFramePart[ucPartId].ucWindowStartId;
        ucWindowEnd = pstSceneProp->astFramePart[ucPartId].ucWindowStartId + pstSceneProp->astFramePart[ucPartId].ucWindowNum;
        /* 创建并初始化FramePart中的所有window */
        for (UCHAR8 ucWinId = ucWindowStart; ucWinId < ucWindowEnd; ucWinId++)
        {
            pstWindow = Hv_Mw_OsdCreateWindow(pstScene, ucWinId);
            if (NULL == pstWindow)
            {
                OSD_LOG_ERROR("Create Window %d Failed!!!", ucWinId);
                return NULL;
            }
        }
    }

    if (pstSceneProp->usItemNum)
    {
        /* 创建并初始化所有scene中的item */
        OSD_LOG_DEBUG("Create ItemList, item num = %d", pstSceneProp->usItemNum);
        pstItemList = Hv_Mw_OsdCreateItemList(pstScene, pstSceneProp->usItemStartId, pstSceneProp->usItemNum);
        HV_ASSERT_VALID_PTR_RET(pstItemList, NULL);
    }

    return pstScene;
}

static VOID Hv_Mw_OsdDestoryScene(UCHAR8 ucSceneId)
{
    const OsdSceneProp* pstSceneProp = OSD_GET_SCENE_PROP(ucSceneId);
    HV_ASSERT_VALID_PTR_VOID(pstSceneProp);

    Hv_Mw_OsdDestoryItemList(pstSceneProp->usItemStartId);

    for (UCHAR8 ucPartId = 0; ucPartId < pstSceneProp->ucFramePartNum; ucPartId++)
    {
        for (UCHAR8 ucWinId = pstSceneProp->astFramePart[ucPartId].ucWindowStartId;
             ucWinId < pstSceneProp->astFramePart[ucPartId].ucWindowStartId + pstSceneProp->astFramePart[ucPartId].ucWindowNum;
             ucWinId++)
        {
            Hv_Mw_OsdDestoryWindow(ucWinId);
        }
    }
}

Status Hv_Mw_OsdInit(VOID)
{
    OsdScene* pstScene = NULL;

    s_bOsdInited = HV_FALSE;
#ifdef OSD_DISABLE
    OSD_LOG_WARN("OSD is disabled");
    return HV_SUCCESS;
#endif

    OSD_LOG_DEBUG("OSD Init Start!");

    /* 初始化OSD驱动 */
    OSD_LOG_DEBUG("Init Driver.");
    Hv_Drv_OsdInit();

    /* 创建所有Scene */
    OSD_LOG_DEBUG("Create Scenes, num = %d", SCENE_ID_MAX);
    for (UCHAR8 ucSceneId = 0; ucSceneId < SCENE_ID_MAX; ucSceneId++)
    {
        pstScene = Hv_Mw_OsdCreateScene(ucSceneId);
        HV_ASSERT_VALID_PTR(pstScene);
    }

    /* 初始化Event数据 */
    OSD_LOG_DEBUG("Init Event.");
    Hv_Mw_OsdEventInit();

    /* 初始化Operation数据 */
    OSD_LOG_DEBUG("Init Operation.");
    Hv_Mw_OsdOpsInit();

    /* 初始化Draw数据 */
    OSD_LOG_DEBUG("Init Draw.");
    Hv_Mw_OsdDrawInit();

    s_bOsdInited = HV_TRUE;
    OSD_LOG_DEBUG("OSD Init Done!");

    return HV_SUCCESS;
}

VOID Hv_Mw_OsdDeinit(VOID)
{
    Hv_Mw_OsdEventDeinit();

    /* 销毁所有scene */
    for (UCHAR8 ucSceneId = 0; ucSceneId < SCENE_ID_MAX; ucSceneId++)
    {
        Hv_Mw_OsdDestoryScene(ucSceneId);
    }
    HV_MEMSET(g_astOsdSceneArray, 0, sizeof(OsdScene) * SCENE_ID_MAX);
    HV_MEMSET(g_astOsdWindowArray, 0, sizeof(OsdWindow) * WIN_ID_MAX);
    HV_MEMSET(g_astOsdItemArray, 0, sizeof(OsdItem) * ITEM_ID_MAX);

    s_bOsdInited = HV_FALSE;
}

Status Hv_Mw_OsdPostInit(VOID)
{
    /* 初始化所有App层相关设置 */
    Hv_App_Cb_OsdInit();

    /* enable osd interrupt */
    Hv_Mw_OsdInterrupt_Enable(OSD_INT_TRIG_HIGH_LEVEL,
        OSD_INT_DMA_READ_DONE_BIT | OSD_INT_REGEN_CLR_BIT |
        OSD_INT_DMA_RESET_ERR_BIT | OSD_INT_DMA_START_ERR_BIT);

    /* close osd clock */
    Hv_Drv_OsdFrame_SetOsdClockEnable(HV_FALSE);

    return HV_SUCCESS;
}
