package codechicken.lib.render;

import codechicken.lib.render.SpriteSheetManager.SpriteSheet;
import codechicken.lib.render.TextureUtils.IIconRegister;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.client.renderer.texture.TextureUtil;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.data.AnimationMetadataSection;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.util.ResourceLocation;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;

@SideOnly(Side.CLIENT)
public class TextureSpecial extends TextureAtlasSprite implements IIconRegister
{
    //sprite sheet fields
    private int spriteIndex;
    private SpriteSheet spriteSheet;

    //textureFX fields
    private TextureFX textureFX;
    private int mipmapLevels;
    private int rawWidth;
    private int rawHeight;

    private int blankSize = -1;
    private ArrayList<TextureDataHolder> baseTextures;

    private boolean selfRegister;
    public int atlasIndex;

    protected TextureSpecial(String par1) {
        super(par1);
    }

    public TextureSpecial addTexture(TextureDataHolder t) {
        if (baseTextures == null)
            baseTextures = new ArrayList<TextureDataHolder>();
        baseTextures.add(t);
        return this;
    }

    public TextureSpecial baseFromSheet(SpriteSheet spriteSheet, int spriteIndex) {
        this.spriteSheet = spriteSheet;
        this.spriteIndex = spriteIndex;
        return this;
    }

    public TextureSpecial addTextureFX(TextureFX fx) {
        textureFX = fx;
        return this;
    }

    @Override
    public void initSprite(int sheetWidth, int sheetHeight, int originX, int originY, boolean rotated) {
        super.initSprite(sheetWidth, sheetHeight, originX, originY, rotated);
        if (textureFX != null)
            textureFX.onTextureDimensionsUpdate(rawWidth, rawHeight);
    }

    @Override
    public void updateAnimation() {
        if (textureFX != null) {
            textureFX.update();
            if (textureFX.changed()) {
                int[][] mipmaps = new int[mipmapLevels + 1][];
                mipmaps[0] = textureFX.imageData;
                //TODO mipmaps = prepareAnisotropicFiltering(mipmaps);
                mipmaps = TextureUtil.generateMipmapData(mipmapLevels, width, mipmaps);
                TextureUtil.uploadTextureMipmap(mipmaps, width, height, originX, originY, false, false);
            }
        }
    }

    /**
     * Copy paste mojang code because it's private, and CCL can't have access transformers or reflection
     */
    /*public int[][] prepareAnisotropicFiltering(int[][] mipmaps) {
        if (Minecraft.getMinecraft().gameSettings.anisotropicFiltering <= 1)
        {
            return mipmaps;
        }
        else
        {
            int[][] aint1 = new int[mipmaps.length][];

            for (int k = 0; k < mipmaps.length; ++k)
            {
                int[] aint2 = mipmaps[k];

                if (aint2 != null)
                {
                    int[] aint3 = new int[(rawWidth + 16 >> k) * (rawHeight + 16 >> k)];
                    System.arraycopy(aint2, 0, aint3, 0, aint2.length);
                    aint1[k] = TextureUtil.prepareAnisotropicData(aint3, rawWidth >> k, rawHeight >> k, 8 >> k);
                }
            }

            return aint1;
        }
    }*/

    @Override
    public void loadSprite(BufferedImage[] images, AnimationMetadataSection animationMeta) {
        rawWidth = images[0].getWidth();
        rawHeight = images[0].getHeight();
        try
        {
            super.loadSprite(images, null);
        }
        catch(IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void generateMipmaps(int p_147963_1_) {
        super.generateMipmaps(p_147963_1_);
        mipmapLevels = p_147963_1_;
    }

    @Override
    public boolean hasCustomLoader(IResourceManager manager, ResourceLocation location) {
        return true;
    }

    public void addFrame(int[] data, int width, int height) {
        GameSettings settings = Minecraft.getMinecraft().gameSettings;
        BufferedImage[] images = new BufferedImage[settings.mipmapLevels+1];
        images[0] = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        images[0].setRGB(0, 0, width, height, data, 0, width);

        loadSprite(images, null);
    }

    @Override
    public boolean load(IResourceManager manager, ResourceLocation location) {
        if (baseTextures != null) {
            for (TextureDataHolder tex : baseTextures)
                addFrame(tex.data, tex.width, tex.height);
        }
        else if (spriteSheet != null) {
            TextureDataHolder tex = spriteSheet.createSprite(spriteIndex);
            addFrame(tex.data, tex.width, tex.height);
        }
        else if (blankSize > 0) {
            addFrame(new int[blankSize * blankSize], blankSize, blankSize);
        }

        if (framesTextureData.isEmpty())
            throw new RuntimeException("No base frame for texture: " + getIconName());

        return false;
    }

    @Override
    public boolean hasAnimationMetadata() {
        return textureFX != null || super.hasAnimationMetadata();
    }

    @Override
    public int getFrameCount() {
        if (textureFX != null)
            return 1;

        return super.getFrameCount();
    }

    public TextureSpecial blank(int size) {
        blankSize = size;
        return this;
    }

    public TextureSpecial selfRegister() {
        selfRegister = true;
        TextureUtils.addIconRegister(this);
        return this;
    }

    @Override
    public void registerIcons(TextureMap textureMap) {
        textureMap.setTextureEntry(getIconName(), this);
    }
}