/**
 * @file hv_drv_OsdFont.c
 * @brief Osd Driver Blend c file.
 * @details This file provides the following functions: \n
 *          (1) blend initialization functions \n
 *          (5) blend type choose 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"

OsdBlendParam *s_pstBlendParam = NULL;

/* Low level blending functions */

VOID Hv_Drv_OsdBlend_SetRectGroupAlpha(OsdWindowPhyId enWinID, UCHAR8 ucAlpha)
{
    Hv_Drv_OsdWindow_SetCurrentWindow(enWinID);
    Hv_Cal_OsdBlend_SetForegroundAlpha(OSD_BLENDING_STAGE_RECT_GROUP, ucAlpha);
}

VOID Hv_Drv_OsdBlend_SetSwitch(OsdBlendingStage enStage, BOOL bSwitch)
{
    Hv_Cal_OsdBlend_SetSwitch(enStage, bSwitch);
    return;
}

VOID Hv_Drv_OsdBlend_SetAlphaSelect(OsdBlendingStage enStage, OsdAlphaSelectType enType, UCHAR8 ucValue)
{
    OsdBlendAlphaSelectParam *pstParam = &s_pstBlendParam->astAlphaSelectParams[enStage];

    pstParam->enType = enType;
    pstParam->ucAlpha = ucValue;
    Hv_Cal_OsdBlend_SetAlphaSelect(enStage, enType, ucValue);
    return;
}

VOID Hv_Drv_OsdBlend_SetAlphaOutput(OsdBlendingStage enStage, OsdAlphaOutputType enType, UCHAR8 ucValue)
{
    OsdBlendAlphaOutputParam *pstParam = &s_pstBlendParam->astAlphaOutputParams[enStage];

    pstParam->enType = enType;
    pstParam->ucAlpha = ucValue;
    Hv_Cal_OsdBlend_SetAlphaOutput(enStage, enType, ucValue);
    return;
}

VOID Hv_Drv_OsdBlend_SetAlphaOutputRatio(OsdBlendingStage enStage, BOOL bEnable, UCHAR8 ucValue)
{
    if (bEnable)
    {
        Hv_Cal_OsdBlend_SetAlphaOutputRatio(enStage, ucValue);
    }
    else
    {
        Hv_Cal_OsdBlend_SetAlphaOutputRatioEnable(enStage, HV_FALSE);
    }
    return;
}

VOID Hv_Drv_OsdBlend_SetBackground(OsdBlendingStage enStage, BOOL bEnable, USHORT16 usColor, UCHAR8 ucAlpha)
{
    if (bEnable)
    {
        Hv_Cal_OsdBlend_SetBackground(enStage, HV_TRUE, usColor);
        Hv_Cal_OsdBlend_SetBackgroundAlpha(enStage, ucAlpha);
    }
    else
    {
        Hv_Cal_OsdBlend_SetBackground(enStage, HV_FALSE, 0);
    }
    return;
}

/* High level blending functions */

VOID Hv_Drv_OsdBlend_SetBlendingType(OsdBlendingStage enStage, OsdBlendingType enType, UCHAR8 ucAlpha)
{
    OsdBlendAlphaSelectParam *pstSelectParam = &s_pstBlendParam->astAlphaSelectParams[enStage];
    OsdBlendAlphaOutputParam *pstOutputParam = &s_pstBlendParam->astAlphaOutputParams[enStage];

    switch (enType)
    {
        case OSD_BLENDING_TYPE_NOBLENDING:
        {
            Hv_Drv_OsdBlend_SetSwitch(enStage, 1);

            Hv_Drv_OsdBlend_SetAlphaOutput(enStage, pstOutputParam->enType, 0);
            Hv_Drv_OsdBlend_SetAlphaOutputRatio(enStage, HV_FALSE, 0);

            break;
        }
        case OSD_BLENDING_TYPE_NOBLENDING_FORCE_ALPHA:
        {
            Hv_Drv_OsdBlend_SetSwitch(enStage, 1);

            Hv_Drv_OsdBlend_SetAlphaOutput(enStage, OSD_ALPHA_OUTPUT_FORCE, ucAlpha);
            Hv_Drv_OsdBlend_SetAlphaOutputRatio(enStage, HV_FALSE, 0);

            break;
        }
        case OSD_BLENDING_TYPE_BLENDING:
        {
            Hv_Drv_OsdBlend_SetSwitch(enStage, 0);

            Hv_Cal_OsdBlend_SetAlphaSelect(enStage, pstSelectParam->enType, pstSelectParam->ucAlpha);

            Hv_Drv_OsdBlend_SetAlphaOutput(enStage, pstOutputParam->enType, 0);
            Hv_Drv_OsdBlend_SetAlphaOutputRatio(enStage, HV_FALSE, 0);
            break;
        }
        case OSD_BLENDING_TYPE_BLENDING_FORCE_ALPHA:
        {
            Hv_Drv_OsdBlend_SetSwitch(enStage, 0);

            Hv_Cal_OsdBlend_SetAlphaSelect(enStage, pstSelectParam->enType, 0);

            Hv_Drv_OsdBlend_SetAlphaOutput(enStage, OSD_ALPHA_OUTPUT_FORCE, ucAlpha);
            Hv_Drv_OsdBlend_SetAlphaOutputRatio(enStage, HV_FALSE, 0);
            break;
        }
        default:
        {
            break;
        }
    }
    return;
}

static VOID Hv_Drv_OsdBlend_AllStageExecute(pfBlendingCallback pfCallback, VOID *pvArg1, VOID *pvArg2)
{
    OsdWindowPhyId enWinID = PHY_WIN_0;
    OsdBlendingStage enStage = 0;

    for (; enWinID < PHY_WIN_ID_MAX; ++enWinID)
    {
        Hv_Drv_OsdWindow_SetCurrentWindow(enWinID);

        pfCallback(OSD_BLENDING_STAGE_RECT_GROUP, pvArg1, pvArg2);

        if (OSD_WINDOW_IS_NORMAL(enWinID))
        {
            pfCallback(OSD_BLENDING_STAGE_RECT_FONT, pvArg1, pvArg2);
        }
    }

    for (enStage = OSD_BLENDING_STAGE_WIN01;
            enStage <= OSD_BLENDING_STAGE_GRAPHIC; ++enStage)
    {
        pfCallback(enStage, pvArg1, pvArg2);
    }
    return;
}

VOID Hv_Drv_OsdBlend_UniversalAlphaExcludeStage(OsdBlendingStage enStage, UINT32 uiParam)
{
    OsdBlendExcludeParam *pstParam = NULL;

    pstParam = &s_pstBlendParam->astExcludeParams[s_pstBlendParam->ucExcludeCount++];
    pstParam->enStage = enStage;
    pstParam->uiParam = uiParam;

    return;
}

VOID Hv_Drv_OsdBlend_UniversalAlphaExcludeClear(VOID)
{
    s_pstBlendParam->ucExcludeCount = 0;
}

static BOOL bStageExcluded(OsdBlendingStage enStage, UINT32 uiParam)
{
    OsdBlendExcludeParam *pstExcludeParam = NULL;
    UCHAR8 ucIndex = 0;
    BOOL bFound = HV_FALSE;

    for (; ucIndex < s_pstBlendParam->ucExcludeCount; ++ucIndex)
    {
        pstExcludeParam = &s_pstBlendParam->astExcludeParams[ucIndex];
        if (pstExcludeParam->enStage != enStage)
        {
            continue;
        }

        if ((enStage < OSD_BLENDING_STAGE_WIN01) && (uiParam != pstExcludeParam->uiParam))
        {
            continue;
        }

        bFound = HV_TRUE;
        break;
    }

    return bFound;
}

VOID Hv_Drv_OsdBlend_SetUniversalAlpha(OsdUniversalAlphaType enType, UCHAR8 ucAlpha)
{
    OsdBlendAlphaOutputParam *pstOutputParam = NULL;
    OsdWindowPhyId enWinID = PHY_WIN_0;
    OsdBlendingStage enStage = 0;

    if (enType == OSD_UNIVERSAL_ALPHA_TYPE_ALL)
    {
        for (enWinID = 0; enWinID < PHY_WIN_ID_MAX; ++enWinID)
        {
            Hv_Drv_OsdWindow_SetCurrentWindow(enWinID);

            if (!bStageExcluded(OSD_BLENDING_STAGE_RECT_GROUP, enWinID))
            {
                OSD_DRV_LOG_DEBUG("include rect group-%d universal alpha set: ucAlpha", enWinID);
                Hv_Cal_OsdBlend_SetForegroundAlpha(OSD_BLENDING_STAGE_RECT_GROUP, ucAlpha);
            }
            else
            {
                OSD_DRV_LOG_DEBUG("exclude rect group-%d universal alpha set: ucAlpha", enWinID);
            }

            if (OSD_WINDOW_IS_NORMAL(enWinID))
            {
                if (!bStageExcluded(OSD_BLENDING_STAGE_RECT_FONT, enWinID))
                {
                    Hv_Drv_OsdBlend_SetAlphaOutput(OSD_BLENDING_STAGE_RECT_FONT, OSD_ALPHA_OUTPUT_FORCE, ucAlpha);
                }
            }
        }
        for (enStage = OSD_BLENDING_STAGE_WIN01; enStage <= OSD_BLENDING_STAGE_GRAPHIC; ++enStage)
        {
            if (!bStageExcluded(enStage, 0))
            {
                pstOutputParam = &s_pstBlendParam->astAlphaOutputParams[enStage];
                Hv_Drv_OsdBlend_SetAlphaOutput(enStage, pstOutputParam->enType, ucAlpha);
            }
        }
#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
        Hv_Cal_OsdFrame_SetUniversalAlphaEnable(OSD_DATAPATH_DDRREAD, HV_TRUE);
        Hv_Cal_OsdFrame_SetUniversalAlphaValue(OSD_DATAPATH_DDRREAD, ucAlpha);
#endif
    }
    else if (enType == OSD_UNIVERSAL_ALPHA_TYPE_EXCLUDE_FONT)
    {
        for (enWinID = 0; enWinID < PHY_WIN_ID_MAX; ++enWinID)
        {
            Hv_Drv_OsdWindow_SetCurrentWindow(enWinID);

            if (!bStageExcluded(OSD_BLENDING_STAGE_RECT_GROUP, enWinID))
            {
                Hv_Cal_OsdBlend_SetForegroundAlpha(OSD_BLENDING_STAGE_RECT_GROUP, ucAlpha);
            }

            if (OSD_WINDOW_IS_NORMAL(enWinID))
            {
                if (!bStageExcluded(OSD_BLENDING_STAGE_RECT_FONT, enWinID))
                {
                    pstOutputParam = &s_pstBlendParam->astAlphaOutputParams[OSD_BLENDING_STAGE_RECT_FONT];
                    Hv_Drv_OsdBlend_SetAlphaOutput(OSD_BLENDING_STAGE_RECT_FONT, pstOutputParam->enType, 0);
                }
            }
        }
        for (enStage = OSD_BLENDING_STAGE_WIN01; enStage <= OSD_BLENDING_STAGE_GRAPHIC; ++enStage)
        {
            if (!bStageExcluded(enStage, 0))
            {
                pstOutputParam = &s_pstBlendParam->astAlphaOutputParams[enStage];
                Hv_Drv_OsdBlend_SetAlphaOutput(enStage, pstOutputParam->enType, 0);
            }
        }
#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
        Hv_Cal_OsdFrame_SetUniversalAlphaEnable(OSD_DATAPATH_GRAPHIC, HV_TRUE);
        Hv_Cal_OsdFrame_SetUniversalAlphaValue(OSD_DATAPATH_GRAPHIC, ucAlpha);
#endif

#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
        Hv_Cal_OsdFrame_SetUniversalAlphaEnable(OSD_DATAPATH_DDRREAD, HV_FALSE);
#endif
    }
    else /* non-universal */
    {
        for (enWinID = 0; enWinID <= PHY_WIN_3; ++enWinID)
        {
            pstOutputParam = &s_pstBlendParam->astAlphaOutputParams[OSD_BLENDING_STAGE_RECT_FONT];
            Hv_Drv_OsdWindow_SetCurrentWindow(enWinID);
            Hv_Drv_OsdBlend_SetAlphaOutput(OSD_BLENDING_STAGE_RECT_FONT, pstOutputParam->enType, pstOutputParam->ucAlpha);
        }
        for (enStage = OSD_BLENDING_STAGE_WIN01; enStage <= OSD_BLENDING_STAGE_GRAPHIC; ++enStage)
        {
            pstOutputParam = &s_pstBlendParam->astAlphaOutputParams[enStage];
            Hv_Drv_OsdBlend_SetAlphaOutput(enStage, pstOutputParam->enType, pstOutputParam->ucAlpha);
        }
#if (HV_PROJECT_CONFIG_OSD_GRAPHIC == HV_CONFIG_ON)
        Hv_Cal_OsdFrame_SetUniversalAlphaEnable(OSD_DATAPATH_GRAPHIC, HV_FALSE);
#endif

#if (HV_PROJECT_CONFIG_OSD_DDRPATH == HV_CONFIG_ON)
        Hv_Cal_OsdFrame_SetUniversalAlphaEnable(OSD_DATAPATH_DDRREAD, HV_FALSE);
#endif
    }
    return;
}

VOID Hv_Drv_OsdBlend_Init(VOID)
{
    UCHAR8 ucIndex = 0;

    s_pstBlendParam = (OsdBlendParam*)OSD_DRIVER_ALLOC_STATIC(OsdBlendParam, 1);
    HV_MEMSET(s_pstBlendParam, 0, sizeof(*s_pstBlendParam));

    for (ucIndex = 0; ucIndex < OSD_BLENDING_STAGE_MAX; ++ucIndex)
    {
        s_pstBlendParam->astAlphaSelectParams[ucIndex].enType = OSD_ALPHA_TYPE_CH0;
        s_pstBlendParam->astAlphaOutputParams[ucIndex].enType = OSD_ALPHA_OUTPUT_CH0;
    }

    Hv_Drv_OsdBlend_AllStageExecute((pfBlendingCallback)Hv_Drv_OsdBlend_SetBlendingType,(VOID*)OSD_BLENDING_TYPE_NOBLENDING, (VOID*)0);
    return;
}
