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.Set;
import java.util.Map.Entry;

import client.init.RenderRegistry;
import client.renderer.GlState;
import client.renderer.texture.TextureTicked.TextureCreator;
import client.util.FileUtils;
import common.block.Block;
import common.collect.Lists;
import common.collect.Maps;
import common.init.BlockRegistry;
import common.log.Log;
import common.model.TextureAnimation;

public class TextureMap extends Texture
{
    public static final String MISSING = "missingno";
    public static final String BLOCKS = "textures/atlas/blocks.png";
    
    private final List<Sprite> listAnimatedSprites;
    private final Map<String, Sprite> mapRegisteredSprites;
    private final Map<String, Sprite> mapUploadedSprites;
    private final Map<String, TextureCreator> tickedTextures;
    private final Map<String, Integer> animTextures;
    private final Sprite missingImage;

    public TextureMap()
    {
        this.listAnimatedSprites = Lists.<Sprite>newArrayList();
        this.mapRegisteredSprites = Maps.<String, Sprite>newHashMap();
        this.mapUploadedSprites = Maps.<String, Sprite>newHashMap();
        this.tickedTextures = Maps.<String, TextureCreator>newHashMap();
        this.animTextures = Maps.<String, Integer>newHashMap();
        this.missingImage = new Sprite(MISSING);
        Map<String, Object> map = Maps.newHashMap();
        Map<TextureAnimation, TextureCreator> anim = Maps.newHashMap();
        RenderRegistry.registerAnimations(anim);
		for(Block block : BlockRegistry.blocks()) {
			block.getAnimatedTextures(map);
		}
		for(Entry<String, Object> entry : map.entrySet()) {
			if(entry.getValue() instanceof Integer) {
				this.animTextures.put("blocks/" + entry.getKey(), (Integer)entry.getValue());
			}
			else {
				TextureCreator clazz = anim.get((TextureAnimation)entry.getValue());
				if(clazz == null)
					throw new RuntimeException("Animation '" + entry.getValue() + "' existiert nicht");
				this.tickedTextures.put("blocks/" + 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(Set<String> set, Map<String, Sprite> sprites)
    {
        this.mapRegisteredSprites.clear();
        for (String loc : set)
        {
            Sprite sprite = this.registerSprite(loc);
            sprites.put(loc, sprite);
        }
        this.initMissingImage();
        this.deleteGlTexture();
        this.loadTextureAtlas();
    }

    private void loadTextureAtlas()
    {
        Stitcher stitcher = new Stitcher();
        this.mapUploadedSprites.clear();
        this.listAnimatedSprites.clear();
        int j = Integer.MAX_VALUE;

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

            try
            {
            	TextureCreator animationmetadatasection = this.tickedTextures.get(textureatlassprite.getIconName());
                
                if(animationmetadatasection != null) {
                	textureatlassprite.loadSprite(animationmetadatasection);
                }
                else {
	                BufferedImage abufferedimage = 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()));

            stitcher.addSprite(textureatlassprite);
        }

        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, Sprite> map = Maps.<String, Sprite>newHashMap(this.mapRegisteredSprites);

        for (Sprite 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 (Sprite textureatlassprite3 : map.values())
        {
            textureatlassprite3.copyFrom(this.missingImage);
        }
    }

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

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

        return textureatlassprite;
    }

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

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

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

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

            return textureatlassprite;
        }
    }

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