/*
Copyright 2014 Google Inc. All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/


package dan200.qcraft.shared;

import dan200.QCraft;
import net.minecraft.block.*;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityFallingBlock;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.IIcon;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

public class BlockQBlock extends BlockSand
     implements ITileEntityProvider, IQuantumObservable
{
    public int blockRenderID;
    private static IIcon s_transparentIcon;
    private static IIcon s_swirlIcon;
    private static IIcon s_fuzzIcon;
    private static ItemStack[] s_impostorBlocks;

    public static enum Appearance
    {
        Block,
        Fuzz,
        Swirl
    }

    public static ItemStack[] getImpostorBlockList()
    {
        if( s_impostorBlocks == null )
        {
            s_impostorBlocks = new ItemStack[]{
                    null,
                    new ItemStack( Blocks.stone, 1, 0 ),
                    new ItemStack( Blocks.grass, 1, 0 ),
                    new ItemStack( Blocks.dirt, 1, 0 ),
                    new ItemStack( Blocks.bedrock, 1, 0 ),
                    new ItemStack( Blocks.sand, 1, 0 ),
                    new ItemStack( Blocks.gravel, 1, 0 ),
                    new ItemStack( Blocks.gold_ore, 1, 0 ),
                    new ItemStack( Blocks.iron_ore, 1, 0 ),
                    new ItemStack( Blocks.coal_ore, 1, 0 ),
                    new ItemStack( Blocks.log, 1, 0 ),
                    new ItemStack( Blocks.lapis_ore, 1, 0 ),
                    new ItemStack( Blocks.sandstone, 1, 0 ),
                    new ItemStack( Blocks.diamond_ore, 1, 0 ),
                    new ItemStack( Blocks.redstone_ore, 1, 0 ),
                    new ItemStack( Blocks.emerald_ore, 1, 0 ),
                    new ItemStack( Blocks.ice, 1, 0 ),
                    new ItemStack( Blocks.clay, 1, 0 ),
                    new ItemStack( Blocks.pumpkin, 1, 0 ),
                    new ItemStack( Blocks.melon_block, 1, 0 ),
                    new ItemStack( Blocks.mycelium, 1, 0 ),
                    new ItemStack( Blocks.obsidian, 1, 0 ), // 21
                    new ItemStack( Blocks.cobblestone, 1, 0 ),
                    new ItemStack( Blocks.planks, 1, 0 ),
                    new ItemStack( Blocks.bookshelf, 1, 0 ),
                    new ItemStack( Blocks.mossy_cobblestone, 1, 0 ),
                    new ItemStack( Blocks.netherrack, 1, 0 ),
                    new ItemStack( Blocks.soul_sand, 1, 0 ),
                    new ItemStack( Blocks.glowstone, 1, 0 ),
                    new ItemStack( Blocks.end_stone, 1, 0 ),
                    new ItemStack( Blocks.iron_block, 1, 0 ),
                    new ItemStack( Blocks.gold_block, 1, 0 ), // 31
                    new ItemStack( Blocks.diamond_block, 1, 0 ),
                    new ItemStack( Blocks.lapis_block, 1, 0 ),
                    new ItemStack( Blocks.wool, 1, 0 ),
                    new ItemStack( Blocks.glass, 1, 0 ),
                    new ItemStack( Blocks.wool, 1, 1 ),
                    new ItemStack( Blocks.wool, 1, 2 ),
                    new ItemStack( Blocks.wool, 1, 3 ),
                    new ItemStack( Blocks.wool, 1, 4 ),
                    new ItemStack( Blocks.wool, 1, 5 ),
                    new ItemStack( Blocks.wool, 1, 6 ),
                    new ItemStack( Blocks.wool, 1, 7 ),
                    new ItemStack( Blocks.wool, 1, 8 ),
                    new ItemStack( Blocks.wool, 1, 9 ),
                    new ItemStack( Blocks.wool, 1, 10 ),
                    new ItemStack( Blocks.wool, 1, 11 ),
                    new ItemStack( Blocks.wool, 1, 12 ),
                    new ItemStack( Blocks.wool, 1, 13 ),
                    new ItemStack( Blocks.wool, 1, 14 ),
                    new ItemStack( Blocks.wool, 1, 15 ),
                    new ItemStack( Blocks.log, 1, 1 ),
                    new ItemStack( Blocks.log, 1, 2 ),
                    new ItemStack( Blocks.log, 1, 3 ),
                    new ItemStack( Blocks.planks, 1, 1 ),
                    new ItemStack( Blocks.planks, 1, 2 ),
                    new ItemStack( Blocks.planks, 1, 3 ),
                    new ItemStack( Blocks.sandstone, 1, 1 ),
                    new ItemStack( Blocks.sandstone, 1, 2 ),
                    new ItemStack( Blocks.stonebrick, 1, 0 ),
                    new ItemStack( Blocks.stonebrick, 1, 1 ),
                    new ItemStack( Blocks.stonebrick, 1, 2 ),
                    new ItemStack( Blocks.stonebrick, 1, 3 ),
                    new ItemStack( Blocks.nether_brick, 1, 0 ),
                    new ItemStack( Blocks.brick_block, 1, 0 ),
                    new ItemStack( Blocks.redstone_block, 1, 0 ),
                    new ItemStack( Blocks.quartz_ore, 1, 0 ),
                    new ItemStack( Blocks.quartz_block, 1, 0 ),
                    new ItemStack( Blocks.quartz_block, 1, 1 ),
                    new ItemStack( Blocks.quartz_block, 1, 2 ),

                    // New in 1.6.4!
                    new ItemStack( Blocks.stained_hardened_clay, 1, 0 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 1 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 2 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 3 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 4 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 5 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 6 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 7 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 8 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 9 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 10 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 11 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 12 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 13 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 14 ),
                    new ItemStack( Blocks.stained_hardened_clay, 1, 15 ),
                    new ItemStack( Blocks.hay_block, 1, 0 ),
                    new ItemStack( Blocks.hardened_clay, 1, 0 ),
                    new ItemStack( Blocks.coal_block, 1, 0 ),

                    // New in 1.7.2!
                    new ItemStack( Blocks.log2, 1, 0 ),
                    new ItemStack( Blocks.log2, 1, 1 ),
                    new ItemStack( Blocks.dirt, 1, 2 ), // Podzol
                    new ItemStack( Blocks.planks, 1, 4 ),
                    new ItemStack( Blocks.planks, 1, 5 ),
                    new ItemStack( Blocks.sand, 1, 1 ), // Red sand
                    new ItemStack( Blocks.packed_ice, 1, 0 ),
                    new ItemStack( Blocks.stained_glass, 1, 0 ),
                    new ItemStack( Blocks.stained_glass, 1, 1 ),
                    new ItemStack( Blocks.stained_glass, 1, 2 ),
                    new ItemStack( Blocks.stained_glass, 1, 3 ),
                    new ItemStack( Blocks.stained_glass, 1, 4 ),
                    new ItemStack( Blocks.stained_glass, 1, 5 ),
                    new ItemStack( Blocks.stained_glass, 1, 6 ),
                    new ItemStack( Blocks.stained_glass, 1, 7 ),
                    new ItemStack( Blocks.stained_glass, 1, 8 ),
                    new ItemStack( Blocks.stained_glass, 1, 9 ),
                    new ItemStack( Blocks.stained_glass, 1, 10 ),
                    new ItemStack( Blocks.stained_glass, 1, 11 ),
                    new ItemStack( Blocks.stained_glass, 1, 12 ),
                    new ItemStack( Blocks.stained_glass, 1, 13 ),
                    new ItemStack( Blocks.stained_glass, 1, 14 ),
                    new ItemStack( Blocks.stained_glass, 1, 15 ),
            };
        }
        return s_impostorBlocks;
    }

    public static class SubType
    {
        public static final int Standard = 0;
        public static final int FiftyFifty = 1;
        public static final int Count = 2;
    }

    public BlockQBlock()
    {
        setCreativeTab( QCraft.getCreativeTab() );
        setHardness( 5.0f );
        setResistance( 10.0f );
        setStepSound( Block.soundTypeMetal );
        setBlockName( "qcraft:qblock" );
    }

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

    public int getSubType( IBlockAccess world, int x, int y, int z )
    {
        return world.getBlockMetadata( x, y, z );
    }

    // IQuantumObservable implementation

    @Override
    public boolean isObserved( World world, int x, int y, int z, int side )
    {
        TileEntity entity = world.getTileEntity( x, y, z );
        if( entity != null && entity instanceof TileEntityQBlock )
        {
            TileEntityQBlock qBlock = (TileEntityQBlock) entity;
            if( qBlock.isForceObserved( side ) )
            {
                return true;
            }
        }
        return false;
    }

    @Override
    public void observe( World world, int x, int y, int z, int side )
    {
        TileEntity entity = world.getTileEntity( x, y, z );
        if( entity != null && entity instanceof TileEntityQBlock )
        {
            TileEntityQBlock qBlock = (TileEntityQBlock) entity;
            qBlock.setForceObserved( side, true );
        }
    }

    @Override
    public void reset( World world, int x, int y, int z, int side )
    {
        TileEntity entity = world.getTileEntity( x, y, z );
        if( entity != null && entity instanceof TileEntityQBlock )
        {
            TileEntityQBlock qBlock = (TileEntityQBlock) entity;
            qBlock.setForceObserved( side, false );
        }
    }

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

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

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

    @Override
    public int getRenderType()
    {
        return blockRenderID;
    }

    @Override
    public boolean isNormalCube( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null && !( block instanceof BlockCompressedPowered ) && block != Blocks.ice && block != Blocks.packed_ice && block != Blocks.glass && block != Blocks.stained_glass )
        {
            return true;
        }
        return false;
    }

    @Override
    public int colorMultiplier( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block == Blocks.grass )
        {
            return block.colorMultiplier( world, x, y, z );
        }
        return 0xffffff;
    }

    @Override
    public void addCollisionBoxesToList( World world, int x, int y, int z, AxisAlignedBB bigBox, List list, Entity entity )
    {
        // Determine if solid
        boolean solid = false;
        int type = getImpostorType( world, x, y, z );
        if( type > 0 )
        {
            // Solid blocks are solid to everyone
            solid = true;
        }
        else if( entity instanceof EntityPlayer )
        {
            // Air blocks are solid to people with goggles on
            EntityPlayer player = (EntityPlayer) entity;
            if( QCraft.isPlayerWearingQuantumGoggles( player ) )
            {
                solid = true;
            }
        }

        // Add AABB if so
        if( solid )
        {
            AxisAlignedBB aabb = AxisAlignedBB.getBoundingBox(
                    (double) x, (double) y, (double) z,
                    (double) x + 1.0, (double) y + 1.0, (double) z + 1.0
            );
            if( aabb != null && aabb.intersectsWith( bigBox ) )
            {
                list.add( aabb );
            }
        }
    }

    @Override
    public boolean isReplaceable( IBlockAccess world, int x, int y, int z )
    {
        /*
		Appearance appearance = getAppearance( world, x, y, z );
		int type = getImpostorType( world, x, y, z );
		if( appearance == Appearance.Block && type == 0 )
		{
			return true;
		}
		*/
        return false;
    }

    @Override
    public void setBlockBoundsBasedOnState( IBlockAccess world, int x, int y, int z )
    {
        Appearance appearance = getAppearance( world, x, y, z );
        int type = getImpostorType( world, x, y, z );
        if( appearance != Appearance.Block || type > 0 )
        {
            super.setBlockBounds( 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f );
        }
        else
        {
            super.setBlockBounds( 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f );
        }
    }

    @Override
    public AxisAlignedBB getCollisionBoundingBoxFromPool( World world, int x, int y, int z )
    {
        setBlockBoundsBasedOnState( world, x, y, z );
        return super.getCollisionBoundingBoxFromPool( world, x, y, z );
    }

    @Override
    public AxisAlignedBB getSelectedBoundingBoxFromPool( World world, int x, int y, int z )
    {
        setBlockBoundsBasedOnState( world, x, y, z );
        return super.getSelectedBoundingBoxFromPool( world, x, y, z );
    }

    @Override
    public float getBlockHardness( World world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getBlockHardness( world, x, y, z );
        }
        return 0.0f;
    }

    @Override
    public float getExplosionResistance( Entity entity, World world, int x, int y, int z, double explosionX, double explosionY, double explosionZ )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getExplosionResistance( entity, world, x, y, z, explosionX, explosionY, explosionZ );
        }
        return 0.0f;
    }

    @Override
    public boolean isSideSolid( IBlockAccess world, int x, int y, int z, ForgeDirection side )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return true;
        }
        return false;
    }

    @Override
    public boolean isAir( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return false;
        }
        return true;
    }

    @Override
    public boolean canSustainLeaves( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.canSustainLeaves( world, x, y, z );
        }
        return false;
    }

    @Override
    public boolean canBeReplacedByLeaves( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return false;
        }
        return true;
    }

    @Override
    public boolean isWood( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.isWood( world, x, y, z );
        }
        return true;
    }

    @Override
    public int getFlammability( IBlockAccess world, int x, int y, int z, ForgeDirection face )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getFlammability( world, x, y, z, face );
        }
        return 0;
    }

    @Override
    public boolean isFlammable( IBlockAccess world, int x, int y, int z, ForgeDirection face )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.isFlammable( world, x, y, z, face );
        }
        return false;
    }

    @Override
    public int getFireSpreadSpeed( IBlockAccess world, int x, int y, int z, ForgeDirection face )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getFireSpreadSpeed( world, x, y, z, face );
        }
        return 0;
    }

    @Override
    public boolean isFireSource( World world, int x, int y, int z, ForgeDirection side )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.isFireSource( world, x, y, z, side );
        }
        return false;
    }

    @Override
    public int getLightOpacity( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getLightOpacity( world, x, y, z );
        }
        return 0;
    }

    @Override
    public boolean isBeaconBase( IBlockAccess world, int x, int y, int z, int beaconX, int beaconY, int beaconZ )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.isBeaconBase( world, x, y, z, beaconX, beaconY, beaconZ );
        }
        return false;
    }

    @Override
    public ArrayList<ItemStack> getDrops( World world, int x, int y, int z, int metadata, int fortune )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getDrops( world, x, y, z, getImpostorDamage( world, x, y, z ), fortune );
        }
        return new ArrayList<ItemStack>();
    }

    @Override
    public void dropBlockAsItemWithChance( World world, int i, int j, int k, int l, float f, int unknown )
    {
        // removeBlockByPlayer handles this instead
    }

    @Override
    public boolean removedByPlayer( World world, EntityPlayer player, int x, int y, int z )
    {
        if( world.isRemote )
        {
            return false;
        }

        if( !player.capabilities.isCreativeMode )
        {
            if( EnchantmentHelper.getSilkTouchModifier( player ) )
            {
                // Silk harvest (get qblock back)
                TileEntity entity = world.getTileEntity( x, y, z );
                if( entity != null && entity instanceof TileEntityQBlock )
                {
                    TileEntityQBlock qblock = (TileEntityQBlock) entity;
                    ItemStack item = ItemQBlock.create( qblock.getSubType(), qblock.getTypes(), qblock.getEntanglementFrequency(), 1 );
                    dropBlockAsItem( world, x, y, z, item );
                }
            }
            else
            {
                // Regular harvest (get impostor)
                Block block = getImpostorBlock( world, x, y, z );
                if( block != null )
                {
                    int metadata = getImpostorDamage( world, x, y, z );
                    if( block.canHarvestBlock( player, metadata ) )
                    {
                        int fortune = EnchantmentHelper.getFortuneModifier( player );
                        ArrayList<ItemStack> items = getDrops( world, x, y, z, metadata, fortune );
                        Iterator<ItemStack> it = items.iterator();
                        while( it.hasNext() )
                        {
                            ItemStack item = it.next();
                            dropBlockAsItem( world, x, y, z, item );
                        }
                    }
                }
            }
        }
        return super.removedByPlayer( world, player, x, y, z );
    }

    @Override
    public ItemStack getPickBlock( MovingObjectPosition target, World world, int x, int y, int z )
    {
        TileEntity entity = world.getTileEntity( x, y, z );
        if( entity != null && entity instanceof TileEntityQBlock )
        {
            TileEntityQBlock qblock = (TileEntityQBlock) entity;
            return ItemQBlock.create( qblock.getSubType(), qblock.getTypes(), qblock.getEntanglementFrequency(), 1 );
        }
        return null;
    }

    @Override
    public boolean canHarvestBlock( EntityPlayer player, int metadata )
    {
        return true;
    }

    @Override
    public void harvestBlock( World world, EntityPlayer player, int x, int y, int z, int metadata )
    {
    }

    @Override
    public boolean canSilkHarvest( World world, EntityPlayer player, int x, int y, int z, int metadata )
    {
        return false;
    }

    @Override
    public void onBlockPlacedBy( World world, int x, int y, int z, EntityLivingBase player, ItemStack stack )
    {
        int subType = stack.getItemDamage();
        int metadata = subType;
        world.setBlockMetadataWithNotify( x, y, z, metadata, 3 );
    }

    @Override
    public void updateTick( World world, int x, int y, int z, Random r )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null && block instanceof BlockSand )
        {
            super.updateTick( world, x, y, z, r );
        }
    }

    @Override
    protected void func_149829_a( EntityFallingBlock entityFallingSand ) // onStartFalling
    {
        // Setup NBT for block to place
        World world = entityFallingSand.worldObj;
        int x = (int) ( entityFallingSand.posX - 0.5f );
        int y = (int) ( entityFallingSand.posY - 0.5f );
        int z = (int) ( entityFallingSand.posZ - 0.5f );
        TileEntity entity = world.getTileEntity( x, y, z );
        if( entity != null && entity instanceof TileEntityQBlock )
        {
            NBTTagCompound nbttagcompound = new NBTTagCompound();
            entity.writeToNBT( nbttagcompound );
            entityFallingSand.field_145810_d = nbttagcompound; // data
        }

        // Prevent the falling qBlock from dropping items
        entityFallingSand.field_145813_c = false; // dropItems
    }
    
    @Override
    public void func_149828_a(World world, int x, int y, int z, int p) // onStopFalling
    {        
        TileEntity entity = world.getTileEntity(x, y, z);        
        if (entity != null && entity instanceof TileEntityQBlock) {
            TileEntityQBlock qBlock = (TileEntityQBlock) entity;
            qBlock.hasJustFallen = true;
        }
    }

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

    @Override
    public boolean canConnectRedstone( IBlockAccess world, int x, int y, int z, int side )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null && block instanceof BlockCompressedPowered )
        {
            return true;
        }
        return false;
    }

    @Override
    public int isProvidingWeakPower( IBlockAccess world, int x, int y, int z, int side )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null && block instanceof BlockCompressedPowered )
        {
            return 15;
        }
        return 0;
    }

    @Override
    public int getLightValue( IBlockAccess world, int x, int y, int z )
    {
        Block block = getImpostorBlock( world, x, y, z );
        if( block != null )
        {
            return block.getLightValue();
        }
        return 0;
    }

    public int getColorForType( int side, int type )
    {
        if( type == 2 ) // grass
        {
            return ( side == 1 ) ? Blocks.grass.getRenderColor( 0 ) : 0xffffff;
        }
        return 0xffffff;
    }

    public IIcon getIconForType( int side, int type, Appearance appearance )
    {
        if( appearance == Appearance.Swirl )
        {
            return s_swirlIcon;
        }
        else if( appearance == Appearance.Fuzz )
        {
            return s_fuzzIcon;
        }
        else //if( appearance == Appearance.Block )
        {
            ItemStack[] blockList = getImpostorBlockList();
            if( type >= 0 && type < blockList.length )
            {
                ItemStack item = blockList[ type ];
                if( item != null )
                {
                    Block block = ((ItemBlock)item.getItem()).field_150939_a;
                    int damage = item.getItemDamage();
                    return block.getIcon( side, damage );
                }
            }
            return s_transparentIcon;
        }
    }

    @Override
    public IIcon getIcon( IBlockAccess world, int x, int y, int z, int side )
    {
        int type = getImpostorType( world, x, y, z );
        Appearance appearance = getAppearance( world, x, y, z );
        return getIconForType( side, type, appearance );
    }

    public static boolean s_forceGrass = false;

    @Override
    public IIcon getIcon( int side, int damage )
    {
        if( s_forceGrass )
        {
            return Blocks.grass.getIcon( side, damage );
        }
        else
        {
            return s_swirlIcon;
        }
    }

    @Override
    public void registerBlockIcons( IIconRegister iconRegister )
    {
        s_transparentIcon = iconRegister.registerIcon( "qcraft:transparent" );
        s_swirlIcon = iconRegister.registerIcon( "qcraft:qblock_swirl" );
        s_fuzzIcon = iconRegister.registerIcon( "qcraft:qblock_fuzz" );
    }

    @Override
    public TileEntity createNewTileEntity( World world, int metadata )
    {
        return new TileEntityQBlock();
    }

    @Override
    public TileEntity createTileEntity( World world, int metadata )
    {
        return createNewTileEntity( world, metadata );
    }

    private Appearance getAppearance( IBlockAccess world, int x, int y, int z )
    {
        TileEntity entity = world.getTileEntity( x, y, z );
        if( entity != null && entity instanceof TileEntityQBlock )
        {
            TileEntityQBlock quantum = (TileEntityQBlock) entity;
            return quantum.getAppearance();
        }
        return Appearance.Fuzz;
    }

    private int getImpostorType( IBlockAccess world, int x, int y, int z )
    {
        int type = 0;
        if( y >= 0 )
        {
            TileEntity entity = world.getTileEntity( x, y, z );
            if( entity != null && entity instanceof TileEntityQBlock )
            {
                TileEntityQBlock quantum = (TileEntityQBlock) entity;
                type = quantum.getObservedType();
            }
        }
        return type;
    }

    public Block getImpostorBlock( IBlockAccess world, int x, int y, int z )
    {
        // Return block
        int type = getImpostorType( world, x, y, z );
        ItemStack[] blockList = getImpostorBlockList();
        if( type < blockList.length )
        {
            ItemStack item = blockList[ type ];
            if( item != null )
            {
                return Block.getBlockFromItem( item.getItem() );
            }
        }
        return null;
    }

    private int getImpostorDamage( IBlockAccess world, int x, int y, int z )
    {
        // Return damage
        int type = getImpostorType( world, x, y, z );
        ItemStack[] blockList = getImpostorBlockList();
        if( type < blockList.length )
        {
            ItemStack item = blockList[ type ];
            if( item != null )
            {
                return item.getItemDamage();
            }
        }
        return 0;
    }
}