package common.block.tech;

import java.util.EnumSet;
import java.util.List;
import java.util.Set;

import common.block.Block;
import common.block.Material;
import common.collect.Lists;
import common.collect.Sets;
import common.init.Blocks;
import common.init.Items;
import common.item.Item;
import common.item.block.ItemRedstone;
import common.model.BlockLayer;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.model.ParticleType;
import common.potion.PotionHelper;
import common.properties.Property;
import common.properties.PropertyEnum;
import common.properties.PropertyInteger;
import common.rng.Random;
import common.util.BlockPos;
import common.util.BoundingBox;
import common.util.ExtMath;
import common.util.Facing;
import common.util.Identifyable;
import common.world.IBlockAccess;
import common.world.IWorldAccess;
import common.world.AWorldClient;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockRedstoneWire extends Block
{
	private static final Model redstone_none = ModelProvider.getModelProvider().getModel("redstone_dust_cross")
			.add(5, 0.25f, 5, 11, 0.25f, 11).noShade()
				.u().uv(5, 5, 11, 11).tint().noCull()
			.add(5, 0.25f, 5, 11, 0.25f, 11).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 5, 11, 11).noCull()
	;
	private static final Model redstone_nsew = ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(0, 0, 16, 16).noCull()
	;
	private static final Model redstone_unusueuw = ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(0, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0.25f, 0, 0, 0.25f, 16, 16).noShade()
				.e("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0.25f, 0, 0, 0.25f, 16, 16).noShade()
				.e("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
	;
	private static final Model redstone_unus = ModelProvider.getModelProvider().getModel("redstone_dust_cross")
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
	;
	private static final Model redstone_ueuw = ModelProvider.getModelProvider().getModel("redstone_dust_cross")
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line").uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line_overlay").uv(0, 0, 16, 16).noCull()
			.add(0.25f, 0, 0, 0.25f, 16, 16).noShade()
				.e("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0.25f, 0, 0, 0.25f, 16, 16).noShade()
				.e("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
	;

	private static Model redstone_n(boolean rot) { 
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross")
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot ? ModelRotation.X0_Y90 : ModelRotation.X0_Y0);
	}
	
	private static Model redstone_ne(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u().uv(5, 0, 16, 11).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 11).noCull()
			.rotate(rot);
	}
	
	private static Model redstone_uew(boolean rot) {
		Model model = ModelProvider.getModelProvider().getModel("redstone_dust_cross")
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line").uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line_overlay").uv(0, 0, 16, 16).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull();
		return rot ? model.uvLock().rotate(ModelRotation.X0_Y180) : model;
	}
	private static Model redstone_nue(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u().uv(5, 0, 16, 11).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 11).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(270).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(270).noCull()
			.rotate(rot);
	}
	private static Model redstone_une(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u().uv(5, 0, 16, 11).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 11).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_nse(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.rotate(rot);
	}
	private static Model redstone_uns(boolean lock, ModelRotation rot) {
		Model model = ModelProvider.getModelProvider().getModel("redstone_dust_cross")
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
		return lock ? model.uvLock() : model;
	}
	
	private static Model redstone_nsue(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(270).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(270).noCull()
			.rotate(rot);
	}
	private static Model redstone_unse(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
				.rotate(rot);
	}
	private static Model redstone_nuse(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_unue(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u().uv(5, 0, 16, 11).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 11).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 11).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	
	private static Model redstone_unusue(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_unusew(boolean rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(0, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot ? ModelRotation.X0_Y90 : ModelRotation.X0_Y0);
	}
	private static Model redstone_unusuew(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(0, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_unuse(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_nusue(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 15.75f, 16, 16, 15.75f).noShade()
				.n("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_unsew(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(0, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_unsuew(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(0, 0, 16, 16).tint().noCull()
			.add(0, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(0, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	private static Model redstone_unsue(ModelRotation rot) {
		return ModelProvider.getModelProvider().getModel("redstone_dust_cross").uvLock()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u().uv(5, 0, 16, 16).tint().noCull()
			.add(5, 0.25f, 0, 16, 0.25f, 16).noShade()
				.u("redstone_dust_cross_overlay").uv(5, 0, 16, 16).noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(0, 0, 0.25f, 16, 16, 0.25f).noShade()
				.s("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line").uv(0, 0, 16, 16).rot(90).tint().noCull()
			.add(15.75f, 0, 0, 15.75f, 16, 16).noShade()
				.w("redstone_dust_line_overlay").uv(0, 0, 16, 16).rot(90).noCull()
			.rotate(rot);
	}
	
    public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> NORTH = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("north", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> EAST = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("east", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> SOUTH = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("south", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyEnum<BlockRedstoneWire.EnumAttachPosition> WEST = PropertyEnum.<BlockRedstoneWire.EnumAttachPosition>create("west", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyInteger POWER = PropertyInteger.create("power", 0, 15);
    private boolean canProvidePower = true;
    private final Set<BlockPos> blocksNeedingUpdate = Sets.<BlockPos>newHashSet();

    public BlockRedstoneWire()
    {
        super(Material.SMALL);
        this.setDefaultState(this.getBaseState().withProperty(NORTH, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(EAST, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(SOUTH, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(WEST, BlockRedstoneWire.EnumAttachPosition.NONE).withProperty(POWER, Integer.valueOf(0)));
        this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.0625F, 1.0F);
    }

    /**
     * Get the actual Block state of this Block at the given position. This applies properties not visible in the
     * metadata, such as fence connections.
     */
    public State getActualState(State state, IWorldAccess worldIn, BlockPos pos)
    {
        state = state.withProperty(WEST, this.getAttachPosition(worldIn, pos, Facing.WEST));
        state = state.withProperty(EAST, this.getAttachPosition(worldIn, pos, Facing.EAST));
        state = state.withProperty(NORTH, this.getAttachPosition(worldIn, pos, Facing.NORTH));
        state = state.withProperty(SOUTH, this.getAttachPosition(worldIn, pos, Facing.SOUTH));
        return state;
    }

    private BlockRedstoneWire.EnumAttachPosition getAttachPosition(IBlockAccess worldIn, BlockPos pos, Facing direction)
    {
        BlockPos blockpos = pos.offset(direction);
        Block block = worldIn.getState(pos.offset(direction)).getBlock();

        if (!canConnectTo(worldIn.getState(blockpos), direction) && (block.isBlockNormalCube() || !canConnectUpwardsTo(worldIn.getState(blockpos.down()))))
        {
            Block block1 = worldIn.getState(pos.up()).getBlock();
            return !block1.isBlockNormalCube() && block.isBlockNormalCube() && canConnectUpwardsTo(worldIn.getState(blockpos.up())) ? BlockRedstoneWire.EnumAttachPosition.UP : BlockRedstoneWire.EnumAttachPosition.NONE;
        }
        else
        {
            return BlockRedstoneWire.EnumAttachPosition.SIDE;
        }
    }

    public BoundingBox getCollisionBoundingBox(World worldIn, BlockPos pos, State state)
    {
        return null;
    }

    /**
     * Used to determine ambient occlusion and culling when rebuilding chunks for render
     */
    public boolean isOpaqueCube()
    {
        return false;
    }

    public boolean isFullCube()
    {
        return false;
    }

    public int colorMultiplier(IWorldAccess worldIn, BlockPos pos, int renderPass)
    {
        State iblockstate = worldIn.getState(pos);
        return iblockstate.getBlock() != this ? super.colorMultiplier(worldIn, pos, renderPass) : this.colorMultiplier(((Integer)iblockstate.getValue(POWER)).intValue());
    }

    public boolean canPlaceBlockAt(World worldIn, BlockPos pos)
    {
        return worldIn.isBlockSolid(pos.down()) || worldIn.getState(pos.down()).getBlock() == Blocks.glowstone;
    }

    private State updateSurroundingRedstone(World worldIn, BlockPos pos, State state)
    {
        state = this.calculateCurrentChanges(worldIn, pos, pos, state);
        List<BlockPos> list = Lists.newArrayList(this.blocksNeedingUpdate);
        this.blocksNeedingUpdate.clear();

        for (BlockPos blockpos : list)
        {
            worldIn.notifyNeighborsOfStateChange(blockpos, this);
        }

        return state;
    }

    private State calculateCurrentChanges(World worldIn, BlockPos pos1, BlockPos pos2, State state)
    {
        State iblockstate = state;
        int i = ((Integer)state.getValue(POWER)).intValue();
        int j = 0;
        j = this.getMaxCurrentStrength(worldIn, pos2, j);
        this.canProvidePower = false;
        int k = worldIn.isBlockIndirectlyGettingPowered(pos1);
        this.canProvidePower = true;

        if (k > 0 && k > j - 1)
        {
            j = k;
        }

        int l = 0;

        for (Facing enumfacing : Facing.Plane.HORIZONTAL)
        {
            BlockPos blockpos = pos1.offset(enumfacing);
            boolean flag = blockpos.getX() != pos2.getX() || blockpos.getZ() != pos2.getZ();

            if (flag)
            {
                l = this.getMaxCurrentStrength(worldIn, blockpos, l);
            }

            if (worldIn.getState(blockpos).getBlock().isNormalCube() && !worldIn.getState(pos1.up()).getBlock().isNormalCube())
            {
                if (flag && pos1.getY() >= pos2.getY())
                {
                    l = this.getMaxCurrentStrength(worldIn, blockpos.up(), l);
                }
            }
            else if (!worldIn.getState(blockpos).getBlock().isNormalCube() && flag && pos1.getY() <= pos2.getY())
            {
                l = this.getMaxCurrentStrength(worldIn, blockpos.down(), l);
            }
        }

        if (l > j)
        {
            j = l - 1;
        }
        else if (j > 0)
        {
            --j;
        }
        else
        {
            j = 0;
        }

        if (k > j - 1)
        {
            j = k;
        }

        if (i != j)
        {
            state = state.withProperty(POWER, Integer.valueOf(j));

            if (worldIn.getState(pos1) == iblockstate)
            {
                worldIn.setState(pos1, state, 2);
            }

            this.blocksNeedingUpdate.add(pos1);

            for (Facing enumfacing1 : Facing.values())
            {
                this.blocksNeedingUpdate.add(pos1.offset(enumfacing1));
            }
        }

        return state;
    }

    /**
     * Calls World.notifyNeighborsOfStateChange() for all neighboring blocks, but only if the given block is a redstone
     * wire.
     */
    private void notifyWireNeighborsOfStateChange(World worldIn, BlockPos pos)
    {
        if (worldIn.getState(pos).getBlock() == this)
        {
            worldIn.notifyNeighborsOfStateChange(pos, this);

            for (Facing enumfacing : Facing.values())
            {
                worldIn.notifyNeighborsOfStateChange(pos.offset(enumfacing), this);
            }
        }
    }

    public void onBlockAdded(AWorldServer worldIn, BlockPos pos, State state)
    {
        if (!worldIn.client)
        {
            this.updateSurroundingRedstone(worldIn, pos, state);

            for (Facing enumfacing : Facing.Plane.VERTICAL)
            {
                worldIn.notifyNeighborsOfStateChange(pos.offset(enumfacing), this);
            }

            for (Facing enumfacing1 : Facing.Plane.HORIZONTAL)
            {
                this.notifyWireNeighborsOfStateChange(worldIn, pos.offset(enumfacing1));
            }

            for (Facing enumfacing2 : Facing.Plane.HORIZONTAL)
            {
                BlockPos blockpos = pos.offset(enumfacing2);

                if (worldIn.getState(blockpos).getBlock().isNormalCube())
                {
                    this.notifyWireNeighborsOfStateChange(worldIn, blockpos.up());
                }
                else
                {
                    this.notifyWireNeighborsOfStateChange(worldIn, blockpos.down());
                }
            }
        }
    }

    public void onBlockRemoved(AWorldServer worldIn, BlockPos pos, State state)
    {
        super.onBlockRemoved(worldIn, pos, state);

        if (!worldIn.client)
        {
            for (Facing enumfacing : Facing.values())
            {
                worldIn.notifyNeighborsOfStateChange(pos.offset(enumfacing), this);
            }

            this.updateSurroundingRedstone(worldIn, pos, state);

            for (Facing enumfacing1 : Facing.Plane.HORIZONTAL)
            {
                this.notifyWireNeighborsOfStateChange(worldIn, pos.offset(enumfacing1));
            }

            for (Facing enumfacing2 : Facing.Plane.HORIZONTAL)
            {
                BlockPos blockpos = pos.offset(enumfacing2);

                if (worldIn.getState(blockpos).getBlock().isNormalCube())
                {
                    this.notifyWireNeighborsOfStateChange(worldIn, blockpos.up());
                }
                else
                {
                    this.notifyWireNeighborsOfStateChange(worldIn, blockpos.down());
                }
            }
        }
    }

    private int getMaxCurrentStrength(World worldIn, BlockPos pos, int strength)
    {
        if (worldIn.getState(pos).getBlock() != this)
        {
            return strength;
        }
        else
        {
            int i = ((Integer)worldIn.getState(pos).getValue(POWER)).intValue();
            return i > strength ? i : strength;
        }
    }

    /**
     * Called when a neighboring block changes.
     */
    public void onNeighborBlockChange(World worldIn, BlockPos pos, State state, Block neighborBlock)
    {
        if (!worldIn.client)
        {
            if (this.canPlaceBlockAt(worldIn, pos))
            {
                this.updateSurroundingRedstone(worldIn, pos, state);
            }
            else
            {
                this.dropBlockAsItem(worldIn, pos, state, 0);
                worldIn.setBlockToAir(pos);
            }
        }
    }

    /**
     * Get the Item that this Block should drop when harvested.
     */
    public Item getItemDropped(State state, Random rand, int fortune)
    {
        return Items.redstone;
    }

    public int getStrongPower(IWorldAccess worldIn, BlockPos pos, State state, Facing side)
    {
        return !this.canProvidePower ? 0 : this.getWeakPower(worldIn, pos, state, side);
    }

    public int getWeakPower(IWorldAccess worldIn, BlockPos pos, State state, Facing side)
    {
        if (!this.canProvidePower)
        {
            return 0;
        }
        else
        {
            int i = ((Integer)state.getValue(POWER)).intValue();

            if (i == 0)
            {
                return 0;
            }
            else if (side == Facing.UP)
            {
                return i;
            }
            else
            {
                EnumSet<Facing> enumset = EnumSet.<Facing>noneOf(Facing.class);

                for (Facing enumfacing : Facing.Plane.HORIZONTAL)
                {
                    if (this.isConnectedTo(worldIn, pos, enumfacing))
                    {
                        enumset.add(enumfacing);
                    }
                }

                if (side.getAxis().isHorizontal() && enumset.isEmpty())
                {
                    return i;
                }
                else if (enumset.contains(side) && !enumset.contains(side.rotateYCCW()) && !enumset.contains(side.rotateY()))
                {
                    return i;
                }
                else
                {
                    return 0;
                }
            }
        }
    }

    private boolean isConnectedTo(IBlockAccess worldIn, BlockPos pos, Facing side)
    {
        BlockPos blockpos = pos.offset(side);
        State iblockstate = worldIn.getState(blockpos);
        Block block = iblockstate.getBlock();
        boolean flag = block.isNormalCube();
        boolean flag1 = worldIn.getState(pos.up()).getBlock().isNormalCube();
        return !flag1 && flag && canConnectUpwardsTo(worldIn, blockpos.up()) ? true : (canConnectTo(iblockstate, side) ? true : (block == Blocks.powered_repeater && iblockstate.getValue(BlockRedstoneDiode.FACING) == side ? true : !flag && canConnectUpwardsTo(worldIn, blockpos.down())));
    }

    protected static boolean canConnectUpwardsTo(IBlockAccess worldIn, BlockPos pos)
    {
        return canConnectUpwardsTo(worldIn.getState(pos));
    }

    protected static boolean canConnectUpwardsTo(State state)
    {
        return canConnectTo(state, (Facing)null);
    }

    protected static boolean canConnectTo(State blockState, Facing side)
    {
        Block block = blockState.getBlock();

        if (block == Blocks.redstone)
        {
            return true;
        }
        else if (Blocks.repeater.isAssociated(block))
        {
            Facing enumfacing = (Facing)blockState.getValue(BlockRedstoneRepeater.FACING);
            return enumfacing == side || enumfacing.getOpposite() == side;
        }
        else
        {
            return block.canProvidePower() && side != null;
        }
    }

    /**
     * Can this block provide power. Only wire currently seems to have this change based on its state.
     */
    public boolean canProvidePower()
    {
        return this.canProvidePower;
    }

    private int colorMultiplier(int powerLevel)
    {
        float f = (float)powerLevel / 15.0F;
        float f1 = f * 0.6F + 0.4F;

        if (powerLevel == 0)
        {
            f1 = 0.3F;
        }

        float f2 = f * f * 0.7F - 0.5F;
        float f3 = f * f * 0.6F - 0.7F;

        if (f2 < 0.0F)
        {
            f2 = 0.0F;
        }

        if (f3 < 0.0F)
        {
            f3 = 0.0F;
        }

        int i = ExtMath.clampi((int)(f1 * 255.0F), 0, 255);
        int j = ExtMath.clampi((int)(f2 * 255.0F), 0, 255);
        int k = ExtMath.clampi((int)(f3 * 255.0F), 0, 255);
        return -16777216 | i << 16 | j << 8 | k;
    }

    public void randomDisplayTick(AWorldClient worldIn, BlockPos pos, State state, Random rand)
    {
        int i = ((Integer)state.getValue(POWER)).intValue();

        if (i != 0)
        {
            double d0 = (double)pos.getX() + 0.5D + ((double)rand.floatv() - 0.5D) * 0.2D;
            double d1 = (double)((float)pos.getY() + 0.0625F);
            double d2 = (double)pos.getZ() + 0.5D + ((double)rand.floatv() - 0.5D) * 0.2D;
            float f = (float)i / 15.0F;
            float f1 = f * 0.6F + 0.4F;
            float f2 = Math.max(0.0F, f * f * 0.7F - 0.5F);
            float f3 = Math.max(0.0F, f * f * 0.6F - 0.7F);
            worldIn.spawnParticle(ParticleType.REDSTONE, d0, d1, d2, (double)f1, (double)f2, (double)f3);
        }
    }

    public Item getItem(World worldIn, BlockPos pos)
    {
        return Items.redstone;
    }

    public BlockLayer getBlockLayer()
    {
        return BlockLayer.CUTOUT;
    }

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(POWER, Integer.valueOf(meta));
    }

    /**
     * Convert the BlockState into the correct metadata value
     */
    public int getMetaFromState(State state)
    {
        return ((Integer)state.getValue(POWER)).intValue();
    }

    protected Property[] getProperties()
    {
        return new Property[] {NORTH, EAST, SOUTH, WEST, POWER};
    }
    
    public boolean isMagnetic() {
    	return true;
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	boolean na = state.getValue(NORTH) == EnumAttachPosition.NONE;
    	boolean sa = state.getValue(SOUTH) == EnumAttachPosition.NONE;
    	boolean wa = state.getValue(WEST) == EnumAttachPosition.NONE;
    	boolean ea = state.getValue(EAST) == EnumAttachPosition.NONE;
    	boolean nu = state.getValue(NORTH) == EnumAttachPosition.UP;
    	boolean su = state.getValue(SOUTH) == EnumAttachPosition.UP;
    	boolean wu = state.getValue(WEST) == EnumAttachPosition.UP;
    	boolean eu = state.getValue(EAST) == EnumAttachPosition.UP;
    	boolean nr = state.getValue(NORTH) == EnumAttachPosition.SIDE;
    	boolean sr = state.getValue(SOUTH) == EnumAttachPosition.SIDE;
    	boolean wr = state.getValue(WEST) == EnumAttachPosition.SIDE;
    	boolean er = state.getValue(EAST) == EnumAttachPosition.SIDE;
    	
    	if(ea && na && sa && wa)
    		return redstone_none;
    	else if(eu && nu && su && wu)
    		return redstone_unusueuw;
    	else if(er && nr && sr && wr)
    		return redstone_nsew;
    	else if(ea && nu && su && wa)
    		return redstone_unus;
    	else if(eu && na && sa && wu)
    		return redstone_ueuw;

        else if(ea && nr && sa && wa)
			return redstone_n(false);
        else if(ea && na && sr && wa)
			return redstone_n(false);
        else if(er && na && sa && wa)
			return redstone_n(true);
        else if(ea && na && sa && wr)
			return redstone_n(true);

        else if(ea && nu && sa && wa)
			return redstone_uns(false, ModelRotation.X0_Y0);
        else if(ea && na && su && wa)
			return redstone_uns(true, ModelRotation.X0_Y180);
        else if(eu && na && sa && wa)
			return redstone_uew(false);
        else if(ea && na && sa && wu)
			return redstone_uew(true);

        else if(er && nr && sa && wa)  
			return redstone_ne(ModelRotation.X0_Y0);
        else if(er && nu && sa && wa) 
			return redstone_une(ModelRotation.X0_Y0);
        else if(eu && nr && sa && wa) 
			return redstone_nue(ModelRotation.X0_Y0);
        else if(eu && nu && sa && wa)
			return redstone_unue(ModelRotation.X0_Y0);

        else if(er && na && sr && wa)  
			return redstone_ne(ModelRotation.X0_Y90);
        else if(eu && na && sr && wa) 
			return redstone_une(ModelRotation.X0_Y90);
        else if(er && na && su && wa) 
			return redstone_nue(ModelRotation.X0_Y90);
        else if(eu && na && su && wa)
			return redstone_unue(ModelRotation.X0_Y90);

        else if(ea && na && sr && wr)  
			return redstone_ne(ModelRotation.X0_Y180);
        else if(ea && na && su && wr) 
			return redstone_une(ModelRotation.X0_Y180);
        else if(ea && na && sr && wu) 
			return redstone_nue(ModelRotation.X0_Y180);
        else if(ea && na && su && wu)
			return redstone_unue(ModelRotation.X0_Y180);

        else if(ea && nr && sa && wr)  
			return redstone_ne(ModelRotation.X0_Y270);
        else if(ea && nr && sa && wu) 
			return redstone_une(ModelRotation.X0_Y270);
        else if(ea && nu && sa && wr) 
			return redstone_nue(ModelRotation.X0_Y270);
        else if(ea && nu && sa && wu)
			return redstone_unue(ModelRotation.X0_Y270);

        else if(ea && nr && sr && wa) 
			return redstone_n(false);
        else if(ea && nu && sr && wa)
			return redstone_uns(false, ModelRotation.X0_Y0);
        else if(ea && nr && su && wa)
			return redstone_uns(false, ModelRotation.X0_Y180);

        else if(er && na && sa && wr) 
			return redstone_n(true);
        else if(eu && na && sa && wr)
			return redstone_uns(false, ModelRotation.X0_Y90);
        else if(er && na && sa && wu)
			return redstone_uns(false, ModelRotation.X0_Y270);

        else if(er && nr && sr && wa)   
			return redstone_nse(ModelRotation.X0_Y0);
        else if(er && nu && sr && wa)  
			return redstone_unse(ModelRotation.X0_Y0);
        else if(er && nr && su && wa)  
			return redstone_nuse(ModelRotation.X0_Y0);
        else if(eu && nr && sr && wa)  
			return redstone_nsue(ModelRotation.X0_Y0);
        else if(eu && nr && su && wa) 
			return redstone_nusue(ModelRotation.X0_Y0);
        else if(er && nu && su && wa) 
			return redstone_unuse(ModelRotation.X0_Y0);
        else if(eu && nu && sr && wa) 
			return redstone_unsue(ModelRotation.X0_Y0);
        else if(eu && nu && su && wa)
			return redstone_unusue(ModelRotation.X0_Y0);

        else if(er && na && sr && wr)   
			return redstone_nse(ModelRotation.X0_Y90);
        else if(eu && na && sr && wr)  
			return redstone_unse(ModelRotation.X0_Y90);
        else if(er && na && sr && wu)  
			return redstone_nuse(ModelRotation.X0_Y90);
        else if(er && na && su && wr)  
			return redstone_nsue(ModelRotation.X0_Y90);
        else if(er && na && su && wu) 
			return redstone_nusue(ModelRotation.X0_Y90);
        else if(eu && na && sr && wu) 
			return redstone_unuse(ModelRotation.X0_Y90);
        else if(eu && na && su && wr) 
			return redstone_unsue(ModelRotation.X0_Y90);
        else if(eu && na && su && wu)
			return redstone_unusue(ModelRotation.X0_Y90);

        else if(ea && nr && sr && wr)   
			return redstone_nse(ModelRotation.X0_Y180);
        else if(ea && nr && su && wr)  
			return redstone_unse(ModelRotation.X0_Y180);
        else if(ea && nu && sr && wr)  
			return redstone_nuse(ModelRotation.X0_Y180);
        else if(ea && nr && sr && wu)  
			return redstone_nsue(ModelRotation.X0_Y180);
        else if(ea && nu && sr && wu) 
			return redstone_nusue(ModelRotation.X0_Y180);
        else if(ea && nu && su && wr) 
			return redstone_unuse(ModelRotation.X0_Y180);
        else if(ea && nr && su && wu) 
			return redstone_unsue(ModelRotation.X0_Y180);
        else if(ea && nu && su && wu)
			return redstone_unusue(ModelRotation.X0_Y180);

        else if(er && nr && sa && wr)   
			return redstone_nse(ModelRotation.X0_Y270);
        else if(er && nr && sa && wu)  
			return redstone_unse(ModelRotation.X0_Y270);
        else if(eu && nr && sa && wr)  
			return redstone_nuse(ModelRotation.X0_Y270);
        else if(er && nu && sa && wr)  
			return redstone_nsue(ModelRotation.X0_Y270);
        else if(eu && nu && sa && wr) 
			return redstone_nusue(ModelRotation.X0_Y270);
        else if(eu && nr && sa && wu) 
			return redstone_unuse(ModelRotation.X0_Y270);
        else if(er && nu && sa && wu) 
			return redstone_unsue(ModelRotation.X0_Y270);
        else if(eu && nu && sa && wu)
			return redstone_unusue(ModelRotation.X0_Y270);

        else if(er && nu && sr && wr)
			return redstone_unsew(ModelRotation.X0_Y0);
        else if(er && nr && su && wr)
			return redstone_unsew(ModelRotation.X0_Y180);
        else if(eu && nr && sr && wr)
			return redstone_unsew(ModelRotation.X0_Y90);
        else if(er && nr && sr && wu)
			return redstone_unsew(ModelRotation.X0_Y270);

        else if(er && nu && su && wr)
			return redstone_unusew(false);
        else if(eu && nr && sr && wu)
			return redstone_unusew(true);

        else if(eu && nu && sr && wr)
			return redstone_unsuew(ModelRotation.X0_Y0);
        else if(eu && nr && su && wr)
			return redstone_unsuew(ModelRotation.X0_Y90);
        else if(er && nr && su && wu)
			return redstone_unsuew(ModelRotation.X0_Y180);
        else if(er && nu && sr && wu)
			return redstone_unsuew(ModelRotation.X0_Y270);

        else if(eu && nu && su && wr)
			return redstone_unusuew(ModelRotation.X0_Y0);
        else if(eu && nr && su && wu)
			return redstone_unusuew(ModelRotation.X0_Y90);
        else if(er && nu && su && wu)
			return redstone_unusuew(ModelRotation.X0_Y180);
        else if(eu && nu && sr && wu)
			return redstone_unusuew(ModelRotation.X0_Y270);
    	
        else
    		return redstone_none;
    }

    public Property<?>[] getIgnoredProperties() {
    	return new Property[] {POWER};
    }
	
	protected Item getItemToRegister() {
		return new ItemRedstone(Blocks.redstone).setDisplay("Redstone").setPotionEffect(PotionHelper.redstoneEffect).setMaxAmount(256);
	}

    static enum EnumAttachPosition implements Identifyable
    {
        UP("up"),
        SIDE("side"),
        NONE("none");

        private final String name;

        private EnumAttachPosition(String name)
        {
            this.name = name;
        }

        public String toString()
        {
            return this.getName();
        }

        public String getName()
        {
            return this.name;
        }
    }
}
