package client.renderer.blockmodel;

import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import client.renderer.texture.TextureAtlasSprite;
import client.renderer.texture.TextureMap;
import common.block.Block;
import common.block.liquid.BlockLiquid;
import common.collect.Maps;
import common.init.BlockRegistry;
import common.init.Blocks;
import common.init.FluidRegistry;
import common.properties.IProperty;
import common.util.IRegistry;
import common.world.State;

public class ModelManager
{
    private IRegistry<String, IBakedModel> modelRegistry;
    private final TextureMap texMap;
    private final Map<State, IBakedModel> bakedModelStore = Maps.<State, IBakedModel>newIdentityHashMap();
    private final Map<Block, String> liquidMap = Maps.<Block, String>newIdentityHashMap();
	private final Map<Block, StateMap> mappers = Maps.<Block, StateMap>newIdentityHashMap();
	private final Set<Block> builtin = Collections.newSetFromMap(Maps.<Block, Boolean>newIdentityHashMap());
    private IBakedModel defaultModel;

    public ModelManager(TextureMap textures)
    {
        this.texMap = textures;
		for(Block block : BlockRegistry.REGISTRY) {
			if(block.getRenderType() != 3) {
				this.builtin.add(block);
				//		Log.info("Builtin: " + BlockRegistry.getNameFromBlock(block));
			}
			else {
				IProperty<?>[] ignored = block.getIgnoredProperties();
				if(ignored != null)
					this.mappers.put(block, new MultiStateMap.Builder().ignore(ignored).build());
			}
		}
    }

    public void onReload()
    {
        this.modelRegistry = ModelBakery.setupModelRegistry(this.texMap, this.getMap());
        this.defaultModel = this.modelRegistry.getObject(ModelBakery.MISSING);
        this.reloadModels();
    }

    public IBakedModel getModel(String modelLocation)
    {
        if (modelLocation == null)
        {
            return this.defaultModel;
        }
        else
        {
            IBakedModel ibakedmodel = this.modelRegistry.getObject(modelLocation);
            return ibakedmodel == null ? this.defaultModel : ibakedmodel;
        }
    }

    public IBakedModel getMissingModel()
    {
        return this.defaultModel;
    }

    public TextureMap getTextureMap()
    {
        return this.texMap;
    }

    public TextureAtlasSprite getTexture(State state)
    {
        Block block = state.getBlock();
        IBakedModel ibakedmodel = this.getModelForState(state);

        if (ibakedmodel == null || ibakedmodel == this.defaultModel)
        {
            if (block == Blocks.wall_sign || block == Blocks.sign || block == Blocks.chest || block == Blocks.trapped_chest || block == Blocks.banner || block == Blocks.wall_banner)
            {
                return this.texMap.getAtlasSprite("blocks/oak_planks");
            }

            if (block == Blocks.floor_portal)
            {
                return this.texMap.getAtlasSprite("blocks/obsidian");
            }

            if (block == Blocks.flowing_lava || block == Blocks.lava)
            {
                return this.texMap.getAtlasSprite("blocks/lava_still");
            }

            if (block == Blocks.flowing_water || block == Blocks.water)
            {
                return this.texMap.getAtlasSprite("blocks/water_still");
            }

//            if (block == Blocks.barrier)
//            {
//                return this.modelManager.getTextureMap().getAtlasSprite("items/barrier");
//            }

            if (block.getMaterial().isLiquid())
            {
            	String texture = this.liquidMap.get(block);
            	if(texture == null)
            		this.liquidMap.put(block, texture = "blocks/" + BlockRegistry.getNameFromBlock(FluidRegistry.getStaticBlock(FluidRegistry.getFluidMeta((BlockLiquid)block))) + "_still");
                return this.texMap.getAtlasSprite(texture);
            }
        }

        if (ibakedmodel == null)
        {
            ibakedmodel = this.defaultModel;
        }

        return ibakedmodel.getBaseTexture();
    }

    public IBakedModel getModelForState(State state)
    {
        IBakedModel ibakedmodel = (IBakedModel)this.bakedModelStore.get(state);

        if (ibakedmodel == null)
        {
            ibakedmodel = this.defaultModel;
        }

        return ibakedmodel;
    }

    public void reloadModels()
    {
        this.bakedModelStore.clear();

        for (Entry<State, String> entry : this.getMap().entrySet())
        {
            this.bakedModelStore.put(entry.getKey(), this.getModel(entry.getValue()));
        }
    }
    
	public Map<State, String> getMap() {
		Map<State, String> map = Maps.<State, String>newIdentityHashMap();
		for(Block block : BlockRegistry.REGISTRY) {
			if(!this.builtin.contains(block)) {
				StateMap mapper = this.mappers.get(block);
				if(mapper == null)
					mapper = new SingleStateMap();
				map.putAll( // (Objects.firstNonNull(, ))
						mapper.putStateModelLocations(block));
			}
		}
		return map;
	}
}
