//
// Created by martin on 12.11.21.
//

#ifndef ANIMTESTBED_ANIMSAMPLERNODE_H
#define ANIMTESTBED_ANIMSAMPLERNODE_H

#include "../AnimNode.h"

struct AnimSamplerNode : public AnimNode {
  AnimSamplerNode(AnimationController* animation_controller)
      : AnimNode(animation_controller),
        m_time_prev(0.f),
        m_override_ratio(false),
        m_anim_ratio(0.f),
        m_root_bone_index(0) {
    assert(m_time_current < 100.0f);
    m_anim_node_type = AnimNodeType::AnimSampler;
  };
  virtual ~AnimSamplerNode() {}

  ozz::animation::Animation* m_animation;

  float m_time_prev;
  bool m_override_ratio;
  float m_anim_ratio;
  float m_anim_ratio_prev;
  bool m_root_bone_index;

  ozz::vector<ozz::math::SoaTransform> m_local_matrices;
  ozz::vector<ozz::math::SoaTransform> m_root_output;
  ozz::animation::SamplingCache m_sampling_cache;

  void SetAnimation(
      ozz::animation::Animation* animation,
      const SyncTrack& sync_track);

  virtual void UpdateIsSynced(bool is_synced) override {
    m_is_time_synced = is_synced;
  }

  virtual void UpdateSyncTrack() override {}

  virtual void UpdateTime(float dt) override {
    if (m_override_ratio) {
      return;
    }

    m_time_prev = m_time_current;
    m_time_current += dt;

    if (m_is_time_synced) {
      m_anim_ratio = m_sync_track.CalcRatioFromSyncTime(m_time_current);
      float prev_sync_time = m_time_current - dt;
      if (m_time_current < 0) {
        prev_sync_time += m_sync_track.m_num_intervals;
      }
      m_anim_ratio_prev = m_sync_track.CalcRatioFromSyncTime(prev_sync_time);
    } else {
      m_anim_ratio =
          fmodf((float)m_time_current / m_animation->duration(), 1.0f);
      m_anim_ratio_prev =
          fmodf((float)m_time_prev / m_animation->duration(), 1.0f);

      if (m_anim_ratio_prev < 0) {
        m_anim_ratio_prev += 1.0f;
      }
    }

    if (m_anim_ratio < 0.f) {
      m_anim_ratio += 1.0f;
    }
  }

  virtual void Evaluate(
      ozz::vector<ozz::math::SoaTransform>* local_matrices,
      ozz::math::Transform* root_transform) override;

  virtual void GetInputNodes(
      std::vector<AnimNode*>& input_nodes) const override{};

  virtual void DrawDebugUi();
};

#endif  //ANIMTESTBED_ANIMSAMPLERNODE_H
