#include "Deer/VoxelWorld.h"
#include "Deer/Voxels/VoxelWorldData.h"

#include "Deer/Log.h"
#include "Deer/Voxels/Chunk.h"
#include "Deer/Voxels/Layer.h"

#ifdef DEER_RENDER
#include "DeerRender/Voxels/VoxelWorldRenderData.h"
#endif

#include <math.h>

#include <cmath>
#include <vector>

namespace Deer {
	void VoxelWorld::initialize(const VoxelWorldProps& props) {
		clear();

		worldProps = props;

		chunks = MakeScope<Chunk[]>(worldProps.getChunkCount());
		layers = MakeScope<Layer[]>(worldProps.getLayerCount());

#ifdef DEER_RENDER
		initializeRenderVars(props);
#endif
		initialized = true;
	}

	void VoxelWorld::clear() {
		chunks.reset();
		layers.reset();

		initialized = false;
#ifdef DEER_RENDER
		clearRenderVars();
#endif
	}

	const VoxelWorldProps& VoxelWorld::getWorldProps() {
		return worldProps;
	}
	
	uint16_t VoxelWorld::calculateLayerVoxelHeight(int x, int z) {
		DEER_CORE_ASSERT(initialized, "Voxel World is not initialized");
		LayerVoxelID layerVoxelID;
		LayerID layerID;

		extractLayerCordinates(x, z, layerID, layerVoxelID);
		ChunkID chunkID(layerID.x, 0, layerID.z);

		for (int y = worldProps.chunkSizeY - 1; y >= 0; y--) {
			chunkID.y = y;

			Chunk& chunk = chunks[worldProps.getWorldChunkID(chunkID)];
			uint8_t chunkVoxelHeight =
			    chunk.calculateLayerVoxelHeight(layerVoxelID);

			if (chunkVoxelHeight != 0) {
				return chunkVoxelHeight + chunkID.y * CHUNK_SIZE_Y;
			}
		}
		
		return 0;
	}
}  // namespace Deer
