/*
 * 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.
 */

#pragma once

#include "CubismFramework.hpp"
#include "Type/csmVector.hpp"

namespace Live2D { namespace Cubism { namespace Framework {

class CubismMotionQueueManager;
class CubismMotionQueueEntry;
class CubismModel;

/**
 * @brief モーションの抽象基底クラス
 *
 * モーションの抽象基底クラス。MotionQueueManagerによってモーションの再生を管理する。
 */
class ACubismMotion
{
public:
    /**
     * @brief インスタンスの破棄
     *
     * インスタンスを破棄する。
     *
     * @param[in]   motion  破棄対象のACubismMotion
     */
    static void Delete(ACubismMotion* motion);

    /**
     * @brief コンストラクタ
     *
     * コンストラクタ。
     */
    ACubismMotion();

    /**
     * @brief モデルのパラメータ更新
     *
     * モデルのパラメータを更新する。
     *
     * @param[in]   model               対象のモデル
     * @param[in]   motionQueueEntry    CubismMotionQueueManagerで管理されているモーション
     * @param[in]   userTimeSeconds     デルタ時間の積算値[秒]
     */
    void UpdateParameters(CubismModel* model, CubismMotionQueueEntry* motionQueueEntry, csmFloat32 userTimeSeconds);

    /**
     * @brief フェードイン
     *
     * フェードインの時間を設定する。
     *
     * @param[in]   fadeInSeconds      フェードインにかかる時間[秒]
     */
    void SetFadeInTime(csmFloat32 fadeInSeconds);

    /**
     * @brief フェードアウト
     *
     * フェードアウトの時間を設定する。
     *
     * @param[in]   fadeOutSeconds     フェードアウトにかかる時間[秒]
     */
    void SetFadeOutTime(csmFloat32 fadeOutSeconds);

    /**
     * @brief フェードアウトにかかる時間の取得
     *
     * フェードアウトにかかる時間を取得する。
     *
     * @return フェードアウトにかかる時間[秒]
     */
    csmFloat32 GetFadeOutTime() const;

    /**
     * @brief フェードインにかかる時間の取得
     *
     * フェードインにかかる時間を取得する。
     *
     * @return フェードインにかかる時間[秒]
     */
    csmFloat32 GetFadeInTime() const;

    /**
     * @brief モーション適用の重みの設定
     *
     * モーション適用の重みを設定する。
     *
     * @param[in]   weight      重み(0.0 - 1.0)
     */
    void SetWeight(csmFloat32 weight);

    /**
     * @brief モーション適用の重みの取得
     *
     * モーション適用の重みを取得する。
     *
     * @return 重み(0.0 - 1.0)
     */
    csmFloat32 GetWeight() const;

    /**
     * @brief モーションの長さの取得
     *
     * モーションの長さを取得する。
     *
     * @return モーションの長さ[秒]
     *
     * @note ループのときは「-1」。
     *       ループではない場合は、オーバーライドする。
     *       正の値の時は取得される時間で終了する。
     *       「-1」のときは外部から停止命令が無い限り終わらない処理となる。
     */
    virtual csmFloat32 GetDuration();

    /**
     * @brief モーションのループ1回分の長さの取得
     *
     * モーションのループ1回分の長さを取得する。
     *
     * @return モーションのループ1回分の長さ[秒]
     *
     * @note ループしない場合は GetDuration()と同じ値を返す。
     *       ループ一回分の長さが定義できない場合（プログラム的に動き続けるサブクラスなど）の場合は「-1」を返す
     */
    virtual csmFloat32 GetLoopDuration();


    /**
     * @brief モーション再生の開始時刻の設定
     *
     * モーション再生の開始時刻を設定する。
     *
     * @param[in]   offsetSeconds    モーション再生の開始時刻[秒]
     */
    void SetOffsetTime(csmFloat32 offsetSeconds);

    /**
    * @brief モデルのパラメータ更新
    *
    * イベント発火のチェック。
    * 入力する時間は呼ばれるモーションタイミングを０とした秒数で行う。
    *
    * @param[in]   beforeCheckTimeSeconds   前回のイベントチェック時間[秒]
    * @param[in]   motionTimeSeconds        今回の再生時間[秒]
    */
    virtual const csmVector<const csmString*>& GetFiredEvent(csmFloat32 beforeCheckTimeSeconds,
                                                                   csmFloat32 motionTimeSeconds);
private:
    // Prevention of copy Constructor
    ACubismMotion(const ACubismMotion&);
    ACubismMotion& operator=(const ACubismMotion&);

protected:
    /**
     * @brief デストラクタ
     *
     * デストラクタ。
     */
    virtual ~ACubismMotion();

    /**
     * @brief モデルのパラメータの更新の実行
     *
     * モデルのパラメータ更新を実行する。
     *
     * @param[in]   model               対象のモデル
     * @param[in]   userTimeSeconds     デルタ時間の積算値[秒]
     * @param[in]   weight              モーションの重み
     * @param[in]   motionQueueEntry    CubismMotionQueueManagerで管理されているモーション
     */
    virtual void DoUpdateParameters(CubismModel* model, csmFloat32 userTimeSeconds, csmFloat32 weight, CubismMotionQueueEntry* motionQueueEntry) = 0;

    csmFloat32    _fadeInSeconds;        ///< フェードインにかかる時間[秒]
    csmFloat32    _fadeOutSeconds;       ///< フェードアウトにかかる時間[秒]
    csmFloat32    _weight;               ///< モーションの重み
    csmFloat32    _offsetSeconds;        ///< モーション再生の開始時刻[秒]

    csmVector<const csmString*>    _firedEventValues;
};

}}}
