/*
 * Copyright(c) Live2D Inc. All rights reserved.
 *
 * Use of this source code is governed by the Live2D Open Software license
 * that can be found at http://live2d.com/eula/live2d-open-software-license-agreement_en.html.
 */

#include "ACubismMotion.hpp"
#include "Model/CubismModel.hpp"
#include "CubismMotionQueueEntry.hpp"
#include "Math/CubismMath.hpp"


namespace Live2D { namespace Cubism { namespace Framework {

void ACubismMotion::Delete(ACubismMotion* motion)
{
    CSM_DELETE_SELF(ACubismMotion, motion);
}

ACubismMotion::ACubismMotion()
    : _fadeInSeconds(-1.0f)
    , _fadeOutSeconds(-1.0f)
    , _weight(1.0f)
    , _offsetSeconds(0.0f) //再生の開始時刻
{ }

ACubismMotion::~ACubismMotion()
{
    this->_weight = 0.0f;
}

void ACubismMotion::UpdateParameters(CubismModel* model, CubismMotionQueueEntry* motionQueueEntry, csmFloat32 userTimeSeconds)
{
    if (!motionQueueEntry->IsAvailable() || motionQueueEntry->IsFinished())
    {
        return;
    }

    if (!motionQueueEntry->IsStarted())
    {
        motionQueueEntry->IsStarted(true);
        motionQueueEntry->SetStartTime(userTimeSeconds - _offsetSeconds); //モーションの開始時刻を記録
        motionQueueEntry->SetFadeInStartTime(userTimeSeconds); //フェードインの開始時刻

        const csmFloat32 duration = GetDuration();

        if (motionQueueEntry->GetEndTime() < 0)
        {
            //開始していないうちに終了設定している場合がある。
            motionQueueEntry->SetEndTime( (duration <= 0) ? -1 : motionQueueEntry->GetStartTime() + duration );
            //duration == -1 の場合はループする
        }
    }

    csmFloat32 fadeWeight = _weight; //現在の値と掛け合わせる割合　

    //---- フェードイン・アウトの処理 ----
    //単純なサイン関数でイージングする
    const csmFloat32 fadeIn = _fadeInSeconds == 0.0f
                       ? 1.0f
                       : CubismMath::GetEasingSine( (userTimeSeconds - motionQueueEntry->GetFadeInStartTime()) / _fadeInSeconds );

    const csmFloat32 fadeOut = (_fadeOutSeconds == 0.0f || motionQueueEntry->GetEndTime() < 0.0f)
                        ? 1.0f
                        : CubismMath::GetEasingSine( (motionQueueEntry->GetEndTime() - userTimeSeconds) / _fadeOutSeconds );

    fadeWeight = fadeWeight * fadeIn * fadeOut;

    motionQueueEntry->SetState(userTimeSeconds, fadeWeight);

    CSM_ASSERT(0.0f <= fadeWeight && fadeWeight <= 1.0f);

    //---- 全てのパラメータIDをループする ----
    DoUpdateParameters(model, userTimeSeconds, fadeWeight, motionQueueEntry);

    //後処理
    //終了時刻を過ぎたら終了フラグを立てる（CubismMotionQueueManager）
    if ((motionQueueEntry->GetEndTime() > 0) && (motionQueueEntry->GetEndTime() < userTimeSeconds))
    {
        motionQueueEntry->IsFinished(true);      //終了
    }
}

void ACubismMotion::SetFadeInTime(csmFloat32 fadeInSeconds)
{
    this->_fadeInSeconds = fadeInSeconds;
}

void ACubismMotion::SetFadeOutTime(csmFloat32 fadeOutSeconds)
{
    this->_fadeOutSeconds = fadeOutSeconds;
}

csmFloat32 ACubismMotion::GetFadeOutTime() const
{
    return this->_fadeOutSeconds;
}

csmFloat32 ACubismMotion::GetFadeInTime() const
{
    return this->_fadeInSeconds;
}

void ACubismMotion::SetWeight(csmFloat32 weight)
{
    this->_weight = weight;
}

csmFloat32 ACubismMotion::GetWeight() const
{
    return this->_weight;
}

csmFloat32 ACubismMotion::GetDuration()
{
    return -1.0f;
}

csmFloat32 ACubismMotion::GetLoopDuration()
{
    return -1.0f;
}

void ACubismMotion::SetOffsetTime(csmFloat32 offsetSeconds)
{
    this->_offsetSeconds = offsetSeconds;
}

const csmVector<const csmString*>& ACubismMotion::GetFiredEvent(csmFloat32 beforeCheckTimeSeconds, csmFloat32 motionTimeSeconds)
{
    return _firedEventValues;
}

}}}
