/*
 * Copyright 2022-2025 Frederico de Oliveira Linhares
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "binary_writer.hpp"

namespace
{

union IntAndFloat32bit{
  UI32 i;
  F32 f;
};

union IntAndFloat64bit{
  UI64 i;
  F64 f;
};

}

BinaryWriter::BinaryWriter(const char *file_path):
  output{file_path, std::ios::binary}
{
}

BinaryWriter::BinaryWriter(const std::string &file_path):
  BinaryWriter{file_path.c_str()}
{
}

void
BinaryWriter::write_ui8(UI8 var)
{
	this->output.put(var);
}

void
BinaryWriter::write_ui32(UI32 var)
{
  using namespace std;

  UI8 b1 = var >> 24;
  UI8 b2 = var >> 16;
  UI8 b3 = var >> 8;
  UI8 b4 = var;

  this->output.put(b1);
  this->output.put(b2);
  this->output.put(b3);
  this->output.put(b4);
}

void
BinaryWriter::write_ui64(UI64 var)
{
  using namespace std;

  UI8 b1 = var >> 56;
  UI8 b2 = var >> 48;
  UI8 b3 = var >> 40;
  UI8 b4 = var >> 32;
  UI8 b5 = var >> 24;
  UI8 b6 = var >> 16;
  UI8 b7 = var >> 8;
  UI8 b8 = var;

  this->output.put(b1);
  this->output.put(b2);
  this->output.put(b3);
  this->output.put(b4);
  this->output.put(b5);
  this->output.put(b6);
  this->output.put(b7);
  this->output.put(b8);
}

void
BinaryWriter::write_f32(F32 var)
{
  IntAndFloat32bit num;
  num.f = var;
  write_ui32(num.i);
}

void
BinaryWriter::write_f64(F64 var)
{
  IntAndFloat64bit num;
  num.f = var;
  write_ui64(num.i);
}

void
BinaryWriter::write_vec2(glm::vec2 var)
{
  IntAndFloat32bit x, y;
  x.f = var.x;
  y.f = var.y;

  this->write_ui32(x.i);
  this->write_ui32(y.i);
}

void
BinaryWriter::write_vec3(glm::vec3 var)
{
  IntAndFloat32bit x, y, z;
  x.f = var.x;
  y.f = var.y;
  z.f = var.z;

  this->write_ui32(x.i);
  this->write_ui32(y.i);
  this->write_ui32(z.i);
}

void
BinaryWriter::write_quat(glm::quat var)
{
  IntAndFloat32bit w, x, y, z;
  w.f = var.w;
  x.f = var.x;
  y.f = var.y;
  z.f = var.z;

  this->write_ui32(w.i);
  this->write_ui32(x.i);
  this->write_ui32(y.i);
  this->write_ui32(z.i);
}

void
BinaryWriter::write_mat4(glm::mat4 var)
{
  float *offset_matrix_data{glm::value_ptr(var)};
  IntAndFloat32bit num;

  for(int i{0}; i < 16; i++)
  {
    num.f = offset_matrix_data[i];
    this->write_ui32(num.i);
  }
}

void
BinaryWriter::write_chars(const char *str, int size)
{
  for(int i{0}; i < size; i++) this->write_ui8((UI8)str[i]);
}