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

#include "TextureAsset.hpp"

using namespace Dawn;

TextureAsset::TextureAsset(AssetManager *assetManager, std::string name) :
  Asset(assetManager, name),
  loader(name + ".texture"),
  texture()
{
}

void TextureAsset::updateSync() {
  if(
    this->state != 0x03
  ) return;

  this->state = 0x04;

  
  this->texture.setSize(this->width, this->height, this->format, TEXTURE_DATA_FORMAT_UNSIGNED_BYTE);
  this->texture.buffer(this->colors);
  
  this->texture.wrapModeX = this->wrapModeX;
  this->texture.wrapModeY = this->wrapModeY;
  this->texture.filterModeMin = this->filterModeMin;
  this->texture.filterModeMag = this->filterModeMag;

  this->state = 0x05;
  this->loaded = true;
}

void TextureAsset::updateAsync() {
  if(this->state != 0x00) return;
  this->state = 0x01;
  this->loader.loadRaw(&this->buffer);
  this->state = 0x02;

  // Parse header data.
  char integer[256];
  size_t j = 0, i = 0;
  enum TextureAssetHeaderParseState parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION;
  while(true) {
    if(parseState == TEXTURE_ASSET_HEADER_PARSE_STATE_END) break;
    
    auto c = this->buffer[i++];
    if(c != '|') {
      integer[j++] = c;
      continue;
    }
    
    integer[j] = '\0';

    switch(parseState) {
      case TEXTURE_ASSET_HEADER_PARSE_STATE_VERSION: {
        auto compared = strcmp(integer, "DT_2.00");
        assertTrue(compared == 0);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_WIDTH: {
        this->width = atoi(integer);
        assertTrue(this->width > 0);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_HEIGHT: {
        this->height = atoi(integer);
        assertTrue(this->height > 0);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_FORMAT: {
        this->format = (enum TextureFormat)atoi(integer);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_X: {
        this->wrapModeX = (enum TextureWrapMode)atoi(integer);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_WRAP_MODE_Y: {
        this->wrapModeY = (enum TextureWrapMode)atoi(integer);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MIN: {
        this->filterModeMin = (enum TextureFilterMode)atoi(integer);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG;
        break;
      }

      case TEXTURE_ASSET_HEADER_PARSE_STATE_FILTER_MODE_MAG: {
        this->filterModeMag = (enum TextureFilterMode)atoi(integer);
        j = 0;
        parseState = TEXTURE_ASSET_HEADER_PARSE_STATE_END;
        break;
      }

      default:
        assertUnreachable();
    }
  }

  this->colors = (uint8_t*)((void *)(this->buffer + i));
  this->state = 0x03;
}

TextureAsset::~TextureAsset() {
  if(this->buffer != nullptr) {
    memoryFree(this->buffer);
    this->buffer = nullptr;
  }
}