/**
 * @file hv_drv_OsdFrame.c
 * @brief Osd Driver Frame management c file.
 * @details This file provides the following functions: \n
 *          (1) language setting functions \n
 *          (2) frame redraw prepare functions \n
 *          (3) frame drawing post 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"

//OsdRotationType g_enRotationType = OSD_ROTATION_NONE;

static OsdLanguage s_enCurrentLanguage = 0;

OsdLanguage Hv_Drv_OsdFrame_GetCurrentLanguage(VOID)
{
    return s_enCurrentLanguage;
}

BOOL Hv_Drv_OsdFrame_SetCurrentLanguage(OsdLanguage enLanguage)
{
    OSD_DRV_LOG_DEBUG("Language set to %u current %u",
            enLanguage, s_enCurrentLanguage);

    if (s_enCurrentLanguage != enLanguage)
    {
        s_enCurrentLanguage = enLanguage;

#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
        Hv_Drv_OsdFont_RemoveAutoMarqueeNodes();
        Hv_Drv_OsdFont_ResetAllMarqueeContents();
        Hv_Drv_OsdFont_ResetAll();
#endif

#if (HV_PROJECT_CONFIG_OSD_CUSTOM_GROUP_SUPPORT == HV_CONFIG_ON)
        Hv_Drv_OsdFont_RelocateAllCustomGroup();
#endif

        return HV_TRUE;
    }

    return HV_FALSE;
}

VOID Hv_Drv_OsdFrame_SetOsdClockEnable(BOOL bEnable)
{
    Hv_Cal_OsdTmg_SetClockEnable(bEnable);
    Hv_Cal_OsdTmg_SetOsdWClockGateEnable(bEnable);
    Hv_Cal_OsdTmg_SetOsdRClockGateEnable(bEnable);
}

BOOL Hv_Drv_OsdFrame_GetOsdClockEnable(VOID)
{
    return Hv_Cal_OsdTmg_GetClockEnable();
}

BOOL Hv_Drv_OsdFrame_NeedCloseOsdClock(VOID)
{
    UCHAR8 ucDrawParts = 0;
    BOOL bDMAEnable = 0;

    ucDrawParts = Hv_Drv_OsdDataPath_GetDrawParts();
    bDMAEnable = Hv_Cal_OsdInnerDMA_GetStartFlag();

    return (0 == ucDrawParts) && (!bDMAEnable);
}

VOID Hv_Drv_OsdFrame_SetSync(VOID)
{
    OSD_DRV_LOG_DEBUG("Set sync");

    Hv_Cal_OsdFrame_SetSync();
}

BOOL Hv_Drv_OsdFrame_CheckSync(VOID)
{
    OSD_DRV_LOG_DEBUG("Check sync");
    return Hv_Cal_OsdFrame_CheckSync();
}

VOID Hv_Drv_OsdFrame_SetScalerRatio(VOID)
{
    Hv_Cal_OsdScaler_SetScalerRatio();
}

VOID Hv_Drv_OsdFrame_ReconfigDataPath(VOID)
{
    Hv_Cal_OsdDP_ReconfigDataPath();
}

/*
 * 计算osd的真实帧率，并据此设置osd timing, 记号如下：
 * Fv:      当前video的帧频
 * Fo:      osd的帧频
 * OSD_MIN: 满足显示需求的osd最小帧频，通过宏定义配置
 *
 * 1. 不过DDR的时候osd不能降频，Fo = Fv
 * 2. 过DDR的时候，根据video的模式：
 *    a) VRR模式：
 *       Fo = Fv / 2，防止video帧频过高带来带宽问题，osd在VRR模式下固定2分频，
 *       可能会导致连续按键的时候反应慢的问题
 *    b) 其他模式：
 *       if         Fv < 2 * OSD_MIN:                      Fo = Fv
 *       else if    2 * OSD_MIN <= Fv < 3 * OSD_MIN:       Fo = Fv / 2
 *       else if    3 * OSD_MIN <= Fv < 4 * OSD_MIN:       Fo = Fv / 3
 *       ...
 */
UCHAR8 Hv_Drv_OsdFrame_GetOsdFrameRateDiv(USHORT16 usVideoFrameRate, BOOL bIsVRR)
{
    UCHAR8 ucFrameMin = 0;
    UCHAR8 ucDiv = 1;

    if (HV_TRUE == bIsVRR)
    {
        //OSD_DRV_LOG_DEBUG("VRR mode, osd frequency set to half");
        return 2;
    }
#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_OFF)
    ucDiv = 1;
#else
    ucFrameMin = HV_OSD_CONFIG_FRAMERATE_MIN;
    if (usVideoFrameRate < 2 * ucFrameMin)
    {
        ucDiv = 1;
    }
    else if (usVideoFrameRate < 3 * ucFrameMin)
    {
        ucDiv = 2;
    }
    else if (usVideoFrameRate < 4 * ucFrameMin)
    {
        ucDiv = 3;
    }
    else
    {
        ucDiv = 4;
    }
#endif

    return ucDiv;
}

UCHAR8 Hv_Drv_OsdFrame_GetOsdFrameRate(USHORT16 usVideoFrameRate, BOOL bIsVRR)
{
    UCHAR8 ucDiv = 0;

    ucDiv = Hv_Drv_OsdFrame_GetOsdFrameRateDiv(usVideoFrameRate, bIsVRR);

    return usVideoFrameRate / ucDiv;
}

BOOL Hv_Drv_OsdFrame_CheckHTotalChange(USHORT16 usCurPanelHtotal)
{
    USHORT16 usSavedPanelHtotal = 0;
    BOOL bChanged = HV_FALSE;

    usSavedPanelHtotal = Hv_Cal_OsdTmg_GetPanelHtotal();

    if (usSavedPanelHtotal + 4 != usCurPanelHtotal)
    {
        OSD_DRV_LOG_INFO("video htotal change from %d to %d, update osd htotal.", usSavedPanelHtotal + 4, usCurPanelHtotal);

        Hv_Cal_OsdTmg_SetPanelHtotal(usCurPanelHtotal - 4);

        bChanged = HV_TRUE;
    }

    return bChanged;
}

VOID Hv_Drv_OsdFrame_ReCalculateTiming(USHORT16 usVideoFrameRate, BOOL bIsVRR)
{
    UCHAR8 ucDiv = 0;
    USHORT16 usHtotal = 0;
    OsdHsBlendMode enHsMode = 0;

#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_OFF)
    return;
#endif

    ucDiv = Hv_Drv_OsdFrame_GetOsdFrameRateDiv(usVideoFrameRate, bIsVRR);
    Hv_Drv_OsdDataPath_SetVsDivNumber(ucDiv);

    /* decrease osd frame rate only for DDR drawing */
    enHsMode = Hv_Cal_OsdDP_GetHsBlendMode();
    if ((OSD_HSBLEND_MODE_DDR_FIRST == enHsMode) || (OSD_HSBLEND_MODE_DDR_ONLY) == enHsMode)
    {
        Hv_Cal_OsdFrame_VsDivNum(ucDiv);
    }

    OSD_DRV_LOG_DEBUG("Osd frame rate set to %u video frame rate %u", usVideoFrameRate / ucDiv, usVideoFrameRate);

    if (Hv_Cal_OsdDP_GetOsdScalerup())
    {
        ucDiv *= 2;
    }

    usHtotal = ucDiv * Hv_Cal_OsdTmg_GetPanelHtotal();

    //Hv_Cal_OsdTmg_SetCurrentHtotal(usHtotal);
    Hv_Cal_OsdTmg_SetHtotalRatio(ucDiv);

    OSD_DRV_LOG_DEBUG("Osd htotal set to %u", usHtotal);
}

VOID Hv_Drv_OsdFrame_DrawPre(VOID)
{
    Hv_Drv_OsdIndex_ResetOffset();
    Hv_Drv_OsdWindow_DisableAll();
    Hv_Drv_OsdResource_ClearLoadedResource();

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

#if (HV_PROJECT_CONFIG_OSD_MARQUEE == HV_CONFIG_ON)
    Hv_Drv_OsdFont_MarqueeMarkSlotsFreed();
#endif

#if (HV_PROJECT_CONFIG_OSD_TEXT_WRAPPING == HV_CONFIG_ON)
    /* remove all wrap nodes */
    Hv_Drv_OsdFont_RemoveAllWrapNodes();
#endif

#ifdef HV_SCALER_DEBUG_VERSION
    g_usTotalComponentWidth = 0;
    if (g_usResourceRealTotalSizeMax < g_usResourceRealTotalSize)
    {
        g_usResourceRealTotalSizeMax = g_usResourceRealTotalSize;
    }
    g_usResourceRealTotalSize = 0;
#endif
}

Status Hv_Drv_OsdFrame_DrawPost(VOID)
{
    Status uiRes = HV_FAILURE;

    Hv_Vos_InvalidAllDCache();

    /* 等待上一次传输完成 */
    uiRes = Hv_Drv_OsdDMA_TransferPrepare();
    if (uiRes == HV_FAILURE)
    {
        return uiRes;
    }

    /* allocate DMA channel */
    Hv_Drv_OsdPalette_TransferPalette();
    Hv_Drv_OsdIndex_TransferIndex();
    Hv_Drv_OsdResource_TransferResource();

    Hv_Drv_OsdDMA_Transfer();

#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
    uiRes = Hv_Drv_OsdGraphic_WaitTransferDone();
    if (uiRes == HV_FAILURE)
    {
        return uiRes;
    }
#endif

#ifdef HV_SCALER_DEBUG_VERSION
    if (g_usMaxComponentWidth < g_usTotalComponentWidth)
    {
        g_usMaxComponentWidth = g_usTotalComponentWidth;
    }

    OSD_DRV_LOG_DEBUG("current total component width: %u max width: %u",
            g_usTotalComponentWidth, g_usMaxComponentWidth);
#endif

    return HV_SUCCESS;
}
