#include "Assets.h"

#include "Model.h"
#include "Utility.h"

namespace nf {
	Asset::~Asset() {
		delete[] data;
	}

	AModel::~AModel() {

	}

	ATexture::~ATexture() {

	}

	ACubemap::~ACubemap() {
		delete[] frontData;
		delete[] backData;
		delete[] topData;
		delete[] bottomData;
		delete[] leftData;
		delete[] rightData;
	}

	AShader::~AShader() {

	}

	AFont::~AFont() {

	}

	AssetPack::AssetPack() {

	}

	void AssetPack::load(const char* packName) {
		std::string path = "assets/" + (std::string)packName;
		std::string packContents = readFile(path);
		unsigned int cubemapCount = 0;
		while (packContents.size()) {
			unsigned int startingPos = packContents.find_first_of("#NFASSET ") + 9;
			packContents = packContents.substr(9);
			unsigned int endAssetNamePos = packContents.find_first_of('\n');
			std::string assetName = packContents.substr(0, endAssetNamePos);
			packContents = packContents.substr(endAssetNamePos + 1);
			unsigned int extensionPos = assetName.find_first_of('.');
			std::string extension = assetName.substr(extensionPos + 1);
			std::string assetContents;
			unsigned int nextAssetPos = packContents.find("#NFASSET ");
			if (nextAssetPos != std::string::npos) {
				assetContents = packContents.substr(0, nextAssetPos - 1);
				packContents = packContents.substr(nextAssetPos);
			}
			else {
				assetContents = packContents;
				packContents = "";
			}
			size_t assetSize = assetContents.size();

			if (extension == "obj") {
				AModel* geometry = new AModel;
				geometry->data = new char[assetSize + 1];
				std::memcpy(geometry->data, &assetContents[0], assetSize);
				geometry->data[assetSize] = '\0';
				geometry->alreadyLoaded = false;
				geometry->loadedModel = nullptr;
				m_assets[assetName] = geometry;
				continue;
			}
			if (extension == "png") {
				if (assetName.find("_cmfront") != std::string::npos || assetName.find("_cmback") != std::string::npos || assetName.find("_cmtop") != std::string::npos || assetName.find("_cmbottom") != std::string::npos || assetName.find("_cmleft") != std::string::npos || assetName.find("_cmright") != std::string::npos) {
					static std::unordered_map<std::string, ACubemap*> cubemaps;
					std::string cmName = assetName.substr(0, assetName.find('_'));
					ACubemap* curr;
					if (cubemaps.find(cmName) == cubemaps.end()) {
						cubemaps[cmName] = new ACubemap;
						cubemaps[cmName]->numImages = 0;
					}
					curr = cubemaps[cmName];
					if (curr->numImages == 6)
						Error("Duplicate cubemap images in pack \"" + (std::string)packName + (std::string)"\"!");
					if (assetName.find("_cmfront") != std::string::npos) {
						curr->frontData = new char[assetSize];
						std::memcpy(curr->frontData, &assetContents[0], assetSize);
						curr->frontSize = assetSize;
					}
					if (assetName.find("_cmback") != std::string::npos) {
						curr->backData = new char[assetSize];
						std::memcpy(curr->backData, &assetContents[0], assetSize);
						curr->backSize = assetSize;
					}
					if (assetName.find("_cmtop") != std::string::npos) {
						curr->topData = new char[assetSize];
						std::memcpy(curr->topData, &assetContents[0], assetSize);
						curr->topSize = assetSize;
					}
					if (assetName.find("_cmbottom") != std::string::npos) {
						curr->bottomData = new char[assetSize];
						std::memcpy(curr->bottomData, &assetContents[0], assetSize);
						curr->bottomSize = assetSize;
					}
					if (assetName.find("_cmleft") != std::string::npos) {
						curr->leftData = new char[assetSize];
						std::memcpy(curr->leftData, &assetContents[0], assetSize);
						curr->leftSize = assetSize;
					}
					if (assetName.find("_cmright") != std::string::npos) {
						curr->rightData = new char[assetSize];
						std::memcpy(curr->rightData, &assetContents[0], assetSize);
						curr->rightSize = assetSize;
					}
					curr->numImages++;

					if (curr->numImages == 6) {
						m_assets[cmName + (std::string)".cm"] = curr;
					}

					cubemapCount++;
					continue;
				}
				ATexture* texture = new ATexture;
				texture->data = new char[assetSize];
				std::memcpy(texture->data, &assetContents[0], assetSize);
				texture->size = assetSize;
				m_assets[assetName] = texture;
				continue;
			}
			if (extension == "shader") {
				AShader* shader = new AShader;
				shader->data = new char[assetSize + 1];
				std::memcpy(shader->data, &assetContents[0], assetSize);
				shader->data[assetSize] = '\0';
				m_assets[assetName] = shader;
				continue;
			}
			if (extension == "ttf") {
				AFont* font = new AFont;
				font->data = new char[assetSize];
				std::memcpy(font->data, &assetContents[0], assetSize);
				font->size = assetSize;
				m_assets[assetName] = font;
				continue;
			}
			Error("Invalid asset extention in pack \"" + (std::string)packName + (std::string)"\"!");
		}
		if (cubemapCount % 6 != 0)
			Error("Could not find full cubemap in pack \"" + (std::string)packName + (std::string)"\"!")
	}

	Asset* AssetPack::operator[](const char* in) {
		if (m_assets.find(in) == m_assets.end())
			Error("Could not find asset \"" + (std::string)in + (std::string)"\" in asset pack!");
		return m_assets[in];
	}
	Asset* AssetPack::operator[](std::string& in) {
		if (m_assets.find(in) == m_assets.end())
			Error("Could not find asset \"" + in + (std::string)"\" in asset pack!");
		return m_assets[in];
	}

	void AssetPack::unload() {
		for (auto curr : m_assets)
			delete curr.second;
	}

	AssetPack::~AssetPack() {
		unload();
	}

	AModel* BaseAssets::cube;
	AModel* BaseAssets::plane;
	AModel* BaseAssets::sphere;
	AModel* BaseAssets::cone;
	AModel* BaseAssets::cylinder;
	AModel* BaseAssets::torus;

	ATexture* BaseAssets::logo;

	AFont* BaseAssets::defaultFont;
}