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.Sprite;
import client.renderer.texture.TextureMap;
import common.block.Block;
import common.block.liquid.BlockDynamicLiquid;
import common.collect.Maps;
import common.init.BlockRegistry;
import common.init.Blocks;
import common.properties.Property;
import common.world.State;

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

    public ModelManager(TextureMap textures)
    {
        this.texMap = textures;
		for(Block block : BlockRegistry.blocks()) {
			if(block == Blocks.air || block.getMaterial().isLiquid()) {
				this.builtin.add(block);
			}
			else {
				Property<?>[] 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.get(ModelBakery.MISSING);
        this.reloadModels();
    }

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

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

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

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

        if ((model == null || model == this.defaultModel) && block.getMaterial().isLiquid())
        {
        	return this.texMap.getAtlasSprite("blocks/" + BlockRegistry.getName(block instanceof BlockDynamicLiquid liquid ? liquid.getStaticBlock() : block) + "_still");
        }

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

        return model.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.blocks()) {
			if(!this.builtin.contains(block)) {
				StateMap mapper = this.mappers.get(block);
				if(mapper == null)
					mapper = new SingleStateMap();
				map.putAll(mapper.putStateModelLocations(block));
			}
		}
		return map;
	}
}
