package client.renderer.blockmodel;

import java.util.List;

import client.renderer.texture.TextureMap;
import common.collect.Lists;
import common.collect.Maps;
import common.model.Model;
import common.model.ModelRotation;
import common.model.GuiPosition;
import common.util.Facing;
import common.util.Vector3f;

public class ModelBlock extends Model {
	private final List<BlockPart> elements;
    private final boolean gui3d;
    private final String primary;
    private final String[] layers;
    private final ModelBlock parent;
    
	private ModelRotation rotation;
	private boolean uvLock;
    private GuiPosition transform;
    
    private BlockPart lastPart;
    private BlockPartFace[] last;
    
    public ModelBlock uvLock() {
    	this.uvLock = true;
    	return this;
    }
    
    public ModelBlock rotate(ModelRotation rot) {
    	this.rotation = rot;
    	return this;
    }
    
    public ModelBlock add(float x1, float y1, float z1, float x2, float y2, float z2) {
    	this.elements.add(this.lastPart = new BlockPart(new Vector3f(x1, y1, z1), new Vector3f(x2, y2, z2), 
    			Maps.newEnumMap(Facing.class), null, true));
    	return this;
    }
    
    public ModelBlock noShade() {
    	this.lastPart.shade = false;
    	return this;
    }
    
    public ModelBlock rotate(float x, float y, float z, Facing.Axis axisIn, float angleIn, boolean rescaleIn) {
    	this.lastPart.partRotation = new BlockPartRotation(x, y, z, axisIn, angleIn, rescaleIn);
    	return this;
    }
    
    public ModelBlock face(String texture, Facing ... faces) {
    	texture = !texture.equals(TextureMap.MISSING) && texture.indexOf('/') == -1 ? "blocks/" + texture : texture;
    	this.last = new BlockPartFace[faces.length];
    	for(int z = 0; z < faces.length; z++) {
	    	this.lastPart.mapFaces.put(faces[z], this.last[z] = 
	    			new BlockPartFace(faces[z], -1, texture, new BlockFaceUV(this.lastPart.getFaceUvs(faces[z]), 0)));
    	}
    	return this;
    }
    
    public ModelBlock cull(Facing cull) {
    	for(BlockPartFace last : this.last) {
    		last.cull = cull;
    	}
    	return this;
    }
    
    public ModelBlock rot(int rot) {
    	for(BlockPartFace last : this.last) {
        	last.uv = new BlockFaceUV(last.uv.uvs, rot);
    	}
    	return this;
    }
    
    public ModelBlock uv(float x1, float y1, float x2, float y2) {
    	for(BlockPartFace last : this.last) {
        	last.uv = new BlockFaceUV(new float[] {x1, y1, x2, y2}, last.uv.rotation);
    	}
    	return this;
    }

	public String getPrimary() {
		return this.primary;
	}
    
    
    public ModelBlock(String primary) {
    	this(null, Lists.newArrayList(), primary != null && primary.indexOf('/') == -1 ? "blocks/" + primary : primary, true, true, GuiPosition.NORMAL, null);
    }
    
    public ModelBlock(GuiPosition transform, String ... layers) {
    	this(ModelBakery.MODEL_GENERATED, ModelBakery.MODEL_GENERATED.elements, 
    			layers[0].indexOf('/') == -1 ? "items/" + layers[0] : layers[0], false, false, transform, layers);
    }

    public ModelBlock(ModelBlock parent, GuiPosition transform) {
        this(parent, Lists.newArrayList(), parent.getPrimary(), false, true, transform, null);
    }

    public ModelBlock(String primary, GuiPosition transform, String ... layers) {
    	this(ModelBakery.MODEL_GENERATED, ModelBakery.MODEL_GENERATED.elements, 
    			primary.indexOf('/') == -1 ? "items/" + primary : primary, false, false, transform, layers);
    }
    
    public ModelBlock(String primary, List<BlockPart> elements, GuiPosition transform, String ... layers) {
    	this(null, elements, primary, false, false, transform, layers);
    }

	private ModelBlock(ModelBlock parent, List<BlockPart> elements, String primary, boolean occlude, boolean gui3d, 
			GuiPosition transform, String[] layers) {
		for(int z = 0; layers != null && z < layers.length; z++) {
			layers[z] = layers[z].indexOf('/') == -1 ? "items/" + layers[z] : layers[z];
		}
		this.elements = parent == null ? elements : parent.getElements();
		this.gui3d = gui3d;
		this.primary = primary == null ? TextureMap.MISSING : primary;
		this.parent = parent;
		this.transform = transform;
		this.uvLock = parent != null && parent.isUvLocked();
		this.rotation = parent != null ? parent.getRotation() : ModelRotation.X0_Y0;
		this.layers = layers;
	}

	public List<BlockPart> getElements() {
		return this.elements;
	}

	public boolean isGui3d() {
		return this.gui3d;
	}

	public String[] getTextures() {
		return this.layers;
	}

	public int getNumTextures() {
		return this.layers == null ? 0 : this.layers.length;
	}

	public String getTexture(int layer) {
		return this.layers == null || this.layers[layer] == null ? TextureMap.MISSING : this.layers[layer];
	}

	public ModelBlock getParent() {
		return this.parent;
	}

	public GuiPosition getTransform() {
		return this.transform;
	}

	public ModelRotation getRotation() {
		return this.rotation;
	}

	public boolean isUvLocked() {
		return this.uvLock;
	}
}
