package client.renderer.texture;

import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import client.init.RenderRegistry;
import client.renderer.GlState;
import client.util.FileUtils;
import common.block.Block;
import common.collect.Lists;
import common.collect.Maps;
import common.init.BlockRegistry;
import common.init.FluidRegistry;
import common.log.Log;

public class TextureMap extends Texture
{
    public static final String LOCATION_MISSING_TEXTURE = "missingno";
    public static final String locationBlocksTexture = "textures/atlas/blocks.png";
    
    private final List<TextureAtlasSprite> listAnimatedSprites;
    private final Map<String, TextureAtlasSprite> mapRegisteredSprites;
    private final Map<String, TextureAtlasSprite> mapUploadedSprites;
    private final Map<String, Class<? extends TextureTicked>> tickedTextures;
    private final Map<String, Integer> animTextures;
    private final TextureAtlasSprite missingImage;

    public TextureMap()
    {
        this.listAnimatedSprites = Lists.<TextureAtlasSprite>newArrayList();
        this.mapRegisteredSprites = Maps.<String, TextureAtlasSprite>newHashMap();
        this.mapUploadedSprites = Maps.<String, TextureAtlasSprite>newHashMap();
        this.tickedTextures = Maps.<String, Class<? extends TextureTicked>>newHashMap();
        this.animTextures = Maps.<String, Integer>newHashMap();
        this.missingImage = new TextureAtlasSprite(LOCATION_MISSING_TEXTURE);
//		RenderRegistry.registerAnimations(this);
        Map<String, Object> map = Maps.newHashMap();
        Map<String, Class<? extends TextureTicked>> anim = Maps.newHashMap();
        RenderRegistry.registerAnimations(anim);
		for(Block block : BlockRegistry.REGISTRY) {
			block.getAnimatedTextures(map);
		}
		for(int z = 0; z < FluidRegistry.getNumFluids(); z++) {
			map.put("blocks/" + BlockRegistry.getNameFromBlock(FluidRegistry.getStaticBlock(z)) + "_still", 
					FluidRegistry.getStaticAnim(z));
			map.put("blocks/" + BlockRegistry.getNameFromBlock(FluidRegistry.getStaticBlock(z)) + "_flow", 
					FluidRegistry.getFluidAnim(z));
		}
		for(Entry<String, Object> entry : map.entrySet()) {
			if(entry.getValue() instanceof Integer) {
				this.animTextures.put(entry.getKey(), (Integer)entry.getValue());
			}
			else {
				Class<? extends TextureTicked> clazz = anim.get((String)entry.getValue());
				if(clazz == null)
					throw new RuntimeException("Animation '" + (String)entry.getValue() + "' existiert nicht");
				this.tickedTextures.put(entry.getKey(), clazz);
			}
		}
		map.clear();
		anim.clear();
    }

    private void initMissingImage()
    {
        this.missingImage.setIconWidth(16);
        this.missingImage.setIconHeight(16);
        this.missingImage.setFramesTextureData(Lists.newArrayList(TextureUtil.MISSING_DATA));
    }

    public void loadTexture() throws IOException
    {
    }

    public void loadSprites(IIconCreator creator)
    {
        this.mapRegisteredSprites.clear();
        creator.registerSprites(this);
        this.initMissingImage();
        this.deleteGlTexture();
        this.loadTextureAtlas();
    }

    public void loadTextureAtlas()
    {
        Stitcher stitcher = new Stitcher();
        this.mapUploadedSprites.clear();
        this.listAnimatedSprites.clear();
        int j = Integer.MAX_VALUE;
//        int k = 1 << this.mipmapLevels;

        for (Entry<String, TextureAtlasSprite> entry : this.mapRegisteredSprites.entrySet())
        {
            TextureAtlasSprite textureatlassprite = (TextureAtlasSprite)entry.getValue();
            String name = String.format("textures/%s.png", textureatlassprite.getIconName());

            try
            {
                Class<? extends TextureTicked> animationmetadatasection = this.tickedTextures.get(textureatlassprite.getIconName());
                
                if(animationmetadatasection != null) {
                	textureatlassprite.loadSprite(animationmetadatasection);
                }
                else {
	                BufferedImage abufferedimage = // new BufferedImage[1 + this.mipmapLevels];
//	                abufferedimage[0] = 
	                TextureUtil.readImage(FileUtils.getResource(name));
	                Integer frametime = this.animTextures.get(textureatlassprite.getIconName());
	                textureatlassprite.loadSprite(abufferedimage, frametime == null ? 0 : frametime.intValue());
                }
            }
            catch (RuntimeException runtimeexception)
            {
            	Log.IO.error((Throwable)runtimeexception, (String)("Konnte Metadaten von " + name + " nicht laden"));
                continue;
            }
            catch (FileNotFoundException f)
            {
            	Log.IO.warn("Textur ist nicht vorhanden: " + name);
                continue;
            }
            catch (IOException ioexception1)
            {
            	Log.IO.error((Throwable)ioexception1, (String)("Benutze Ersatztextur, konnte " + name + " nicht laden"));
                continue;
            }

            j = Math.min(j, Math.min(textureatlassprite.getIconWidth(), textureatlassprite.getIconHeight()));
            int l1 = Math.min(Integer.lowestOneBit(textureatlassprite.getIconWidth()), Integer.lowestOneBit(textureatlassprite.getIconHeight()));

//            if (l1 < k)
//            {
//            	Log.warn("Textur " + name + " mit Größe " + textureatlassprite.getIconWidth() + "x" + textureatlassprite.getIconHeight() + " begrenzt Mipmap-Level von " + MathHelper.calculateLogBaseTwo(k) + " auf " + MathHelper.calculateLogBaseTwo(l1));
//                k = l1;
//            }

            stitcher.addSprite(textureatlassprite);
        }

//        int j1 = Math.min(j, k);
//        int k1 = MathHelper.calculateLogBaseTwo(j1);
//
//        if (k1 < this.mipmapLevels)
//        {
//        	Log.warn(this.basePath + ": setze Mipmap-Level von " + this.mipmapLevels + " auf " + k1 + " herab, wegen der kleinsten Größe mit Potenz von zwei: " + j1);
//            this.mipmapLevels = k1;
//        }

//        for (final TextureAtlasSprite textureatlassprite1 : this.mapRegisteredSprites.values())
//        {
//            textureatlassprite1.generateMipmaps(this.mipmapLevels);
//        }
//
//        this.missingImage.generateMipmaps(this.mipmapLevels);
        stitcher.addSprite(this.missingImage);

        try
        {
            stitcher.doStitch();
        }
        catch (IndexOutOfBoundsException stitcherexception)
        {
            throw stitcherexception;
        }

        Log.RENDER.info("Textur-Atlas in Größe " + stitcher.getCurrentWidth() + "x" + stitcher.getCurrentHeight() + " erstellt");
        TextureUtil.allocateTexture(this.getGlTextureId(), stitcher.getCurrentWidth(), stitcher.getCurrentHeight());
        Map<String, TextureAtlasSprite> map = Maps.<String, TextureAtlasSprite>newHashMap(this.mapRegisteredSprites);

        for (TextureAtlasSprite textureatlassprite2 : stitcher.getStichSlots())
        {
            String s = textureatlassprite2.getIconName();
            map.remove(s);
            this.mapUploadedSprites.put(s, textureatlassprite2);

            TextureUtil.uploadTexture(textureatlassprite2.getFrameTextureData(0), textureatlassprite2.getIconWidth(), textureatlassprite2.getIconHeight(), textureatlassprite2.getOriginX(), textureatlassprite2.getOriginY());

            if (textureatlassprite2.isAnimated())
            {
                this.listAnimatedSprites.add(textureatlassprite2);
            }
        }

        for (TextureAtlasSprite textureatlassprite3 : map.values())
        {
            textureatlassprite3.copyFrom(this.missingImage);
        }
    }

    public TextureAtlasSprite getAtlasSprite(String iconName)
    {
        TextureAtlasSprite textureatlassprite = (TextureAtlasSprite)this.mapUploadedSprites.get(iconName);

        if (textureatlassprite == null)
        {
            textureatlassprite = this.missingImage;
        }

        return textureatlassprite;
    }

    public void updateAnimations()
    {
        GlState.bindTexture(this.getGlTextureId());

        for (TextureAtlasSprite textureatlassprite : this.listAnimatedSprites)
        {
            textureatlassprite.updateAnimation();
        }
    }

    public TextureAtlasSprite registerSprite(String location)
    {
        if (location == null)
        {
            throw new IllegalArgumentException("Location kann nicht Null sein!");
        }
        else
        {
            TextureAtlasSprite textureatlassprite = (TextureAtlasSprite)this.mapRegisteredSprites.get(location.toString());

            if (textureatlassprite == null)
            {
                textureatlassprite = new TextureAtlasSprite(location);
                this.mapRegisteredSprites.put(location.toString(), textureatlassprite);
            }

            return textureatlassprite;
        }
    }

//    public void tick()
//    {
//        this.updateAnimations();
//    }

    public TextureAtlasSprite getMissingSprite()
    {
        return this.missingImage;
    }
}
