package net.minecraft.src;

import java.util.Random;

import net.minecraft.src.forge.ITextureProvider;



public class PClo_BlockGate extends BlockContainer implements PCco_IRotatedBox, PCco_ISwapTerrain, PCco_INoHarvestBlock, PCco_IRedstoneDevice,
		ITextureProvider {
	public boolean active;
	public static boolean keepInv;

	protected PClo_BlockGate(int id, boolean flag) {
		super(id, Material.circuits);
		active = flag;
		blockIndexInTexture = 6;
		setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F);
	}

	@Override
	public boolean isItem3D() {
		return false;
	}

	@Override
	public TileEntity getBlockEntity() {
		return new PClo_TileEntityGate();
	}

	@Override
	public String getTextureFile() {
		return getTerrainFile();
	}
	
	public PClo_TileEntityGate getTE(IBlockAccess iblockaccess, int x, int y, int z){
		TileEntity te = iblockaccess.getBlockTileEntity(x,y,z);
		if (te == null) {
			return null;
		}
		return (PClo_TileEntityGate) te;
	}

	/**
	 * Get gate type
	 * 
	 * @param iblockaccess world
	 * @param i x
	 * @param j y
	 * @param k z
	 * @return type index
	 */
	public int getType(IBlockAccess iblockaccess, int i, int j, int k) {				
		return getTE(iblockaccess,i,j,k).gateType;
	}

	
	/**
	 * Set gate type
	 * 
	 * @param iblockaccess world
	 * @param i x
	 * @param j y
	 * @param k z
	 * @param type type index
	 */
	public void setType(IBlockAccess iblockaccess, int i, int j, int k, int type) {
		getTE(iblockaccess,i,j,k).gateType = type;
	}

	
	public boolean getOldClock(IBlockAccess iblockaccess, int i, int j, int k) {
		return getTE(iblockaccess,i,j,k).prevClockState;
	}
	

	public void setClock(IBlockAccess iblockaccess, int i, int j, int k, boolean clk) {
		getTE(iblockaccess,i,j,k).prevClockState = clk;
	}

	@Override
	public int getBlockTexture(IBlockAccess iblockaccess, int i, int j, int k, int l) {
		if (l == 1) {
			// top face!
			
			int index = getTE(iblockaccess,i,j,k).gateType;
			
			if(index == PClo_GType.CROSSING){
				int variant = getTE(iblockaccess,i,j,k).getCrossingVariant();
				switch(variant){
					case 0: return 48;
					case 1: return 49;
					case 2: return 50;
					case 3: return 51;
				}
				
				return 48;
			}
			
			return getTopFaceFromEnum(index) + (active ? 16 : 0);
		}

		if (l == 0) return 6;
		return 5;
	}


	@Override
	public int getBlockTextureFromSideAndMetadata(int i, int j) {
		if (i == 0) {
			return 6; // stone slab particles
		}
		if (i == 1) {
			
			if(j == PClo_GType.CROSSING) return 48;
			
			return getTopFaceFromEnum(j) + 16; // top face
		} else {
			return 5; // side
		}
	}

	public int getTopFaceFromEnum(int meta) {
		if (meta <= 15) {
			return 16 + meta;
		} else {
			return 64 + meta;
		}
	}

	@Override
	public boolean shouldSideBeRendered(IBlockAccess iblockaccess, int i, int j, int k, int l) {
		return l != 1;
	}

	@Override
	public boolean renderAsNormalBlock() {
		return false;
	}

	@Override
	public int getRenderType() {
		return mod_PCcore.rotatedBoxRenderer;
	}

	@Override
	public int getRotation(int meta) {
		return getRotation_static(meta);
	}
	
	public static int getRotation_static(int meta) {
		return meta & 3;
	}

	@Override
	public String getTerrainFile() {
		return mod_PClogic.imgDir + "tiles.png";
	}

	@Override
	public int idDropped(int i, Random random, int j) {
		return -1;
	}

	@Override
	public int quantityDropped(Random random) {
		return 0;
	}

	@Override
	public void onBlockRemoval(World world, int i, int j, int k) {
		if (!keepInv) {
			PClo_TileEntityGate teg = getTE(world,i,j,k);
			
			if (teg != null) {
				
				if(teg.gateType == PClo_GType.SPECIAL){
					unpausePausedBlocks(world, i, j, k);
				}
				
				teg.zombie = true;
				
				if (!ModLoader.getMinecraftInstance().playerController.isInCreativeMode()) {					
					dropBlockAsItem_do(world, i, j, k, new ItemStack(mod_PClogic.gateOn, 1, teg.gateType));
				}
			}
		}
		
		
		super.onBlockRemoval(world, i, j, k);
		//System.gc();
	}

	@Override
	public boolean canPlaceBlockAt(World world, int i, int j, int k) {
		if (!world.isBlockNormalCube(i, j - 1, k)) {
			return false;
		} else {
			return super.canPlaceBlockAt(world, i, j, k);
		}
	}

	@Override
	public boolean canBlockStay(World world, int i, int j, int k) {
		if (!world.isBlockNormalCube(i, j - 1, k)) {
			return false;
		} else {
			return super.canBlockStay(world, i, j, k);
		}
	}

	// end of block setup

	// start of logic

	@Override
	public boolean isIndirectlyPoweringTo(World world, int i, int j, int k, int l) {
		return isPoweringTo(world, i, j, k, l);
	}

	public boolean checkEmptyChest(World world, int i, int j, int k) {
		return getTE(world,i,j,k).isChestEmpty();
	}

	public boolean checkFullChest(World world, int i, int j, int k) {
		return getTE(world,i,j,k).isChestFull();
	}

	public boolean isOutputActive(World world, int i, int j, int k) {

		if (getType(world, i, j, k) == PClo_GType.DAY) return world.isDaytime();
		if (getType(world, i, j, k) == PClo_GType.RAIN) return world.isRaining();
		if (getType(world, i, j, k) == PClo_GType.CHEST_EMPTY) return checkEmptyChest(world, i, j, k);
		if (getType(world, i, j, k) == PClo_GType.CHEST_FULL) return checkFullChest(world, i, j, k);

		int meta = world.getBlockMetadata(i, j, k);

		if (getType(world, i, j, k) == PClo_GType.SPECIAL) return powered_from_input(world, i, j, k, meta, 0);
		if (getType(world, i, j, k) == PClo_GType.FIFO_DELAYER) return getTE(world,i,j,k).getBufferOutput();
		
		
		boolean q = getResult(getType(world, i, j, k), powered_from_input(world, i, j, k, meta, 0), powered_from_input(world, i, j, k, meta, 1),
				powered_from_input(world, i, j, k, meta, 2));
		return q;
	}

	@Override
	public void updateTick(World world, int x, int y, int z, Random random) {

		int gateMeta = world.getBlockMetadata(x, y, z);
		
		int type = getType(world, x, y, z);
		boolean on, state;

		switch(type){
			case PClo_GType.CROSSING:
				world.notifyBlockChange(x, y, z, blockID);
				return;
		
		
			case PClo_GType.SPECIAL:	
				on = powered_from_input(world, x, y, z, gateMeta, 0);
				if (!on) unpausePausedBlocks(world, x, y, z);
	
				if (on && !active) {
					// do spawning
					spawnMobsFromSpawners(world, x, y, z);
	
					changeGateState(true, world, x, y, z);
				}else
				if (!on && active) {
					changeGateState(false, world, x, y, z);
				}
				
				break;
				
				
			case PClo_GType.DAY:
				if (world.isDaytime() && !active) {
					changeGateState(true, world, x, y, z);
				}else
				if (!world.isDaytime() && active) {
					changeGateState(false, world, x, y, z);
				}
				break;
				
				
			case PClo_GType.FIFO_DELAYER:
				
				state = getTE(world, x, y, z).getBufferOutput();
				
				if (state && !active) {
					changeGateState(true, world, x, y, z);
				}else
				if (!state && active) {
					changeGateState(false, world, x, y, z);
				}
	
				break;
				
				
			case PClo_GType.HOLD_DELAYER:
				
				boolean inp = powered_from_input(world, x, y, z, gateMeta, 0);
				
				if(inp) getTE(world, x,y,z).repeaterHoldStart();
				
				state = getTE(world, x, y, z).isRepeaterHolding();
				
				if (state && !active) {
					changeGateState(true, world, x, y, z);
				}else
				if (!state && active) {
					changeGateState(false, world, x, y, z);
				}
	
				break;
				
				
			case  PClo_GType.RAIN:
				if (world.isRaining() && !active) {
					changeGateState(true, world, x, y, z);
				}else
				if (!world.isRaining() && active) {
					changeGateState(false, world, x, y, z);
				}
	
				break;
				
				
			case  PClo_GType.CHEST_EMPTY:
				boolean empty = checkEmptyChest(world, x, y, z);
				if (empty && !active) {
					changeGateState(true, world, x, y, z);
				}else
				if (!empty && active) {
					changeGateState(false, world, x, y, z);
				}
	
				break;
				
				
			case PClo_GType.CHEST_FULL:
				boolean full = checkFullChest(world, x, y, z);
				if (full && !active) {
					changeGateState(true, world, x, y, z);
				}else
				if (!full && active) {
					changeGateState(false, world, x, y, z);
				}
	
				break;
				
				
			case PClo_GType.D:
				int CLOCK = 2;
				int DATA = 0;
				int RST = 1;
				// D flip flop
				if (powered_from_input(world, x, y, z, gateMeta, RST)) {
					changeGateState(false, world, x, y, z);
					setClock(world, x, y, z, powered_from_input(world, x, y, z, gateMeta, CLOCK));
				} else if (powered_from_input(world, x, y, z, gateMeta, CLOCK)) { // clock
																			// on
					if (getOldClock(world, x, y, z) == false) {// clock was zero
																// before, thus
																// RISING EDGE
						if (powered_from_input(world, x, y, z, gateMeta, DATA)) {
							// D is on
							setClock(world, x, y, z, true);
							changeGateState(true, world, x, y, z);
						} else {
							// D is off
							setClock(world, x, y, z, true);
							changeGateState(false, world, x, y, z);
						}
					} else {
						// clock was on before, and is still on
						// do nothing
					}
				} else {
					// clock is off
					if (getOldClock(world, x, y, z) == true) {
						// clock was on before - set off
						setClock(world, x, y, z, false);
					}
				}
	
				break;
				
				
			case PClo_GType.RS:
				int R = 2;
				int S = 1;
				on = isActive(world, x, y, z);
				// RS flip flop
				if (!on && powered_from_input(world, x, y, z, gateMeta, S) && !powered_from_input(world, x, y, z, gateMeta, R)) {
					// turn it on
					changeGateState(true, world, x, y, z);
				} else if (on && powered_from_input(world, x, y, z, gateMeta, R) && !powered_from_input(world, x, y, z, gateMeta, S)) {
					changeGateState(false, world, x, y, z);
				}
	
				break;
				
				
			case PClo_GType.T:
				int T = 0;
				if (powered_from_input(world, x, y, z, gateMeta, 1) || powered_from_input(world, x, y, z, gateMeta, 2)) {
					changeGateState(false, world, x, y, z);
					setClock(world, x, y, z, powered_from_input(world, x, y, z, gateMeta, T));
				} else if (powered_from_input(world, x, y, z, gateMeta, T)) { // clock on
					if (getOldClock(world, x, y, z) == false) {// clock was zero
																// before, thus
																// RISING EDGE
						setClock(world, x, y, z, true);
						if (!isActive(world, x, y, z)) {// if off, turn on
							changeGateState(true, world, x, y, z);
						} else {
							changeGateState(false, world, x, y, z);
						}
					}
				} else {
					// clock is off
					if (getOldClock(world, x, y, z) == true) {
						// clock was on before - set off
						setClock(world, x, y, z, false);
					}
				}
				
	
				// BASIC GATES
			default:
				
				on = isActive(world, x, y, z);
	
				boolean outputActive = isOutputActive(world, x, y, z);
	
				if (on && !outputActive) {
					// turn off
					changeGateState(false, world, x, y, z);
				} else if (!on && outputActive) {
					// turn on
					changeGateState(true, world, x, y, z);
				}
		}
	}

	// mob spawning procedure
	private void spawnMobsFromSpawners(World world, int i, int j, int k) {
		TileEntity te = world.getBlockTileEntity(i + 1, j, k);
		if (te != null && te instanceof TileEntityMobSpawner) {
			spawnMobs(world, i, j, k, ((TileEntityMobSpawner) te).getMobID());
		}

		te = world.getBlockTileEntity(i - 1, j, k);
		if (te != null && te instanceof TileEntityMobSpawner) {
			spawnMobs(world, i, j, k, ((TileEntityMobSpawner) te).getMobID());
		}

		te = world.getBlockTileEntity(i, j, k + 1);
		if (te != null && te instanceof TileEntityMobSpawner) {
			spawnMobs(world, i, j, k, ((TileEntityMobSpawner) te).getMobID());
		}

		te = world.getBlockTileEntity(i, j, k - 1);
		if (te != null && te instanceof TileEntityMobSpawner) {
			spawnMobs(world, i, j, k, ((TileEntityMobSpawner) te).getMobID());
		}

		te = world.getBlockTileEntity(i, j + 1, k);
		if (te != null && te instanceof TileEntityMobSpawner) {
			spawnMobs(world, i, j, k, ((TileEntityMobSpawner) te).getMobID());
		}
	}

	private boolean isPlayerInParticleRange(World world, int i, int j, int k) {
		return world.getClosestPlayer(i + 0.5D, j + 0.5D, k + 0.5D, 16D) != null;
	}

	private void spawnMobs(World world, int i, int j, int k, String type) {
		byte count = 5;

		boolean playerInRange = isPlayerInParticleRange(world, i, j, k);

		for (int q = 0; q < count; q++) {
			EntityLiving entityliving = (EntityLiving) EntityList.createEntityByName(type, world);
			if (entityliving == null) {
				return;
			}
			int c = world.getEntitiesWithinAABB(entityliving.getClass(),
					AxisAlignedBB.getBoundingBoxFromPool(i, j, k, i + 1, j + 1, k + 1).expand(8D, 4D, 8D)).size();
			if (c >= 6) {
				if (playerInRange) {
					double d = world.rand.nextGaussian() * 0.02D;
					double d1 = world.rand.nextGaussian() * 0.02D;
					double d2 = world.rand.nextGaussian() * 0.02D;
					world.spawnParticle("smoke", i + 0.5D, j + 0.4D, k + 0.5D, d, d1, d2);
				}
				return;
			}

			double d3 = i + (world.rand.nextDouble() - world.rand.nextDouble()) * 3D;
			double d4 = (j + world.rand.nextInt(3)) - 1;
			double d5 = k + (world.rand.nextDouble() - world.rand.nextDouble()) * 3D;
			entityliving.setLocationAndAngles(d3, d4, d5, world.rand.nextFloat() * 360F, 0.0F);
			if (world.checkIfAABBIsClear(entityliving.boundingBox) && world.getCollidingBoundingBoxes(entityliving, entityliving.boundingBox).size() == 0) {
				world.spawnEntityInWorld(entityliving);
				if (playerInRange) {
					world.playAuxSFX(2004, i, j, k, 0);
					entityliving.spawnExplosionParticle();
				}
				return;
			}
		}
	}

	// end of mob spawning

	@Override
	public void setBlockBoundsBasedOnState(IBlockAccess iblockaccess, int i, int j, int k) {
		setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F);
	}

	@Override
	public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int i, int j, int k) {
		setBlockBoundsBasedOnState(world, i, j, k);
		return super.getCollisionBoundingBoxFromPool(world, i, j, k);
	}

	// change the block while preserving tile entity
	public void changeGateState(boolean flag, World world, int i, int j, int k) {
		int l = world.getBlockMetadata(i, j, k);
		TileEntity tileentity = world.getBlockTileEntity(i, j, k);

		keepInv = true;
		if (flag) {
			world.setBlockWithNotify(i, j, k, mod_PClogic.gateOn.blockID);
		} else {
			world.setBlockWithNotify(i, j, k, mod_PClogic.gateOff.blockID);
		}

		world.setBlockMetadataWithNotify(i, j, k, l);
		keepInv = false;
		if (tileentity != null) {
			tileentity.validate();
			world.setBlockTileEntity(i, j, k, tileentity);
		}
		hugeUpdate(world, i, j, k);
	}

	// check if its not a standard gate
	public boolean isSpecialDevice(int type) {
		return type == PClo_GType.D || type == PClo_GType.RS || type == PClo_GType.T || type == PClo_GType.HOLD_DELAYER;
	}

	// check if it has two outputs
	public boolean hasTwoOutputs(int type) {
		return type == PClo_GType.RS;
	}

	public void unpausePausedBlocks(World world, int i, int j, int k) {
		int type = getType(world, i, j, k);
		if (type == PClo_GType.SPECIAL) {
			TileEntity te = world.getBlockTileEntity(i + 1, j, k);
			if (te != null && te instanceof PClo_TileEntityPulsar) {
				((PClo_TileEntityPulsar) te).paused = false;
			}

			te = world.getBlockTileEntity(i - 1, j, k);
			if (te != null && te instanceof PClo_TileEntityPulsar) {
				((PClo_TileEntityPulsar) te).paused = false;
			}

			te = world.getBlockTileEntity(i, j, k + 1);
			if (te != null && te instanceof PClo_TileEntityPulsar) {
				((PClo_TileEntityPulsar) te).paused = false;
			}

			te = world.getBlockTileEntity(i, j, k - 1);
			if (te != null && te instanceof PClo_TileEntityPulsar) {
				((PClo_TileEntityPulsar) te).paused = false;
			}

			te = world.getBlockTileEntity(i, j + 1, k);
			if (te != null && te instanceof PClo_TileEntityPulsar) {
				((PClo_TileEntityPulsar) te).paused = false;
			}

			te = world.getBlockTileEntity(i, j - 1, k);
			if (te != null && te instanceof PClo_TileEntityPulsar) {
				((PClo_TileEntityPulsar) te).paused = false;
			}
		}
	}

	@Override
	public void onNeighborBlockChange(World world, int x, int y, int z, int l) {
		/*if (!canBlockStay(world, i, j, k)) {
			unpausePausedBlocks(world, i, j, k);
			world.setBlockWithNotify(i, j, k, 0);
			return;
		}*/
		

		int type = getType(world, x, y, z);
		if(type == PClo_GType.FIFO_DELAYER) return;
		
		if(type == PClo_GType.CROSSING){
			world.scheduleBlockUpdate(x, y, z, blockID, 1);
		}
		
		if (type == PClo_GType.DAY || type == PClo_GType.RAIN || type == PClo_GType.CHEST_EMPTY || type == PClo_GType.CHEST_FULL){
			world.scheduleBlockUpdate(x, y, z, blockID, 1);
			return;
		}

		if (isSpecialDevice(getType(world, x, y, z))) {
			world.scheduleBlockUpdate(x, y, z, blockID, 1);
			return;
		}

		boolean outputActive = isOutputActive(world, x, y, z);
		boolean on = isActive(world, x, y, z);

		if (on && !outputActive) {
			world.scheduleBlockUpdate(x, y, z, blockID, 1);
		} else if (!on && outputActive) {
			world.scheduleBlockUpdate(x, y, z, blockID, 1);
		}
	}

	@Override
	public boolean isPoweringTo(IBlockAccess iblockaccess, int x, int y, int z, int side) {
		int meta = iblockaccess.getBlockMetadata(x, y, z);
		int rotation = getRotation(meta);
		
		int type = getType(iblockaccess, x, y, z);
		
		
		if(type == PClo_GType.CROSSING){
			
			World world = ModLoader.getMinecraftInstance().theWorld;
			
			//check for rotation and variant.
			int variant = getTE(iblockaccess,x,y,z).getCrossingVariant();
			
			switch(variant){
				case 0:
					if(side == 3) return powered_from_input(world, x, y, z, meta, 0);
					if(side == 4) return powered_from_input(world, x, y, z, meta, 1);
					break;
					
				case 1:
					if(side == 3) return powered_from_input(world, x, y, z, meta, 0);
					if(side == 5) return powered_from_input(world, x, y, z, meta, 2);
					break;
					
				case 2:
					if(side == 2) return powered_from_input(world, x, y, z, meta, 3);
					if(side == 4) return powered_from_input(world, x, y, z, meta, 1);
					break;
					
				case 3:
					if(side == 2) return powered_from_input(world, x, y, z, meta, 3);
					if(side == 5) return powered_from_input(world, x, y, z, meta, 2);
					break;
					
			}
			
			return false;
		}
		

		boolean on = isActive(iblockaccess, x, y, z);
		if (!on) {
			return false;
		}

		if (type == PClo_GType.SPECIAL) return false;

		if (type == PClo_GType.DAY || type == PClo_GType.RAIN) return true;
		// chest & delayer are oriented.

		if ((rotation == 0 && side == 3) || (rotation == 2 && side == 3 && hasTwoOutputs(getType(iblockaccess, x, y, z)))) {
			return true;
		}
		if ((rotation == 1 && side == 4) || (rotation == 3 && side == 4 && hasTwoOutputs(getType(iblockaccess, x, y, z)))) {
			return true;
		}
		if ((rotation == 2 && side == 2) || (rotation == 0 && side == 2 && hasTwoOutputs(getType(iblockaccess, x, y, z)))) {
			return true;
		}
		return ((rotation == 3 && side == 5) || (rotation == 1 && side == 5 && hasTwoOutputs(getType(iblockaccess, x, y, z))));
	}

	private boolean getResult(int gateType, boolean A, boolean B, boolean C) {
		// A = bottom
		// B = left
		// C = right

		if (gateType == PClo_GType.NOT) return !A;
		if (gateType == PClo_GType.AND) return B & C;
		if (gateType == PClo_GType.NAND) return !(B & C);
		if (gateType == PClo_GType.OR) return B | C;
		if (gateType == PClo_GType.NOR) return !(B | C);
		if (gateType == PClo_GType.XOR) return B != C;
		if (gateType == PClo_GType.XNOR) return B == C;
		if (gateType == PClo_GType.AND3) return A & B & C;
		if (gateType == PClo_GType.NAND3) return !(A & B & C);
		if (gateType == PClo_GType.OR3) return A | B | C;
		if (gateType == PClo_GType.NOR3) return !(A | B | C);
		if (gateType == PClo_GType.XOR3) return (A != B) | (B != C) | (C != A);
		if (gateType == PClo_GType.XNOR3) return (A == B) && (B == C) && (C == A);
		return false;

	}

	public static boolean powered_from_input(World world, int x, int y, int z, int meta, int inp) {
		int rotation = getRotation_static(meta);
		int N0 = 0, N1 = 1, N2 = 2, N3 = 3;
		if (inp == 0) {
			N0 = 0;
			N1 = 1;
			N2 = 2;
			N3 = 3;
		}
		if (inp == 1) {
			N0 = 3;
			N1 = 0;
			N2 = 1;
			N3 = 2;
		} else if (inp == 2) {
			N0 = 1;
			N1 = 2;
			N2 = 3;
			N3 = 0;
		} else if (inp == 3) {
			N0 = 2;
			N1 = 3;
			N2 = 0;
			N3 = 1;
		}

		if (rotation == N0) {
			return (world.isBlockIndirectlyProvidingPowerTo(x, y, z + 1, 3) || world.getBlockId(x, y, z + 1) == Block.redstoneWire.blockID
					&& world.getBlockMetadata(x, y, z + 1) > 0);
		}
		if (rotation == N1) {
			return (world.isBlockIndirectlyProvidingPowerTo(x - 1, y, z, 4) || world.getBlockId(x - 1, y, z) == Block.redstoneWire.blockID
					&& world.getBlockMetadata(x - 1, y, z) > 0);
		}
		if (rotation == N2) {
			return (world.isBlockIndirectlyProvidingPowerTo(x, y, z - 1, 2) || world.getBlockId(x, y, z - 1) == Block.redstoneWire.blockID
					&& world.getBlockMetadata(x, y, z - 1) > 0);
		}
		if (rotation == N3) {
			return (world.isBlockIndirectlyProvidingPowerTo(x + 1, y, z, 5) || world.getBlockId(x + 1, y, z) == Block.redstoneWire.blockID
					&& world.getBlockMetadata(x + 1, y, z) > 0);
		}
		return false;
	}

	@Override
	public boolean canProvidePower() {
		return true;
	}

	@Override
	public void onBlockPlacedBy(World world, int i, int j, int k, EntityLiving entityliving) {
		
		if(getType(world, i, j, k) == PClo_GType.CROSSING){
			world.scheduleBlockUpdate(i, j, k, blockID, 1);
			return;
		}
		
		
		int l = ((MathHelper.floor_double(((entityliving.rotationYaw * 4F) / 360F) + 0.5D) & 3) + 2) % 4;

		boolean reverse = mod_PCcore.conf.isKeyDown("ReverseKey");

		if (reverse) {
			if (l == 0) {
				l = 2;
			} else if (l == 2) {
				l = 0;
			} else if (l == 1) {
				l = 3;
			} else if (l == 3) {
				l = 1;
			}
		}

		world.setBlockMetadataWithNotify(i, j, k, l);
		boolean flag = isOutputActive(world, i, j, k);
		if (flag) {
			world.scheduleBlockUpdate(i, j, k, blockID, 1);
		}
	}

	@Override
	public void onBlockAdded(World world, int i, int j, int k) {
		hugeUpdate(world, i, j, k);
		super.onBlockAdded(world, i, j, k);
	}

	public void hugeUpdate(World world, int i, int j, int k) {
		world.notifyBlocksOfNeighborChange(i, j, k, blockID);
		world.notifyBlocksOfNeighborChange(i + 1, j, k, blockID);
		world.notifyBlocksOfNeighborChange(i - 1, j, k, blockID);
		world.notifyBlocksOfNeighborChange(i, j, k + 1, blockID);
		world.notifyBlocksOfNeighborChange(i, j, k - 1, blockID);
		world.notifyBlocksOfNeighborChange(i, j - 1, k, blockID);
		world.notifyBlocksOfNeighborChange(i, j + 1, k, blockID);
	}

	@Override
	public boolean isOpaqueCube() {
		return false;
	}

	@Override
	public void randomDisplayTick(World world, int i, int j, int k, Random random) {
		if (!active) {
			return;
		}

		if (random.nextInt(3) != 0) {
			return;
		}

		double d = (i + 0.5F) + (random.nextFloat() - 0.5F) * 0.20000000000000001D;
		double d1 = (j + 0.2F) + (random.nextFloat() - 0.5F) * 0.20000000000000001D;
		double d2 = (k + 0.5F) + (random.nextFloat() - 0.5F) * 0.20000000000000001D;

		world.spawnParticle("reddust", d, d1, d2, 0.0D, 0.0D, 0.0D);
	}

	public boolean isActive(IBlockAccess world, int i, int j, int k) {
		return active;
	}
	
	@Override
	public boolean blockActivated(World world, int i, int j, int k, EntityPlayer player) {
		
		ItemStack ihold = player.getCurrentEquippedItem();
		if (ihold != null) {
			if (ihold.getItem() instanceof ItemBlock && ihold.getItem().shiftedIndex != mod_PClogic.gateOn.blockID && ihold.getItem().shiftedIndex != mod_PClogic.gateOff.blockID) {
				if (Block.blocksList[ihold.getItem().shiftedIndex] instanceof PCco_INoHarvestBlock) return false;
			}
		}
		
		if(getType(world, i, j, k) == PClo_GType.CROSSING){
			int side = ((MathHelper.floor_double(((player.rotationYaw * 4F) / 360F) + 0.5D) & 3) + 2) % 4;
			if(side == 0 || side == 2) getTE(world, i, j, k).toggleCrossingZ();
			if(side == 1 || side == 3) getTE(world, i, j, k).toggleCrossingX();
			System.out.println("New variant:"+getTE(world, i, j, k).getCrossingVariant());
		}
			
		if(getType(world, i, j, k) == PClo_GType.FIFO_DELAYER){
			
			ModLoader.openGUI(player, new PClo_GuiDelayer(getTE(world, i, j, k), true));
			return true;
			
		}else if(getType(world, i, j, k) == PClo_GType.HOLD_DELAYER){
	
			ModLoader.openGUI(player, new PClo_GuiDelayer(getTE(world, i, j, k), false));
			return true;
		}
		
		return false;
	}
}
