//  BlockyFroggy
//  Copyright © 2017 John Ryland.
//  All rights reserved.
#pragma once
#ifndef COMMON_H
#define COMMON_H


#include "TaskManager.h"
#include <functional>
#include <vector>
#include <mutex>


enum LogLevel
{
  LL_Trace,
  LL_Info,
  LL_Debug,
  LL_Warn,
  LL_Error
};


void Log(enum LogLevel a_level, const char* a_fmt, ...);


void loadFile(const char* a_fileName, std::vector<uint8_t>& a_output);
void loadFileAsync(TaskManager& a_mgr, const char* a_fileName, std::function<void(const std::vector<uint8_t>&)> a_callback);


#if 0
struct mat4
{
  mat4& operator=(const float* other)
  {
    for (int i = 0; i < 16; i++)
      m[i] = other[i];
    return *this;
  }
  union
  {
    struct
    {
      float m00, m01, m02, m03;
      float m10, m11, m12, m13;
      float m20, m21, m22, m23;
      float m30, m31, m32, m33;
    };
    float m[16];
  } __attribute__((aligned(16)));
};


struct mat3
{
  mat3& operator=(const mat3& a_other)
  {
    for (int i = 0; i < 12; i++)
      m[i] = a_other.m[i];
    return *this;
  }
  mat3& operator=(const float* a_flt3x3)
  {
    for (int i = 0; i < 9; i++)
      m[(i/3)*4+(i%3)] = a_flt3x3[i];
    return *this;
  }
  union
  {
    struct
    {
      float m00, m01, m02, dummy01;
      float m10, m11, m12, dummy02;
      float m20, m21, m22, dummy03;
    };
    float m[12];
  };
};
#endif


struct vec2f
{
  union
  {
    struct
    {
      float x, y;
    };
    float v[2];
  };
};


struct vec3f
{
  union
  {
    struct
    {
      float x, y, z;
    };
    float v[3];
  };
};


struct vec4f
{
  union
  {
    struct
    {
      float x, y, z, w;
    };
    float v[4];
  };
};


typedef int sampler2D;


template <typename ...T> struct bad_food : std::false_type {};


// Need to use inheritance from unique_lock to make it compatible with using with condition_variables
class ScopeLock : public std::unique_lock<std::mutex>
{
public:
  ScopeLock(std::mutex& a_mutex) : std::unique_lock<std::mutex>(a_mutex) {}
  template <typename F>
  void unlocked(F&& a_func)
  {
    unlock();
    a_func();
    lock();
  }
};


template <typename T>
struct GenericFactoryItem
{
  GenericFactoryItem(const char* a_name, T a_value)
    : m_name(a_name), m_value(a_value), m_next(getFactoryHead())
  {
    getFactoryHead(this);
  }
  const char* m_name;
  T m_value;
  const GenericFactoryItem<T>* m_next;
  static const GenericFactoryItem<T>* getFactoryHead(const GenericFactoryItem<T>* newValue = nullptr);
};


// It shouldn't matter, but for XCode this needed to not be inline in the definition above
template <typename T>
const GenericFactoryItem<T>* GenericFactoryItem<T>::getFactoryHead(const GenericFactoryItem<T>* newValue)
{
  static const GenericFactoryItem<T>* s_factoryHead = nullptr;
  if (newValue != nullptr)
    s_factoryHead = newValue;
  return s_factoryHead;
}


#endif // COMMON_H
