package common.block;

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

import common.init.Blocks;
import common.init.Config;
import common.material.Material;
import common.rng.Random;
import common.util.BlockPos;
import common.util.Facing;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockDynamicLiquid extends BlockLiquid
{
	private final boolean infinite;
    int adjacentSourceBlocks;

    public BlockDynamicLiquid(Material materialIn, boolean infinite, boolean opaque, int rate)
    {
        super(materialIn, true, opaque, rate);
        this.infinite = infinite;
    }

    private void placeStaticBlock(World worldIn, BlockPos pos, State currentState)
    {
        worldIn.setState(pos, getStaticBlock(this).getState().withProperty(LEVEL, currentState.getValue(LEVEL)), 2);
    }

    public void updateTick(AWorldServer worldIn, BlockPos pos, State state, Random rand)
    {
    	if(!Config.liquidPhysics)
    		return;
        int i = ((Integer)state.getValue(LEVEL)).intValue();
        int j = 1;

        if (this.flowRate < 0 && !worldIn.doesWaterVaporize(pos))
        {
            j = 2;
        }

        int k = this.tickRate(worldIn, pos);

        if (i > 0)
        {
            int l = -100;
            this.adjacentSourceBlocks = 0;

            for (Facing enumfacing : Facing.Plane.HORIZONTAL)
            {
                l = this.checkAdjacentBlock(worldIn, pos.offset(enumfacing), l);
            }

            int i1 = l + j;

            if (i1 >= 8 || l < 0)
            {
                i1 = -1;
            }

            if (this.getLevel(worldIn, pos.up()) >= 0)
            {
                int j1 = this.getLevel(worldIn, pos.up());

                if (j1 >= 8)
                {
                    i1 = j1;
                }
                else
                {
                    i1 = j1 + 8;
                }
            }

            if (this.adjacentSourceBlocks >= 2 && ((Config.mergeWater && this.material == Material.water)
            		|| (Config.mergeLava && this.material == Material.lava)
            		|| (this.infinite && Config.mergeInfinite && this.material != Material.water && this.material != Material.lava)
            		|| (!this.infinite && Config.mergeFinite && this.material != Material.water && this.material != Material.lava)))
            {
                State iblockstate1 = worldIn.getState(pos.down());

                if (iblockstate1.getBlock().getMaterial().isSolid())
                {
                    i1 = 0;
                }
                else if (iblockstate1.getBlock().getMaterial() == this.material && ((Integer)iblockstate1.getValue(LEVEL)).intValue() == 0)
                {
                    i1 = 0;
                }
            }

            if (this.flowRate < 0 && i < 8 && i1 < 8 && i1 > i && rand.rarity(4))
            {
                k *= 4;
            }

            if (i1 == i)
            {
                this.placeStaticBlock(worldIn, pos, state);
            }
            else
            {
                i = i1;

                if (i1 < 0)
                {
                    worldIn.setBlockToAir(pos);
                }
                else
                {
                    state = state.withProperty(LEVEL, Integer.valueOf(i1));
                    worldIn.setState(pos, state, 2);
                    worldIn.scheduleUpdate(pos, this, k);
                    worldIn.notifyNeighborsOfStateChange(pos, this);
                }
            }
        }
        else
        {
            this.placeStaticBlock(worldIn, pos, state);
        }

        State iblockstate = worldIn.getState(pos.down());

        if (this.canFlowInto(worldIn, pos.down(), iblockstate))
        {
            if (this.material == Material.lava && worldIn.getState(pos.down()).getBlock().getMaterial().isColdLiquid())
            {
                worldIn.setState(pos.down(), Blocks.stone.getState());
                this.triggerMixEffects(worldIn, pos.down());
                return;
            }

            if (i >= 8)
            {
                this.tryFlowInto(worldIn, pos.down(), iblockstate, i);
            }
            else
            {
                this.tryFlowInto(worldIn, pos.down(), iblockstate, i + 8);
            }
        }
        else if (i >= 0 && (i == 0 || this.isBlocked(worldIn, pos.down(), iblockstate)))
        {
            Set<Facing> set = this.getPossibleFlowDirections(worldIn, pos);
            int k1 = i + j;

            if (i >= 8)
            {
                k1 = 1;
            }

            if (k1 >= 8)
            {
                return;
            }

            for (Facing enumfacing1 : set)
            {
                this.tryFlowInto(worldIn, pos.offset(enumfacing1), worldIn.getState(pos.offset(enumfacing1)), k1);
            }
        }
    }

    private void tryFlowInto(World worldIn, BlockPos pos, State state, int level)
    {
        if (this.canFlowInto(worldIn, pos, state))
        {
            if (state.getBlock() != Blocks.air)
            {
                if (this.material == Material.lava)
                {
                    this.triggerMixEffects(worldIn, pos);
                }
                else
                {
                    state.getBlock().dropBlockAsItem(worldIn, pos, state, 0);
                }
            }

            worldIn.setState(pos, this.getState().withProperty(LEVEL, Integer.valueOf(level)), 3);
        }
    }

    private int propogateLiquid(World worldIn, BlockPos pos, int distance, Facing calculateFlowCost)
    {
        int i = 1000;

        for (Facing enumfacing : Facing.Plane.HORIZONTAL)
        {
            if (enumfacing != calculateFlowCost)
            {
                BlockPos blockpos = pos.offset(enumfacing);
                State iblockstate = worldIn.getState(blockpos);

                if (!this.isBlocked(worldIn, blockpos, iblockstate) && (iblockstate.getBlock().getMaterial() != this.material || ((Integer)iblockstate.getValue(LEVEL)).intValue() > 0))
                {
                    if (!this.isBlocked(worldIn, blockpos.down(), iblockstate))
                    {
                        return distance;
                    }

                    if (distance < 4)
                    {
                        int j = this.propogateLiquid(worldIn, blockpos, distance + 1, enumfacing.getOpposite());

                        if (j < i)
                        {
                            i = j;
                        }
                    }
                }
            }
        }

        return i;
    }

    private Set<Facing> getPossibleFlowDirections(World worldIn, BlockPos pos)
    {
        int i = 1000;
        Set<Facing> set = EnumSet.<Facing>noneOf(Facing.class);

        for (Facing enumfacing : Facing.Plane.HORIZONTAL)
        {
            BlockPos blockpos = pos.offset(enumfacing);
            State iblockstate = worldIn.getState(blockpos);

            if (!this.isBlocked(worldIn, blockpos, iblockstate) && (iblockstate.getBlock().getMaterial() != this.material || ((Integer)iblockstate.getValue(LEVEL)).intValue() > 0))
            {
                int j;

                if (this.isBlocked(worldIn, blockpos.down(), worldIn.getState(blockpos.down())))
                {
                    j = this.propogateLiquid(worldIn, blockpos, 1, enumfacing.getOpposite());
                }
                else
                {
                    j = 0;
                }

                if (j < i)
                {
                    set.clear();
                }

                if (j <= i)
                {
                    set.add(enumfacing);
                    i = j;
                }
            }
        }

        return set;
    }

    private boolean isBlocked(World worldIn, BlockPos pos, State state)
    {
        Block block = worldIn.getState(pos).getBlock();
        return !(block instanceof BlockDoor) && block != Blocks.sign && block != Blocks.ladder && block != Blocks.reeds ? (block.material == Material.portal ? true : block.material.blocksMovement()) : true;
    }

    protected int checkAdjacentBlock(World worldIn, BlockPos pos, int currentMinLevel)
    {
        int i = this.getLevel(worldIn, pos);

        if (i < 0)
        {
            return currentMinLevel;
        }
        else
        {
            if (i == 0)
            {
                ++this.adjacentSourceBlocks;
            }

            if (i >= 8)
            {
                i = 0;
            }

            return currentMinLevel >= 0 && i >= currentMinLevel ? currentMinLevel : i;
        }
    }

    private boolean canFlowInto(World worldIn, BlockPos pos, State state)
    {
        Material material = state.getBlock().getMaterial();
        return material != this.material && material != Material.lava && !this.isBlocked(worldIn, pos, state);
    }

    public void onBlockAdded(AWorldServer worldIn, BlockPos pos, State state)
    {
        if (!this.checkForMixing(worldIn, pos, state))
        {
            worldIn.scheduleUpdate(pos, this, this.tickRate(worldIn, pos));
        }
    }
}
