package net.minecraft.block;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.properties.PropertyEnum;
import net.minecraft.block.properties.PropertyInteger;
import net.minecraft.block.state.BlockState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.EnumWorldBlockLayer;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class BlockRedstoneWire extends Block
{
    public static final PropertyEnum NORTH = PropertyEnum.create("north", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyEnum EAST = PropertyEnum.create("east", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyEnum SOUTH = PropertyEnum.create("south", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyEnum WEST = PropertyEnum.create("west", BlockRedstoneWire.EnumAttachPosition.class);
    public static final PropertyInteger POWER = PropertyInteger.create("power", 0, 15);
    private boolean canProvidePower = true;
    private final Set field_150179_b = Sets.newHashSet();
    private static final String __OBFID = "CL_00000295";

    public BlockRedstoneWire()
    {
        super(Material.circuits);
        this.setDefaultState(this.blockState.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 IBlockState getActualState(IBlockState state, IBlockAccess worldIn, BlockPos pos)
    {
        state = state.withProperty(WEST, this.getAttachPosition(worldIn, pos, EnumFacing.WEST));
        state = state.withProperty(EAST, this.getAttachPosition(worldIn, pos, EnumFacing.EAST));
        state = state.withProperty(NORTH, this.getAttachPosition(worldIn, pos, EnumFacing.NORTH));
        state = state.withProperty(SOUTH, this.getAttachPosition(worldIn, pos, EnumFacing.SOUTH));
        return state;
    }

    private BlockRedstoneWire.EnumAttachPosition getAttachPosition(IBlockAccess p_176341_1_, BlockPos p_176341_2_, EnumFacing p_176341_3_)
    {
        BlockPos blockpos1 = p_176341_2_.offset(p_176341_3_);
        Block block = p_176341_1_.getBlockState(p_176341_2_.offset(p_176341_3_)).getBlock();

        if (!canRestoneConnect(p_176341_1_, blockpos1, p_176341_3_) && (block.isSolidFullCube() || !canRestoneConnect(p_176341_1_, blockpos1.offsetDown(), null)))
        {
            Block block1 = p_176341_1_.getBlockState(p_176341_2_.offsetUp()).getBlock();
            return !block1.isSolidFullCube() && block.isSolidFullCube() && canRestoneConnect(p_176341_1_, blockpos1.offsetUp(), null) ? BlockRedstoneWire.EnumAttachPosition.UP : BlockRedstoneWire.EnumAttachPosition.NONE;
        }
        else
        {
            return BlockRedstoneWire.EnumAttachPosition.SIDE;
        }
    }

    public AxisAlignedBB getCollisionBoundingBox(World worldIn, BlockPos pos, IBlockState state)
    {
        return null;
    }

    public boolean isOpaqueCube()
    {
        return false;
    }

    public boolean isFullCube()
    {
        return false;
    }

    @SideOnly(Side.CLIENT)
    public int colorMultiplier(IBlockAccess worldIn, BlockPos pos, int renderPass)
    {
        IBlockState iblockstate = worldIn.getBlockState(pos);
        return iblockstate.getBlock() != this ? super.colorMultiplier(worldIn, pos, renderPass) : this.func_176337_b(((Integer)iblockstate.getValue(POWER)).intValue());
    }

    public boolean canPlaceBlockAt(World worldIn, BlockPos pos)
    {
        return World.doesBlockHaveSolidTopSurface(worldIn, pos.offsetDown()) || worldIn.getBlockState(pos.offsetDown()).getBlock() == Blocks.glowstone;
    }

    private IBlockState updateSurroundingRedstone(World worldIn, BlockPos p_176338_2_, IBlockState p_176338_3_)
    {
        p_176338_3_ = this.func_176345_a(worldIn, p_176338_2_, p_176338_2_, p_176338_3_);
        ArrayList arraylist = Lists.newArrayList(this.field_150179_b);
        this.field_150179_b.clear();
        Iterator iterator = arraylist.iterator();

        while (iterator.hasNext())
        {
            BlockPos blockpos1 = (BlockPos)iterator.next();
            worldIn.notifyNeighborsOfStateChange(blockpos1, this);
        }

        return p_176338_3_;
    }

    private IBlockState func_176345_a(World worldIn, BlockPos p_176345_2_, BlockPos p_176345_3_, IBlockState p_176345_4_)
    {
        IBlockState iblockstate1 = p_176345_4_;
        int i = ((Integer)p_176345_4_.getValue(POWER)).intValue();
        byte b0 = 0;
        int l = this.func_176342_a(worldIn, p_176345_3_, b0);
        this.canProvidePower = false;
        int j = worldIn.func_175687_A(p_176345_2_);
        this.canProvidePower = true;

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

        int k = 0;
        Iterator iterator = EnumFacing.Plane.HORIZONTAL.iterator();

        while (iterator.hasNext())
        {
            EnumFacing enumfacing = (EnumFacing)iterator.next();
            BlockPos blockpos2 = p_176345_2_.offset(enumfacing);
            boolean flag = blockpos2.getX() != p_176345_3_.getX() || blockpos2.getZ() != p_176345_3_.getZ();

            if (flag)
            {
                k = this.func_176342_a(worldIn, blockpos2, k);
            }

            if (worldIn.getBlockState(blockpos2).getBlock().isNormalCube() && !worldIn.getBlockState(p_176345_2_.offsetUp()).getBlock().isNormalCube())
            {
                if (flag && p_176345_2_.getY() >= p_176345_3_.getY())
                {
                    k = this.func_176342_a(worldIn, blockpos2.offsetUp(), k);
                }
            }
            else if (!worldIn.getBlockState(blockpos2).getBlock().isNormalCube() && flag && p_176345_2_.getY() <= p_176345_3_.getY())
            {
                k = this.func_176342_a(worldIn, blockpos2.offsetDown(), k);
            }
        }

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

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

        if (i != l)
        {
            p_176345_4_ = p_176345_4_.withProperty(POWER, Integer.valueOf(l));

            if (worldIn.getBlockState(p_176345_2_) == iblockstate1)
            {
                worldIn.setBlockState(p_176345_2_, p_176345_4_, 2);
            }

            this.field_150179_b.add(p_176345_2_);
            EnumFacing[] aenumfacing = EnumFacing.values();
            int i1 = aenumfacing.length;

            for (int j1 = 0; j1 < i1; ++j1)
            {
                EnumFacing enumfacing1 = aenumfacing[j1];
                this.field_150179_b.add(p_176345_2_.offset(enumfacing1));
            }
        }

        return p_176345_4_;
    }

    private void func_176344_d(World worldIn, BlockPos p_176344_2_)
    {
        if (worldIn.getBlockState(p_176344_2_).getBlock() == this)
        {
            worldIn.notifyNeighborsOfStateChange(p_176344_2_, this);
            EnumFacing[] aenumfacing = EnumFacing.values();
            int i = aenumfacing.length;

            for (int j = 0; j < i; ++j)
            {
                EnumFacing enumfacing = aenumfacing[j];
                worldIn.notifyNeighborsOfStateChange(p_176344_2_.offset(enumfacing), this);
            }
        }
    }

    public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state)
    {
        if (!worldIn.isRemote)
        {
            this.updateSurroundingRedstone(worldIn, pos, state);
            Iterator iterator = EnumFacing.Plane.VERTICAL.iterator();
            EnumFacing enumfacing;

            while (iterator.hasNext())
            {
                enumfacing = (EnumFacing)iterator.next();
                worldIn.notifyNeighborsOfStateChange(pos.offset(enumfacing), this);
            }

            iterator = EnumFacing.Plane.HORIZONTAL.iterator();

            while (iterator.hasNext())
            {
                enumfacing = (EnumFacing)iterator.next();
                this.func_176344_d(worldIn, pos.offset(enumfacing));
            }

            iterator = EnumFacing.Plane.HORIZONTAL.iterator();

            while (iterator.hasNext())
            {
                enumfacing = (EnumFacing)iterator.next();
                BlockPos blockpos1 = pos.offset(enumfacing);

                if (worldIn.getBlockState(blockpos1).getBlock().isNormalCube())
                {
                    this.func_176344_d(worldIn, blockpos1.offsetUp());
                }
                else
                {
                    this.func_176344_d(worldIn, blockpos1.offsetDown());
                }
            }
        }
    }

    public void breakBlock(World worldIn, BlockPos pos, IBlockState state)
    {
        super.breakBlock(worldIn, pos, state);

        if (!worldIn.isRemote)
        {
            EnumFacing[] aenumfacing = EnumFacing.values();
            int i = aenumfacing.length;

            for (int j = 0; j < i; ++j)
            {
                EnumFacing enumfacing = aenumfacing[j];
                worldIn.notifyNeighborsOfStateChange(pos.offset(enumfacing), this);
            }

            this.updateSurroundingRedstone(worldIn, pos, state);
            Iterator iterator = EnumFacing.Plane.HORIZONTAL.iterator();
            EnumFacing enumfacing1;

            while (iterator.hasNext())
            {
                enumfacing1 = (EnumFacing)iterator.next();
                this.func_176344_d(worldIn, pos.offset(enumfacing1));
            }

            iterator = EnumFacing.Plane.HORIZONTAL.iterator();

            while (iterator.hasNext())
            {
                enumfacing1 = (EnumFacing)iterator.next();
                BlockPos blockpos1 = pos.offset(enumfacing1);

                if (worldIn.getBlockState(blockpos1).getBlock().isNormalCube())
                {
                    this.func_176344_d(worldIn, blockpos1.offsetUp());
                }
                else
                {
                    this.func_176344_d(worldIn, blockpos1.offsetDown());
                }
            }
        }
    }

    private int func_176342_a(World worldIn, BlockPos p_176342_2_, int p_176342_3_)
    {
        if (worldIn.getBlockState(p_176342_2_).getBlock() != this)
        {
            return p_176342_3_;
        }
        else
        {
            int j = ((Integer)worldIn.getBlockState(p_176342_2_).getValue(POWER)).intValue();
            return j > p_176342_3_ ? j : p_176342_3_;
        }
    }

    public void onNeighborBlockChange(World worldIn, BlockPos pos, IBlockState state, Block neighborBlock)
    {
        if (!worldIn.isRemote)
        {
            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.
     *  
     * @param fortune the level of the Fortune enchantment on the player's tool
     */
    public Item getItemDropped(IBlockState state, Random rand, int fortune)
    {
        return Items.redstone;
    }

    public int isProvidingStrongPower(IBlockAccess worldIn, BlockPos pos, IBlockState state, EnumFacing side)
    {
        return !this.canProvidePower ? 0 : this.isProvidingWeakPower(worldIn, pos, state, side);
    }

    public int isProvidingWeakPower(IBlockAccess worldIn, BlockPos pos, IBlockState state, EnumFacing side)
    {
        if (!this.canProvidePower)
        {
            return 0;
        }
        else
        {
            int i = ((Integer)state.getValue(POWER)).intValue();

            if (i == 0)
            {
                return 0;
            }
            else if (side == EnumFacing.UP)
            {
                return i;
            }
            else
            {
                EnumSet enumset = EnumSet.noneOf(EnumFacing.class);
                Iterator iterator = EnumFacing.Plane.HORIZONTAL.iterator();

                while (iterator.hasNext())
                {
                    EnumFacing enumfacing1 = (EnumFacing)iterator.next();

                    if (this.func_176339_d(worldIn, pos, enumfacing1))
                    {
                        enumset.add(enumfacing1);
                    }
                }

                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 func_176339_d(IBlockAccess p_176339_1_, BlockPos p_176339_2_, EnumFacing p_176339_3_)
    {
        BlockPos blockpos1 = p_176339_2_.offset(p_176339_3_);
        IBlockState iblockstate = p_176339_1_.getBlockState(blockpos1);
        Block block = iblockstate.getBlock();
        boolean flag = block.isNormalCube();
        boolean flag1 = p_176339_1_.getBlockState(p_176339_2_.offsetUp()).getBlock().isNormalCube();
        return !flag1 && flag && canRestoneConnect(p_176339_1_, blockpos1.offsetUp(), null) ? true : (canRestoneConnect(p_176339_1_, blockpos1, p_176339_3_) ? true : (block == Blocks.powered_repeater && iblockstate.getValue(BlockRedstoneDiode.FACING) == p_176339_3_ ? true : !flag && canRestoneConnect(p_176339_1_, blockpos1.offsetDown(), null)));
    }

    protected static boolean canRestoneConnect(IBlockAccess world, BlockPos pos, EnumFacing side)
    {
        IBlockState state = world.getBlockState(pos);

        if (state.getBlock() == Blocks.redstone_wire)
        {
            return true;
        }
        else if (Blocks.unpowered_repeater.func_149907_e(state.getBlock()))
        {
            EnumFacing direction = (EnumFacing)state.getValue(BlockRedstoneRepeater.FACING);
            return direction == side || direction.getOpposite() == side;
        }
        else
        {
            return state.getBlock().canConnectRedstone(world, pos, side);
        }
    }

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

    @SideOnly(Side.CLIENT)
    private int func_176337_b(int p_176337_1_)
    {
        float f = (float)p_176337_1_ / 15.0F;
        float f1 = f * 0.6F + 0.4F;

        if (p_176337_1_ == 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 j = MathHelper.clamp_int((int)(f1 * 255.0F), 0, 255);
        int k = MathHelper.clamp_int((int)(f2 * 255.0F), 0, 255);
        int l = MathHelper.clamp_int((int)(f3 * 255.0F), 0, 255);
        return -16777216 | j << 16 | k << 8 | l;
    }

    @SideOnly(Side.CLIENT)
    public void randomDisplayTick(World worldIn, BlockPos pos, IBlockState state, Random rand)
    {
        int i = ((Integer)state.getValue(POWER)).intValue();

        if (i != 0)
        {
            double d0 = (double)pos.getX() + 0.5D + ((double)rand.nextFloat() - 0.5D) * 0.2D;
            double d1 = (double)((float)pos.getY() + 0.0625F);
            double d2 = (double)pos.getZ() + 0.5D + ((double)rand.nextFloat() - 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(EnumParticleTypes.REDSTONE, d0, d1, d2, (double)f1, (double)f2, (double)f3, new int[0]);
        }
    }

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

    @SideOnly(Side.CLIENT)
    public EnumWorldBlockLayer getBlockLayer()
    {
        return EnumWorldBlockLayer.CUTOUT;
    }

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

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

    protected BlockState createBlockState()
    {
        return new BlockState(this, new IProperty[] {NORTH, EAST, SOUTH, WEST, POWER});
    }

    static enum EnumAttachPosition implements IStringSerializable
    {
        UP("up"),
        SIDE("side"),
        NONE("none");
        private final String field_176820_d;

        private static final String __OBFID = "CL_00002070";

        private EnumAttachPosition(String p_i45689_3_)
        {
            this.field_176820_d = p_i45689_3_;
        }

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

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