/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 * For complete copyright and license terms please see the LICENSE at the root of this distribution.
 *
 * SPDX-License-Identifier: Apache-2.0 OR MIT
 *
 */


#include "EditorDefs.h"

#include "CommentNodeAnimator.h"

// CryCommon
#include <CryCommon/Maestro/Types/AnimParamType.h>
#include <CryCommon/IFont.h>

// Editor
#include "Settings.h"


CCommentNodeAnimator::CCommentNodeAnimator(CTrackViewAnimNode* pCommentNode)
{
    assert(pCommentNode);
    m_pCommentNode = pCommentNode;
}

CCommentNodeAnimator::~CCommentNodeAnimator()
{
    m_pCommentNode = nullptr;
}

void CCommentNodeAnimator::Animate(CTrackViewAnimNode* pNode, const SAnimContext& ac)
{
    if (pNode != m_pCommentNode || pNode->IsDisabled())
    {
        return;
    }

    CTrackViewTrackBundle tracks = pNode->GetAllTracks();

    int trackCount = tracks.GetCount();
    Vec2 pos(0, 0);
    for (int i = 0; i < trackCount; ++i)
    {
        CTrackViewTrack* pTrack = tracks.GetTrack(i);

        if (pTrack->IsMasked(ac.trackMask))
        {
            continue;
        }

        switch (pTrack->GetParameterType().GetType())
        {
        case AnimParamType::CommentText:
        {
            AnimateCommentTextTrack(pTrack, ac);
        }
        break;
        case AnimParamType::PositionX:
        {
            pTrack->GetValue(ac.time, pos.x);
        }
        break;
        case AnimParamType::PositionY:
        {
            pTrack->GetValue(ac.time, pos.y);
        }
        break;
        }
    }

    // Position mapping from [0,100] to [-1,1]
    pos = (pos - Vec2(50.0f, 50.0f)) / 50.0f;
    m_commentContext.m_unitPos = pos;
}

void CCommentNodeAnimator::AnimateCommentTextTrack(CTrackViewTrack* pTrack, const SAnimContext& ac)
{
    if (pTrack->GetKeyCount() == 0)
    {
        return;
    }

    CTrackViewKeyHandle keyHandle = GetActiveKeyHandle(pTrack, ac.time);

    if (keyHandle.IsValid())
    {
        ICommentKey commentKey;

        keyHandle.GetKey(&commentKey);

        if (commentKey.m_duration > 0 && ac.time < keyHandle.GetTime() + commentKey.m_duration)
        {
            m_commentContext.m_strComment = commentKey.m_strComment;
            azstrcpy(m_commentContext.m_strFont, AZ_ARRAY_SIZE(m_commentContext.m_strFont), commentKey.m_strFont.c_str());
            m_commentContext.m_color = commentKey.m_color;
            m_commentContext.m_align = commentKey.m_align;
            m_commentContext.m_size = commentKey.m_size;
        }
        else
        {
            m_commentContext.m_strComment.clear();
        }
    }
    else
    {
        m_commentContext.m_strComment.clear();
    }
}

CTrackViewKeyHandle CCommentNodeAnimator::GetActiveKeyHandle(CTrackViewTrack* pTrack, float fTime)
{
    const int nkeys = pTrack->GetKeyCount();

    if (nkeys == 0)
    {
        return CTrackViewKeyHandle();
    }

    const CTrackViewKeyHandle& firstKeyHandle = pTrack->GetKey(0);

    // Time is before first key.
    if (firstKeyHandle.GetTime() > fTime)
    {
        return CTrackViewKeyHandle();
    }

    for (int i = 0; i < nkeys; i++)
    {
        const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(i);

        if (fTime >= keyHandle.GetTime())
        {
            if ((i == nkeys - 1) || (fTime < pTrack->GetKey(i + 1).GetTime()))
            {
                return keyHandle;
            }
        }
        else
        {
            break;
        }
    }

    return CTrackViewKeyHandle();
}

void CCommentNodeAnimator::Render(CTrackViewAnimNode* pNode, [[maybe_unused]] const SAnimContext& ac)
{
    if (!pNode->IsDisabled())
    {
        CCommentContext* cc = &m_commentContext;

        if (!cc->m_strComment.empty())
        {
            Vec3 color(cc->m_color.GetR(), cc->m_color.GetG(), cc->m_color.GetB());
            DrawText(cc->m_strFont, cc->m_size, cc->m_unitPos, color, cc->m_strComment.c_str(), cc->m_align);
        }
    }
}

Vec2 CCommentNodeAnimator::GetScreenPosFromNormalizedPos(const Vec2&)
{
    AZ_Error("CryLegacy", false, "CCommentNodeAnimator::GetScreenPosFromNormalizedPos not supported");
    return Vec2(0, 0);
}

void CCommentNodeAnimator::DrawText(const char* szFontName, float fSize, const Vec2& unitPos, const ColorF col, const char* szText, int align)
{
    IFFont* pFont = gEnv->pCryFont->GetFont(szFontName);
    if (!pFont)
    {
        pFont = gEnv->pCryFont->GetFont("default");
    }

    if (pFont)
    {
        STextDrawContext ctx;
        ctx.SetSizeIn800x600(false);
        ctx.SetSize(Vec2(UIDRAW_TEXTSIZEFACTOR * fSize, UIDRAW_TEXTSIZEFACTOR * fSize));
        ctx.SetCharWidthScale(0.5f);
        ctx.SetProportional(false);
        ctx.SetFlags(align);

        // alignment
        Vec2 pos = GetScreenPosFromNormalizedPos(unitPos);

        if (align & eDrawText_Center)
        {
            pos.x -= pFont->GetTextSize(szText, true, ctx).x * 0.5f;
        }
        else if (align & eDrawText_Right)
        {
            pos.x -= pFont->GetTextSize(szText, true, ctx).x;
        }

        // Color
        ctx.SetColor(col);

        pFont->DrawString(pos.x, pos.y, szText, true, ctx);
    }
}
