package net.mgsx.gltf.scene3d.utils;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Cubemap.CubemapSide;
import com.badlogic.gdx.graphics.CubemapData;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Blending;
import com.badlogic.gdx.graphics.TextureData;
import com.badlogic.gdx.graphics.glutils.PixmapTextureData;
import com.badlogic.gdx.utils.GdxRuntimeException;

public class FacedMultiCubemapData implements CubemapData
{
	final protected TextureData[] data;
	private int levels;

	/**
	 * Construct Cubemap data for MipMap cubemap.
	 * @param files texture files in following order : 
	 * level 0 (positive X, negative X, positive Y, negative Y, positive Z, negative Z)
	 * level 1 (positive X, negative X, positive Y, negative Y, positive Z, negative Z)
	 * and so on. Where level 0 is the biggest texture. Expected levels x 6 files.
	 * @param levels mipmap levels
	 */
	public FacedMultiCubemapData(FileHandle[] files, int levels)
	{
		this.levels = levels;
		data = new TextureData[6 * levels];
		for(int level = 0 ; level<levels ; level++){
			for(int face = 0 ; face < 6 ; face++){
				int index = level*6+face;
				FileHandle file = files[index];
				data[index] = new PixmapTextureData(new Pixmap(file), null, false, true);
			}
		}
	}
	public FacedMultiCubemapData(Pixmap[] pixmaps, int levels)
	{
		this.levels = levels;
		data = new TextureData[6 * levels];
		for(int level = 0 ; level<levels ; level++){
			for(int face = 0 ; face < 6 ; face++){
				int index = level*6+face;
				Pixmap pixmap = pixmaps[index];
				data[index] = new PixmapTextureData(pixmap, null, false, true);
			}
		}
	}

	@Override
	public boolean isManaged () {
		for (TextureData data : this.data)
			if (!data.isManaged()) return false;
		return true;
	}

	/** @return True if all sides of this cubemap are set, false otherwise. */
	public boolean isComplete () {
		for (int i = 0; i < data.length; i++)
			if (data[i] == null) return false;
		return true;
	}

	/** @return The {@link TextureData} for the specified side, can be null if the cubemap is incomplete. */
	public TextureData getTextureData (CubemapSide side) {
		return data[side.index];
	}

	@Override
	public int getWidth () {
		int tmp, width = 0;
		if (data[CubemapSide.PositiveZ.index] != null && (tmp = data[CubemapSide.PositiveZ.index].getWidth()) > width) width = tmp;
		if (data[CubemapSide.NegativeZ.index] != null && (tmp = data[CubemapSide.NegativeZ.index].getWidth()) > width) width = tmp;
		if (data[CubemapSide.PositiveY.index] != null && (tmp = data[CubemapSide.PositiveY.index].getWidth()) > width) width = tmp;
		if (data[CubemapSide.NegativeY.index] != null && (tmp = data[CubemapSide.NegativeY.index].getWidth()) > width) width = tmp;
		return width;
	}

	@Override
	public int getHeight () {
		int tmp, height = 0;
		if (data[CubemapSide.PositiveZ.index] != null && (tmp = data[CubemapSide.PositiveZ.index].getHeight()) > height)
			height = tmp;
		if (data[CubemapSide.NegativeZ.index] != null && (tmp = data[CubemapSide.NegativeZ.index].getHeight()) > height)
			height = tmp;
		if (data[CubemapSide.PositiveX.index] != null && (tmp = data[CubemapSide.PositiveX.index].getHeight()) > height)
			height = tmp;
		if (data[CubemapSide.NegativeX.index] != null && (tmp = data[CubemapSide.NegativeX.index].getHeight()) > height)
			height = tmp;
		return height;
	}

	@Override
	public boolean isPrepared () {
		return false;
	}

	@Override
	public void prepare () {
		if (!isComplete()) throw new GdxRuntimeException("You need to complete your cubemap data before using it");
		for (int i = 0; i < data.length; i++)
			if (!data[i].isPrepared()) data[i].prepare();
	}

	@Override
	public void consumeCubemapData () {
		for(int level = 0 ; level<levels ; level++){
			for (int i = 0; i < 6; i++) {
				int index = level * 6 + i;
				if (data[index].getType() == TextureData.TextureDataType.Custom) {
					data[index].consumeCustomData(GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i);
				} else {
					Pixmap pixmap = data[index].consumePixmap();
					boolean disposePixmap = data[index].disposePixmap();
					if (data[index].getFormat() != pixmap.getFormat()) {
						Pixmap tmp = new Pixmap(pixmap.getWidth(), pixmap.getHeight(), data[index].getFormat());
						tmp.setBlending(Blending.None);
						tmp.drawPixmap(pixmap, 0, 0, 0, 0, pixmap.getWidth(), pixmap.getHeight());
						if (data[index].disposePixmap()) pixmap.dispose();
						pixmap = tmp;
						disposePixmap = true;
					}
					Gdx.gl.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 1);
					Gdx.gl.glTexImage2D(GL20.GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, pixmap.getGLInternalFormat(), pixmap.getWidth(),
						pixmap.getHeight(), 0, pixmap.getGLFormat(), pixmap.getGLType(), pixmap.getPixels());
					if (disposePixmap) pixmap.dispose();
				}
			}
		}
	}

}