package iron.data;

import haxe.Json;
import kha.arrays.Float32Array;
import iron.math.Vec4;
import iron.data.SceneFormat;
import iron.system.LnxPack;
using StringTools;

class WorldData {

	public var name: String;
	public var raw: TWorldData;
	public var envmap: kha.Image;
	public var probe: Probe;

	static var emptyIrr: Float32Array = null;

	public function new(raw: TWorldData, done: WorldData->Void) {
		this.raw = raw;
		this.name = raw.name;

		// Parse probes
		if (raw.probe != null) {
			new Probe(raw.probe, function(self: Probe) {
				probe = self;
				#if lnx_skip_envmap
				done(this);
				#else
				loadEnvmap(done);
				#end
			});
		}
		else {
			#if lnx_skip_envmap
			done(this);
			#else
			loadEnvmap(done);
			#end
		}
	}

	public function loadEnvmap(done: WorldData->Void) {
		if (raw.envmap != null) {
			Data.getImage(raw.envmap, function(image: kha.Image) {
				envmap = image;
				done(this);
			});
		}
		else done(this);
	}

	public static function parse(name: String, id: String, done: WorldData->Void) {
		Data.getSceneRaw(name, function(format: TSceneFormat) {
			var raw: TWorldData = Data.getWorldRawByName(format.world_datas, id);
			if (raw == null) {
				trace('World data "$id" not found!');
				done(null);
			}
			new WorldData(raw, done);
		});
	}

	public static function getEmptyIrradiance(): Float32Array {
		if (emptyIrr == null) {
			emptyIrr = new Float32Array(28);
			for (i in 0...emptyIrr.length) emptyIrr.set(i, 0.0);
		}
		return emptyIrr;
	}
}

class Probe {

	public var raw: TProbeData;
	public var radiance: kha.Image;
	public var radianceMipmaps: Array<kha.Image> = [];
	public var irradiance: Float32Array;

	public function new(raw: TProbeData, done: Probe->Void) {
		this.raw = raw;

		setIrradiance(function(irr: Float32Array) {
			irradiance = irr;
			if (raw.radiance != null) {
				Data.getImage(raw.radiance, function(rad: kha.Image) {
					radiance = rad;
					while (radianceMipmaps.length < raw.radiance_mipmaps) radianceMipmaps.push(null);
					var dot = raw.radiance.lastIndexOf(".");
					var ext = raw.radiance.substring(dot);
					var base = raw.radiance.substring(0, dot);

					var mipsLoaded = 0;
					for (i in 0...raw.radiance_mipmaps) {
						Data.getImage(base + "_" + i + ext, function(mipimg: kha.Image) {
							radianceMipmaps[i] = mipimg;
							mipsLoaded++;

							if (mipsLoaded == raw.radiance_mipmaps) {
								radiance.setMipmaps(radianceMipmaps);
								done(this);
							}
						}, true); // Readable
					}
				});
			}
			else done(this);
		});
	}

	function setIrradiance(done: Float32Array->Void) {
		// Parse probe data
		if (raw.irradiance == null) {
			done(WorldData.getEmptyIrradiance());
		}
		else {
			var ext = raw.irradiance.endsWith(".json") ? "" : ".lnx";
			Data.getBlob(raw.irradiance + ext, function(b: kha.Blob) {
				var irradianceParsed: TSceneFormat = ext == "" ?
					Json.parse(b.toString()) :
					LnxPack.decode(b.toBytes());
				var irr = new Float32Array(28); // Align to mult of 4 - 27->28
				for (i in 0...27) irr[i] = irradianceParsed.irradiance[i];
				done(irr);
			});
		}
	}
}