// SPDX-License-Identifier: Unlicense

#ifndef HELPER_H
#define HELPER_H

#include "type.h"

#include <string>
#include <vector>

//vec4 colorVec4(const Color& color);
vec4 colorVec4(const char* hexColor);

std::string hexColor(vec4 color);

//void setColor(std::vector<u8>& rgbaData, i32 index, Color color);

//f32 x2GlScreen(f32 x);
//f32 y2GlScreen(f32 y);

//f32 radFromDeg(f32 deg);

f32 TimeNS_To_Seconds(TimeNS time);
inline constexpr TimeNS timeNS_From_Seconds(f32 seconds)
{
  return TimeNS(seconds * f64(1_s));
}
TimeNS timeNS_From_String(std::string timeInSeconds);
std::string TimeNS_To_String(TimeNS time);
std::string F32_To_String(f32 value);

i64 musicTimeElapsedToPlaybackPositionNonStretched(TimeNS musicTimeElapsedNS, f32 sampleRate); // don't forget to '* stretchRatio'

u16 lfsr();

f32 saturate(f32 x);
f32 smoothstep(f32 a, f32 b, f32 x);

namespace vec
{
  f32 lengthSquared(f32 x, f32 y);
  f32 lengthSquared(const vec3& x);

  f32 length(f32 x, f32 y);
  f32 length(const vec3& x);

  void norm(f32& x, f32& y);
  vec3 norm(const vec3& x);


  void rotate(f32& x, f32& y, f32 rad);

  vec3 multiply(const vec3& x, const f32 scale);
  mat4 multiply(const mat4& m0, const mat4& m1);
  vec4 multiply(const mat4& m0, const vec4& v0);

  vec3 truncate(const vec3& x, const f32 max);

  mat4 createTranslationMat(f32 x, f32 y, f32 z);
  mat4 createScaleMat(f32 x, f32 y, f32 z);
  mat4 createMatFromQuaternion(const vec4& quaternion);

  //f32 dotProduct(const vec3& v0, const vec3& v1);
  //vec3 quaternionToDirection(const vec4& quat);
}

template<typename T>
const T& min_(const T& a, const T& b) {
  return (b < a) ? b : a;
}

template<typename T>
const T& max_(const T& a, const T& b) {
  return (a < b) ? b : a;
}

template<typename T>
constexpr const T& clamp(const T& v, const T& lo, const T& hi) // emscripten somehow can't use std::clamp
{
  return (v < lo) ? lo : (hi < v) ? hi : v;
}

template<typename T, typename U>
constexpr U map_(T x, T in_min, T in_max, U out_min, U out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

template<typename T>
bool sameSign(const T& a, const T& b) {
  return a < 0 == b < 0;
}

inline u16 u16_le(const u8* bytes)
{
  return *reinterpret_cast<const u16*>(bytes);
}

inline i16 i16_le(const u8* bytes)
{
  return *reinterpret_cast<const i16*>(bytes);
}

inline u32 u32_le(const u8* bytes)
{
  return *reinterpret_cast<const u32*>(bytes);
}

inline i32 i32_le(const u8* bytes)
{
  return *reinterpret_cast<const i32*>(bytes);
}

inline f32 f32_le(const u8* bytes)
{
  return *reinterpret_cast<const f32*>(bytes);
}

inline f64 f64_le(const u8* bytes)
{
  return *reinterpret_cast<const f64*>(bytes);
}

inline u16 u16_be(const u8* bytes)
{
  return bytes[0] << 8 | bytes[1];
}

inline u32 u32_be(const u8* bytes)
{
  return bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3];
}

inline u64 u40_be(const u8* bytes)
{
  return u64(bytes[0]) << 32 | u64(bytes[1]) << 24 | u64(bytes[2]) << 16 | u64(bytes[3]) << 8 | bytes[4];
}

#endif // HELPER_H
