/**
 * @file hv_drv_OsdLogo.c
 * @brief Osd Driver Logo showing c file.
 * @details This file provides the following functions: \n
 *          (1) logo showing functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-31
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author         <th>Date        <th>Change Description
 * <tr><td>OSD Group      <td>2022-08-31   <td>create
 * </table>
*/

#include "hv_drv_Osd.h"
#include "hv_drv_Flash.h"
#include "hv_comm_FlashConfig.h"

static OsdBox s_astLogoFontAreas[OSD_FONT_WINDOW_NUMS + 1];
static UCHAR8 s_ucLogoFontCount = 0;

#if (HV_PROJECT_CONFIG_OSD_LOGO_INCODE == HV_CONFIG_ON)
const UCHAR8 __attribute__((aligned(16))) g_aucLogoData[] =
{
#include"Logo.h"
};
#endif

static OsdLogoBgWindow* Hv_Drv_OsdLogo_GetBackground(OsdLogoHead *pstLogoHead)
{
    OsdLogoIconBmp *pstIconBmp = &pstLogoHead->stIconBmp;
    OsdLogoBgWindow *pstBgWindow = NULL;

    if (pstLogoHead->ucLogoType == OSD_LOGO_TYPE_GRAPHIC)
    {
        pstBgWindow = &pstLogoHead->stBgWindow;
    }
    else
    {
        pstBgWindow = (OsdLogoBgWindow*)((UINT32)pstIconBmp + sizeof(OsdLogoIconBmp) + pstIconBmp->ucWindowCount * sizeof(OsdLogoWindow));
    }

    OSD_DRV_LOG_DEBUG("logo head: 0x%x bg pos: 0x%x", pstLogoHead, pstBgWindow);

    return pstBgWindow;
}

static VOID Hv_Drv_OsdLogo_ShowLogoBgWindow(OsdLogoBgWindow *pstLogoBgWindow, BOOL bAdjustBgArea)
{
    OsdWindowProp stWindowProp;
    UCHAR8 ucIndex = 0;
    OsdBox stBox = {0};

    OSD_DRV_LOG_DEBUG("Show Bg logo offset: 0x%x, ucWindowEnable = %d,"
                                                "stWindowArea.usX: %d, stWindowArea.usY:%d, stWindowArea.usWidth:%d, stWindowArea.usHeight:%d, usBgColor:0x%x",
                        &pstLogoBgWindow, pstLogoBgWindow->ucWindowEnable,
                        pstLogoBgWindow->stWindowArea.usX,
                        pstLogoBgWindow->stWindowArea.usY,
                        pstLogoBgWindow->stWindowArea.usWidth,
                        pstLogoBgWindow->stWindowArea.usHeight,
                        pstLogoBgWindow->usBgColor);

    if (HV_TRUE == pstLogoBgWindow->ucWindowEnable)
    {
        HV_MEMSET(&stWindowProp, 0, sizeof(stWindowProp));
        stWindowProp.ucWindowID = PHY_WIN_RECT_0;
        if (bAdjustBgArea)
        {
            if (0 == s_ucLogoFontCount)
            {
                bAdjustBgArea = HV_FALSE;
            }
            else
            {
                stBox = s_astLogoFontAreas[0];

                for (ucIndex = 1; ucIndex < s_ucLogoFontCount; ++ucIndex)
                {
                    Hv_Drv_OsdDataPath_ExpandDrawRange((OsdArea*)&stBox, (OsdArea*)(s_astLogoFontAreas + ucIndex));
                }

                stWindowProp.usX = stBox.usX;
                stWindowProp.usY = stBox.usY;
                stWindowProp.usWidth = stBox.usW;
                stWindowProp.usHeight = stBox.usH;
            }
        }

        if (!bAdjustBgArea)
        {
            stWindowProp.usX = pstLogoBgWindow->stWindowArea.usX;
            stWindowProp.usY = pstLogoBgWindow->stWindowArea.usY;
            stWindowProp.usWidth = pstLogoBgWindow->stWindowArea.usWidth;
            stWindowProp.usHeight = pstLogoBgWindow->stWindowArea.usHeight;
        }

        stWindowProp.ucBgEnable = HV_TRUE;
        stWindowProp.usBgColor = pstLogoBgWindow->usBgColor;
        stWindowProp.ucBorderEnable = HV_FALSE;
        Hv_Drv_OsdWindow_DrawWindow(&stWindowProp);
    }
}

VOID Hv_Drv_OsdLogo_ShowLogoIconBmp(OsdLogoHead *pstLogoHead)
{
    UCHAR8 ucIndex = 0;
    UCHAR8 ucResourceIdx = 0;
    USHORT16 usResourceOffset = 0;
    UINT32 uiBytes = 0;
    OsdLogoWindow *pstLogoWindow = NULL;
    OsdLogoBgWindow *pstLogoBgWindow = NULL;
    OsdWindowProp stWindowProp;
    OsdLogoIconBmp *pstIconBmp = &pstLogoHead->stIconBmp;
    OsdBox *pstArea = NULL;

    OSD_DRV_LOG_DEBUG("Show Icon/BMP logo palette offset: 0x%x palette size: 0x%x "
            "index offset: 0x%x index size: 0x%x resource offset: 0x%x resource size: 0x%x "
            "window count: %u", pstIconBmp->uiPaletteOffset, pstIconBmp->usPaletteSize,
            pstIconBmp->uiIndexOffset, pstIconBmp->usIndexSize,
            pstIconBmp->uiResourceOffset, pstIconBmp->usResourceSize,
            pstIconBmp->ucWindowCount);

    HV_ASSERT_TRUE_VOID((pstIconBmp->uiPaletteOffset & 0x0f) == 0);
    HV_ASSERT_TRUE_VOID((pstIconBmp->uiIndexOffset & 0x0f) == 0);
    HV_ASSERT_TRUE_VOID((pstIconBmp->uiResourceOffset & 0x0f) == 0);

    HV_ASSERT_TRUE_VOID(pstIconBmp->usPaletteSize != 0);
    HV_ASSERT_TRUE_VOID(pstIconBmp->usIndexSize != 0);
    HV_ASSERT_TRUE_VOID(pstIconBmp->usResourceSize != 0);

    HV_ASSERT_TRUE_VOID(pstIconBmp->ucWindowCount != 0);

    Hv_Drv_OsdWindow_DisableAll();

    /* set DMA to transfer palette/index/resource */
    for (ucIndex = PHY_WIN_0; ucIndex <= PHY_WIN_3; ++ucIndex)
    {
        Hv_Drv_OsdDMA_Pend((UINT32)pstLogoHead + pstIconBmp->uiPaletteOffset,
                OSD_PALETTE_BUFFER_BASE_ADDR + ucIndex * 2048, pstIconBmp->usPaletteSize);
    }

    Hv_Drv_OsdDMA_Pend((UINT32)pstLogoHead + pstIconBmp->uiIndexOffset,
            OSD_INDEX_BUFFER_BASE_ADDR, pstIconBmp->usIndexSize);

    Hv_Drv_OsdDMA_Pend((UINT32)pstLogoHead + pstIconBmp->uiResourceOffset,
            OSD_RESOURCE_BUFFER_BASE_ADDR, pstIconBmp->usResourceSize);

    pstLogoWindow = pstIconBmp->astWindows;
    for (ucIndex = 0; ucIndex < pstIconBmp->ucWindowCount; ++ucIndex)
    {
        pstLogoWindow = &pstIconBmp->astWindows[ucIndex];

        HV_MEMSET(&stWindowProp, 0, sizeof(stWindowProp));
        stWindowProp.ucWindowID = pstLogoWindow->usWindowIndex;
        stWindowProp.usX = pstLogoWindow->stWindowArea.usX;
        stWindowProp.usY = pstLogoWindow->stWindowArea.usY;
        stWindowProp.usWidth = pstLogoWindow->stWindowArea.usWidth;
        stWindowProp.usHeight = pstLogoWindow->stWindowArea.usHeight;

        pstArea = &s_astLogoFontAreas[s_ucLogoFontCount++];
        pstArea->usX = pstLogoWindow->stWindowArea.usX;
        pstArea->usY = pstLogoWindow->stWindowArea.usY;
        pstArea->usW = pstLogoWindow->stWindowArea.usWidth;
        pstArea->usH = pstLogoWindow->stWindowArea.usHeight;

        OSD_DRV_LOG_DEBUG("logo window %u: window index: %u area(%u, %u, %u, %u)",
                ucIndex, stWindowProp.ucWindowID, stWindowProp.usX,
                stWindowProp.usY, stWindowProp.usWidth, stWindowProp.usHeight);

        /* set window area */
        Hv_Drv_OsdWindow_DrawWindow(&stWindowProp);

        Hv_Drv_OsdFont_SetFontStart(pstLogoWindow->usFontStartX,
                pstLogoWindow->usFontStartY);

        /* set index */
        Hv_Cal_OsdWindow_SetRowCount(pstLogoWindow->usRowCount);
        Hv_Cal_OsdWindow_SetRowIndexAddr(pstLogoWindow->usIndexOffset);

        OSD_DRV_LOG_DEBUG("rowCount: %u Index offset: 0x%x",
                pstLogoWindow->usRowCount, pstLogoWindow->usIndexOffset);

        /* set resource */
        for (ucResourceIdx = 0; ucResourceIdx < OSD_WINDOW_MAX_RESOURCE_COUNT; ++ucResourceIdx)
        {
            usResourceOffset = pstLogoWindow->ausWindowResources[ucResourceIdx];
            Hv_Cal_OsdWindow_SetResource(ucResourceIdx, (usResourceOffset << 4),
                    (usResourceOffset >> 12));

            OSD_DRV_LOG_DEBUG("resource %u %s offset 0x%x", ucResourceIdx,
                    Hv_Drv_OsdCommon_GetResourceSizeStr(usResourceOffset >> 12),
                    usResourceOffset << 4);
        }
#if (HV_PROJECT_CONFIG_OSD_LOGO_EFFECT == HV_CONFIG_ON)
        Hv_Drv_OsdEffect_SetShutter2(stWindowProp.ucWindowID, 2, OSD_TRANS_DI_H);
#endif
        Hv_Drv_OsdFont_SetFontEnable(1);
    }

    Hv_Drv_OsdDMA_TransferPrepare();
    Hv_Drv_OsdDMA_Transfer();
}

static VOID Hv_Drv_OsdLogo_ShowLogoGraphic(OsdLogoHead *pstLogoHead)
{
    OsdLogoGraphic *pstLogoGraphic = NULL;
    OsdBox *pstBox = NULL;

    if (pstLogoHead->ucLogoType == OSD_LOGO_TYPE_GRAPHIC)
    {
        pstLogoGraphic = &pstLogoHead->stGraphic;
        OSD_DRV_LOG_DEBUG("Show graphic logo addr:pstLogoGraphic: 0x%x", pstLogoGraphic);
    }
    else
    {
        OsdLogoIconBmp *pstIconBmp = &pstLogoHead->stIconBmp;
        pstLogoGraphic = (OsdLogoGraphic *)((UINT32)pstLogoHead + pstIconBmp->uiResourceOffset + pstIconBmp->usResourceSize);
        OSD_DRV_LOG_DEBUG("Show both logo addr:pstLogoGraphic: 0x%x", pstLogoGraphic);
    }

    OSD_DRV_LOG_DEBUG("Show graphic logo addr:pstLogoHead: 0x%x,stIconBmp: 0x%x,stBgWindow: 0x%x,stGraphic: 0x%x",
                         pstLogoHead,
                         &pstLogoHead->stIconBmp,
                         &pstLogoHead->stBgWindow,
                         &pstLogoHead->stGraphic);

    OSD_DRV_LOG_DEBUG("Show graphic logo:usX: %d, usY: %d, usWidth: %d, usHeight: %d, "
                                                 "uiGraphicOffset: 0x%x, uiGraphicSize: 0x%x, ucFormat: %d, ucSetAlpha: %d, "
                                                "ucPaddingOne: %d, ucCompressed: %d, ucGraphicOnTop: %d, ucAlpha: %d, ",
#if 0
                                                "ucColorKeyEn: %d, uiColorKey: 0x%x, uiColor: 0x%x ",
#endif
                        pstLogoGraphic->stGraphicArea.usX,
                        pstLogoGraphic->stGraphicArea.usY,
                        pstLogoGraphic->stGraphicArea.usWidth,
                        pstLogoGraphic->stGraphicArea.usHeight,
                        pstLogoGraphic->uiGraphicOffset,
                        pstLogoGraphic->uiGraphicSize,
                        pstLogoGraphic->ucFormat,
                        pstLogoGraphic->ucSetAlpha,
                        pstLogoGraphic->ucPaddingOne,
                        pstLogoGraphic->ucCompressed,
                        pstLogoGraphic->ucGraphicOnTop,
                        pstLogoGraphic->ucAlpha
#if 0
                        pstLogoGraphic->ucColorKeyEn,
                        pstLogoGraphic->uiColorKey,
                        pstLogoGraphic->uiColor
#endif
                        );

    OsdGraphic stGraphic = {0};
    OsdGraphicAddition stGraphicAddition = {0};

    pstBox = &s_astLogoFontAreas[s_ucLogoFontCount++];

    pstBox->usX = stGraphic.usX = pstLogoGraphic->stGraphicArea.usX;
    pstBox->usY = stGraphic.usY = pstLogoGraphic->stGraphicArea.usY;
    pstBox->usW = stGraphic.usWidth = pstLogoGraphic->stGraphicArea.usWidth;
    pstBox->usH = stGraphic.usHeight = pstLogoGraphic->stGraphicArea.usHeight;

    stGraphic.ucFormat = pstLogoGraphic->ucFormat;
    stGraphic.ucCompressed = pstLogoGraphic->ucCompressed;
    stGraphic.ucAlpha = pstLogoGraphic->ucAlpha;
#if 0
    stGraphic.ucColorKeyEn = pstLogoGraphic->ucColorKeyEn;
    stGraphic.uiColorKey = pstLogoGraphic->uiColorKey;
    stGraphic.uiColor = pstLogoGraphic->uiColor;
#endif
    stGraphicAddition.bIsAddition = HV_TRUE;
    stGraphicAddition.uiAdditionAddr = (UINT32)pstLogoHead + pstLogoGraphic->uiGraphicOffset;
    stGraphicAddition.uiAdditionSize = pstLogoGraphic->uiGraphicSize;

    OSD_DRV_LOG_DEBUG("Show graphic logo addr:uiAdditionAddr: 0x%x, uiAdditionSize: %d", stGraphicAddition.uiAdditionAddr, stGraphicAddition.uiAdditionSize);

#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
    Hv_Drv_OsdGraphic_DrawGraphic(&stGraphic, &stGraphicAddition);
    Hv_Drv_OsdBlend_SetSwitch(OSD_BLENDING_STAGE_GRAPHIC, HV_FALSE);
    if (pstLogoGraphic->ucGraphicOnTop)
    {
        Hv_Drv_OsdBlend_SetAlphaSelect(OSD_BLENDING_STAGE_GRAPHIC, OSD_ALPHA_TYPE_CH1, 0);
    }
    else
    {
        Hv_Drv_OsdBlend_SetAlphaSelect(OSD_BLENDING_STAGE_GRAPHIC, OSD_ALPHA_TYPE_CH0, 0);
    }
    Hv_Drv_OsdBlend_SetAlphaOutput(OSD_BLENDING_STAGE_GRAPHIC, OSD_ALPHA_OUTPUT_CH0, 0);
#endif
}

BOOL Hv_Drv_OsdLogo_HasBackground(VOID)
{
#if (HV_PROJECT_CONFIG_OSD_LOGO_INCODE == HV_CONFIG_ON)
    OsdLogoHead *pstLogoHead = (OsdLogoHead*)g_aucLogoData;
#else
    OsdLogoHead *pstLogoHead = (OsdLogoHead*)OSD_LOGO_DDR_START;
#endif
    OsdLogoBgWindow *pstLogoBgWindow = NULL;

    if (OSD_LOGO_MAGIC_NUMBER != pstLogoHead->uiMagic)
    {
        OSD_DRV_LOG_ERROR("Osd logo magic mismatch 0x%x 0x%x",
                pstLogoHead->uiMagic, OSD_LOGO_MAGIC_NUMBER);
        return HV_FALSE;
    }

    if (pstLogoHead->ucVersion > OSD_LOGO_VERSION)
    {
        OSD_DRV_LOG_ERROR("Osd logo version mismatch %u %u",
                pstLogoHead->ucVersion, OSD_LOGO_VERSION);
        return HV_FALSE;
    }

    pstLogoBgWindow = Hv_Drv_OsdLogo_GetBackground(pstLogoHead);
    return pstLogoBgWindow->ucWindowEnable;
}

Status Hv_Drv_OsdLogo_ShowLogoOnlyBg(VOID)
{
#if (HV_PROJECT_CONFIG_OSD_LOGO_INCODE == HV_CONFIG_ON)
    OsdLogoHead *pstLogoHead = (OsdLogoHead*)g_aucLogoData;
#else
    OsdLogoHead *pstLogoHead = (OsdLogoHead*)OSD_LOGO_DDR_START;
#endif
    OsdLogoBgWindow *pstLogoBgWindow = NULL;

    if (!Hv_Drv_OsdLogo_HasBackground())
    {
        return HV_FAILURE;
    }

    pstLogoBgWindow = Hv_Drv_OsdLogo_GetBackground(pstLogoHead);
    Hv_Drv_OsdLogo_ShowLogoBgWindow(pstLogoBgWindow, HV_FALSE);

    return HV_SUCCESS;
}

Status Hv_Drv_OsdLogo_ShowLogo(BOOL bAdjustBgArea)
{
#if (HV_PROJECT_CONFIG_OSD_LOGO_INCODE == HV_CONFIG_ON)
    OsdLogoHead *pstLogoHead = (OsdLogoHead*)g_aucLogoData;
#else
    OsdLogoHead *pstLogoHead = (OsdLogoHead*)OSD_LOGO_DDR_START;
#endif

    if (OSD_LOGO_MAGIC_NUMBER != pstLogoHead->uiMagic)
    {
        OSD_DRV_LOG_ERROR("Osd logo magic mismatch 0x%x 0x%x",
                pstLogoHead->uiMagic, OSD_LOGO_MAGIC_NUMBER);
        return HV_FAILURE;
    }

    if (pstLogoHead->ucVersion > OSD_LOGO_VERSION)
    {
        OSD_DRV_LOG_ERROR("Osd logo version mismatch %u %u",
                pstLogoHead->ucVersion, OSD_LOGO_VERSION);
        return HV_FAILURE;
    }

    s_ucLogoFontCount = 0;

    if (pstLogoHead->ucLogoType == OSD_LOGO_TYPE_ICONBMP)
    {
        OSD_DRV_LOG_DEBUG("Icon/Bmp logo size: %u", pstLogoHead->uiLogoSize);
        Hv_Drv_OsdLogo_ShowLogoIconBmp(pstLogoHead);
    }
    else if (pstLogoHead->ucLogoType == OSD_LOGO_TYPE_GRAPHIC)
    {
        OSD_DRV_LOG_DEBUG("Graphic logo size: %u", pstLogoHead->uiLogoSize);
        Hv_Drv_OsdLogo_ShowLogoGraphic(pstLogoHead);
    }
    else if (pstLogoHead->ucLogoType == OSD_LOGO_TYPE_BOTH)
    {
        OSD_DRV_LOG_DEBUG("Both logo size: %u", pstLogoHead->uiLogoSize);
        Hv_Drv_OsdLogo_ShowLogoIconBmp(pstLogoHead);
        Hv_Drv_OsdLogo_ShowLogoGraphic(pstLogoHead);
    }
    else
    {
        OSD_DRV_LOG_ERROR("Not support logo type!");
    }

    OsdLogoBgWindow *pstLogoBgWindow = Hv_Drv_OsdLogo_GetBackground(pstLogoHead);
    Hv_Drv_OsdLogo_ShowLogoBgWindow(pstLogoBgWindow, bAdjustBgArea);

    return HV_SUCCESS;
}

VOID Hv_Drv_OsdLogo_HideLogo(VOID)
{
    Hv_Drv_OsdWindow_DisableAll();

#if (HV_PROJECT_CONFIG_OSD_LOGO_EFFECT == HV_CONFIG_ON)
    for (OsdWindowPhyId enWinIndex = PHY_WIN_0; enWinIndex <= PHY_WIN_3; ++enWinIndex)
    {
        Hv_Drv_OsdEffect_DisableTranMode(enWinIndex);
    }
#endif

#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
    Hv_Drv_OsdGraphic_SetEnable(HV_FALSE);
#endif

    Hv_Drv_OsdPalette_Init();
}

UCHAR8 Hv_Drv_OsdLogo_GetDrawingAreas(OsdBox **pstBoxList)
{
    *pstBoxList = s_astLogoFontAreas;

    return s_ucLogoFontCount;
}
