// Copyright (c) 2023 Alex Diener. All rights reserved.

#include "binaryserialization/BinaryDeserializationContext.h"
#include "imageio/ImageIO.h"
#include "PROJECT_NAME/FileUtilities.h"
#include "utilities/IOUtilities.h"

static ImageCollection * readImageCollectionFromFileBundle(FileBundle * bundle, const char * entryName) {
	uint32_t dataSize;
	const void * data = FileBundle_getFile(bundle, entryName, &dataSize);
	if (data == NULL) {
		return NULL;
	}
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, dataSize);
	ImageCollection * imageCollection = ImageCollection_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	return imageCollection;
}

static BitmapImage * readBitmapImageFromFileBundle(FileBundle * bundle, const char * entryName) {
	uint32_t dataSize;
	const void * data = FileBundle_getFile(bundle, entryName, &dataSize);
	if (data == NULL) {
		return NULL;
	}
	return ImageIO_readImageData(data, dataSize, IMAGE_PIXEL_FORMAT_AUTOMATIC, false);
}

static TextureAtlasData * readTextureAtlasDataFromFileBundle(FileBundle * bundle, const char * entryName) {
	uint32_t dataSize;
	const void * data = FileBundle_getFile(bundle, entryName, &dataSize);
	if (data == NULL) {
		return NULL;
	}
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, dataSize);
	TextureAtlasData * atlasData = TextureAtlasData_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	return atlasData;
}

bool unpackImageCollectionBundle(FileBundle * bundle, ImageCollection ** outImageCollection, BitmapImage ** outAtlasImage, TextureAtlasData ** outAtlasData) {
	ImageCollection * imageCollection = readImageCollectionFromFileBundle(bundle, "image_collection");
	if (imageCollection == NULL) {
		return NULL;
	}
	
	BitmapImage * atlasImage = readBitmapImageFromFileBundle(bundle, "image");
	if (atlasImage == NULL) {
		ImageCollection_dispose(imageCollection);
		return false;
	}
	
	TextureAtlasData * atlasData = readTextureAtlasDataFromFileBundle(bundle, "atlas");
	if (atlasData == NULL) {
		ImageCollection_dispose(imageCollection);
		BitmapImage_dispose(atlasImage);
		return false;
	}
	
	*outImageCollection = imageCollection;
	*outAtlasImage = atlasImage;
	*outAtlasData = atlasData;
	return true;
}

TilesetEditData * readTilesetEditData(const void * data, size_t size) {
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, size);
	if (context->status != SERIALIZATION_ERROR_OK) {
		BinaryDeserializationContext_dispose(context);
		return NULL;
	}
	TilesetEditData * tileset = TilesetEditData_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	return tileset;
}

TilesetAdjacencyBlendMap * readTilesetAdjacencyBlendMapData(const void * data, size_t size) {
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, size);
	if (context->status != SERIALIZATION_ERROR_OK) {
		BinaryDeserializationContext_dispose(context);
		return NULL;
	}
	TilesetAdjacencyBlendMap * blendMap = TilesetAdjacencyBlendMap_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	return blendMap;
}

SpriteCollection * readSpriteCollectionData(const void * data, size_t size, ImageCollection * imageCollection) {
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, size);
	if (context->status != SERIALIZATION_ERROR_OK) {
		BinaryDeserializationContext_dispose(context);
		return NULL;
	}
	SpriteCollection * spriteCollection = SpriteCollection_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	if (spriteCollection != NULL) {
		SpriteCollection_resolveImageIndexes(spriteCollection, imageCollection);
	}
	return spriteCollection;
}

TileMapEditData * readTileMapEditData(const void * data, size_t size) {
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, size);
	if (context->status != SERIALIZATION_ERROR_OK) {
		BinaryDeserializationContext_dispose(context);
		return NULL;
	}
	TileMapEditData * tileMapData = TileMapEditData_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	return tileMapData;
}

TileZoneMap * readTileZoneMap(const void * data, size_t size) {
	BinaryDeserializationContext * context = BinaryDeserializationContext_createWithBytes(data, size);
	if (context->status != SERIALIZATION_ERROR_OK) {
		BinaryDeserializationContext_dispose(context);
		return NULL;
	}
	TileZoneMap * zoneMap = TileZoneMap_deserialize(context);
	BinaryDeserializationContext_dispose(context);
	return zoneMap;
}
