/**
 * Copyright (c) 2021 Dominic Msters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "asset.h"

char * assetStringLoad(char *assetName) {
  // Open a buffer.
  FILE *fptr = assetBufferOpen(assetName);
  if(fptr == NULL) return NULL;

  // Read the count of bytes in the file
  fseek(fptr, 0, SEEK_END);// Seek to the end
  size_t length = ftell(fptr);// Get our current position (the end)
  fseek(fptr, 0, SEEK_SET);// Reset the seek 

  // Create the string buffer
  char *str = malloc(length + 1);// Add 1 for the null terminator.
  if(str == NULL) {
    assetBufferClose(fptr);
    return NULL;
  }

  // Read and seal the string.
  fread(str, 1, length, fptr);// Read all the bytes
  str[length] = '\0';// Null terminate.
  assetBufferClose(fptr); // Close the buffer.

  return str;
}

FILE * assetBufferOpen(char *assetName) {
  // Get the directory based on the raw input by creating a new string.
  size_t lenAsset = strlen(assetName);// Get the length of asset
  size_t lenPrefix = strlen(ASSET_PREFIX);// Get the length of the prefix
  
  // Create str to house both the prefix and asset, and null terminator
  char *joined = malloc(lenAsset + lenPrefix + 1);
  if(joined == NULL) return NULL;// Mem okay?

  joined[0] = '\0';//Start at null
  strcat(joined, ASSET_PREFIX);//Add prefix
  strcat(joined, assetName);//Add body

  // Open the file pointer now.
  FILE *fptr = fopen(joined, "rb");
  free(joined);// Free the string we just created
  if(!fptr) return NULL;// File available?
  return fptr;
}

bool assetBufferClose(FILE *buffer) {
  return fclose(buffer);
}

int32_t assetBufferRead(FILE *buffer, char *data, int32_t size) {
  return (int32_t)fread(data, 1, size, buffer);
}

int32_t assetBufferEnd(FILE *buffer) {
  return feof(buffer);
}

void assetBufferSkip(FILE *buffer, int32_t n) {
  fseek(buffer, n, SEEK_CUR);
}

void assetShaderLoad(shader_t *shader, char *fileVertex, char *fileFragment) {
  // Load the vertex shader into memory
  char *vertexShader = assetStringLoad(fileVertex);
  if(vertexShader == NULL) return;

  // Load the fragment shader into memory
  char *fragmentShader = assetStringLoad(fileFragment);
  if(fragmentShader == NULL) {
    free(vertexShader);
    return;
  }

  // Now attempt to load the shader
  shaderInit(shader, vertexShader, fragmentShader);
  
  //Cleanup
  free(vertexShader);
  free(fragmentShader);
}

void assetTextureLoad(texture_t *texture, char *fileName) {
  FILE *buffer;
  int channels, width, height;
  pixel_t *data;
  stbi_io_callbacks OPENGL_STBI_CALLBACKS;

  buffer = assetBufferOpen(fileName);
  if(buffer == NULL) return;
  
  // Setup the interface for STBI
  OPENGL_STBI_CALLBACKS.read = &assetBufferRead;
  OPENGL_STBI_CALLBACKS.skip = &assetBufferSkip;
  OPENGL_STBI_CALLBACKS.eof = &assetBufferEnd; 

  // Buffer the image
  channels = 0;
  data = (pixel_t *)stbi_load_from_callbacks(
    &OPENGL_STBI_CALLBACKS, buffer,
    &width, &height,
    &channels, STBI_rgb_alpha
  );

  // Close the buffer
  assetBufferClose(buffer);
  if(data == NULL) return;

  // Turn into a texture.
  textureInit(texture, width, height, data);
  stbi_image_free(data);
}

void assetFontLoad(font_t *font, char *assetName) {
  char *data = assetStringLoad(assetName);
  fontInit(font, data);
  free(data);
}