package common.block.foliage;

import java.util.List;

import common.block.Block;
import common.block.Material;
import common.block.SoundType;
import common.collect.Lists;
import common.color.Colorizer;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.init.ItemRegistry;
import common.init.WoodType;
import common.item.CheatTab;
import common.item.Item;
import common.item.ItemStack;
import common.item.block.ItemColored;
import common.item.tool.ItemShears;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ParticleType;
import common.properties.Property;
import common.properties.PropertyBool;
import common.rng.Random;
import common.tileentity.TileEntity;
import common.util.BlockPos;
import common.util.Facing;
import common.vars.Vars;
import common.world.IWorldAccess;
import common.world.AWorldClient;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockLeaves extends BlockLeavesBase
{
    public static final PropertyBool DECAY = PropertyBool.create("decay");
    public static final List<BlockLeaves> LEAVES = Lists.newArrayList();
    private static final BlockLeaves[] MAPPING = new BlockLeaves[WoodType.values().length * LeavesType.values().length];

	private final WoodType type;
	private final LeavesType subType;
	
    int[] surroundings;
    
    public static BlockLeaves getLeavesBlock(WoodType type, LeavesType subType) {
        return MAPPING[type.ordinal() * LeavesType.values().length + subType.ordinal()];
    }

    public BlockLeaves(WoodType type, LeavesType subType)
    {
        super(Material.LEAVES);
		this.type = type;
		this.subType = subType;
		this.setDefaultState(this.getBaseState().withProperty(DECAY, Boolean.valueOf(true)));
        this.setTickRandomly();
        this.setTab(CheatTab.PLANTS);
        this.setHardness(0.2F);
        this.setLightOpacity(1);
        this.setStepSound(SoundType.GRASS);
        this.setFlammable(30, 60);
        LEAVES.add(this);
        MAPPING[type.ordinal() * LeavesType.values().length + subType.ordinal()] = this;
    }

	public LeavesType getType() {
		return this.subType;
	}

    public void onBlockRemoved(AWorldServer worldIn, BlockPos pos, State state)
    {
        int i = 1;
        int j = i + 1;
        int k = pos.getX();
        int l = pos.getY();
        int i1 = pos.getZ();

        if (worldIn.isAreaLoaded(new BlockPos(k - j, l - j, i1 - j), new BlockPos(k + j, l + j, i1 + j)))
        {
            for (int j1 = -i; j1 <= i; ++j1)
            {
                for (int k1 = -i; k1 <= i; ++k1)
                {
                    for (int l1 = -i; l1 <= i; ++l1)
                    {
                        BlockPos blockpos = pos.add(j1, k1, l1);
                        State iblockstate = worldIn.getState(blockpos);

                        if (iblockstate.getBlock().getMaterial() == Material.LEAVES && !((Boolean)iblockstate.getValue(DECAY)).booleanValue())
                        {
                            worldIn.setState(blockpos, iblockstate.withProperty(DECAY, Boolean.valueOf(true)), 4);
                        }
                    }
                }
            }
        }
    }

    public void updateTick(AWorldServer worldIn, BlockPos pos, State state, Random rand)
    {
		if(Vars.seasonLeaves && this.subType != worldIn.getLeavesGen(pos)) {
			worldIn.setState(pos, getLeavesBlock(this.type, worldIn.getLeavesGen(pos)).getState().withProperty(DECAY, state.getValue(DECAY)), 2);
			return;
		}
    	if(Vars.leafDry && worldIn.getTemperatureC(pos) >= 50.0f) {
    		worldIn.setState(pos, worldIn.rand.chance(40) ? Blocks.air.getState() : Blocks.dry_leaves.getState());
    		return;
    	}
//        if (!worldIn.client)
//        {
    	else if (Vars.leavesDecay && ((Boolean)state.getValue(DECAY)).booleanValue())
        {
            int i = 4;
            int j = i + 1;
            int k = pos.getX();
            int l = pos.getY();
            int i1 = pos.getZ();
            int j1 = 32;
            int k1 = j1 * j1;
            int l1 = j1 / 2;

            if (this.surroundings == null)
            {
                this.surroundings = new int[j1 * j1 * j1];
            }

            if (worldIn.isAreaLoaded(new BlockPos(k - j, l - j, i1 - j), new BlockPos(k + j, l + j, i1 + j)))
            {
                BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();

                for (int i2 = -i; i2 <= i; ++i2)
                {
                    for (int j2 = -i; j2 <= i; ++j2)
                    {
                        for (int k2 = -i; k2 <= i; ++k2)
                        {
                            Block block = worldIn.getState(blockpos$mutableblockpos.set(k + i2, l + j2, i1 + k2)).getBlock();

                            if (!(block instanceof BlockLog))
                            {
                                if (block.getMaterial() == Material.LEAVES)
                                {
                                    this.surroundings[(i2 + l1) * k1 + (j2 + l1) * j1 + k2 + l1] = -2;
                                }
                                else
                                {
                                    this.surroundings[(i2 + l1) * k1 + (j2 + l1) * j1 + k2 + l1] = -1;
                                }
                            }
                            else
                            {
                                this.surroundings[(i2 + l1) * k1 + (j2 + l1) * j1 + k2 + l1] = 0;
                            }
                        }
                    }
                }

                for (int i3 = 1; i3 <= 4; ++i3)
                {
                    for (int j3 = -i; j3 <= i; ++j3)
                    {
                        for (int k3 = -i; k3 <= i; ++k3)
                        {
                            for (int l3 = -i; l3 <= i; ++l3)
                            {
                                if (this.surroundings[(j3 + l1) * k1 + (k3 + l1) * j1 + l3 + l1] == i3 - 1)
                                {
                                    if (this.surroundings[(j3 + l1 - 1) * k1 + (k3 + l1) * j1 + l3 + l1] == -2)
                                    {
                                        this.surroundings[(j3 + l1 - 1) * k1 + (k3 + l1) * j1 + l3 + l1] = i3;
                                    }

                                    if (this.surroundings[(j3 + l1 + 1) * k1 + (k3 + l1) * j1 + l3 + l1] == -2)
                                    {
                                        this.surroundings[(j3 + l1 + 1) * k1 + (k3 + l1) * j1 + l3 + l1] = i3;
                                    }

                                    if (this.surroundings[(j3 + l1) * k1 + (k3 + l1 - 1) * j1 + l3 + l1] == -2)
                                    {
                                        this.surroundings[(j3 + l1) * k1 + (k3 + l1 - 1) * j1 + l3 + l1] = i3;
                                    }

                                    if (this.surroundings[(j3 + l1) * k1 + (k3 + l1 + 1) * j1 + l3 + l1] == -2)
                                    {
                                        this.surroundings[(j3 + l1) * k1 + (k3 + l1 + 1) * j1 + l3 + l1] = i3;
                                    }

                                    if (this.surroundings[(j3 + l1) * k1 + (k3 + l1) * j1 + (l3 + l1 - 1)] == -2)
                                    {
                                        this.surroundings[(j3 + l1) * k1 + (k3 + l1) * j1 + (l3 + l1 - 1)] = i3;
                                    }

                                    if (this.surroundings[(j3 + l1) * k1 + (k3 + l1) * j1 + l3 + l1 + 1] == -2)
                                    {
                                        this.surroundings[(j3 + l1) * k1 + (k3 + l1) * j1 + l3 + l1 + 1] = i3;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            int l2 = this.surroundings[l1 * k1 + l1 * j1 + l1];

            if (l2 >= 0)
            {
                worldIn.setState(pos, state.withProperty(DECAY, Boolean.valueOf(false)), 4);
            }
            else
            {
                this.destroy(worldIn, pos);
            }
        }
//        }
    }

    public void randomDisplayTick(AWorldClient worldIn, BlockPos pos, State state, Random rand)
    {
        if (worldIn.isRainingAt(pos.up(), true) && !worldIn.isBlockSolid(pos.down()) && rand.chance(15)) // == 1
        {
            double d0 = (double)((float)pos.getX() + rand.floatv());
            double d1 = (double)pos.getY() - 0.05D;
            double d2 = (double)((float)pos.getZ() + rand.floatv());
            worldIn.spawnParticle(ParticleType.DRIP_WATER, d0, d1, d2, 0.0D, 0.0D, 0.0D);
        }
    }

    private void destroy(World worldIn, BlockPos pos)
    {
        this.dropBlockAsItem(worldIn, pos, worldIn.getState(pos), 0);
        worldIn.setBlockToAir(pos);
    }

    /**
     * Returns the quantity of items to drop on block destruction.
     */
    public int quantityDropped(Random random)
    {
        return random.chance(0, 1, this.type.getSaplingChance());
    }

    /**
     * Get the Item that this Block should drop when harvested.
     */
    public Item getItemDropped(State state, Random rand, int fortune)
    {
        return ItemRegistry.getRegisteredItem(this.type.getName() + "_sapling");
    }

    /**
     * Spawns this Block's drops into the World as EntityItems.
     */
    public void dropBlockAsItemWithChance(World worldIn, BlockPos pos, State state, float chance, int fortune)
    {
        if (!worldIn.client)
        {
            int i = this.type.getSaplingChance();

            if (fortune > 0)
            {
                i -= 2 << fortune;

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

            if (worldIn.rand.chance(i))
            {
                Item item = this.getItemDropped(state, worldIn.rand, fortune);
                spawnAsEntity(worldIn, pos, new ItemStack(item));
            }

            i = 200;

            if (fortune > 0)
            {
                i -= 10 << fortune;

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

            if(this.type.getItem() != null && worldIn.rand.chance(i)) // np
				spawnAsEntity(worldIn, pos, new ItemStack(ItemRegistry.getRegisteredItem(this.type.getItem())));
        }
    }

    public int getRenderColor(State state)
    {
        return state.getBlock() != this || !this.subType.isTinted() ? 16777215 : 
        		((this.type.getTintType() == null ? Colorizer.BASIC : this.type.getTintType()).getColor());
    }

    public int colorMultiplier(IWorldAccess worldIn, BlockPos pos, int renderPass)
    {
    	State state = worldIn.getState(pos);
        return state.getBlock() != this || !this.subType.isTinted() ? 16777215 : (this.type.getTintType()
        		== null ? Colorizer.getFoliageColor(worldIn, pos) : this.type.getTintType().getColor());
    }

	public State getStateFromMeta(int meta) {
		return this.getState().withProperty(DECAY, Boolean.valueOf((meta & 8) == 0));
	}

	public int getMetaFromState(State state) {
		int i = 0;

		if(!((Boolean)state.getValue(DECAY)).booleanValue()) {
			i |= 8;
		}

		return i;
	}

	protected Property[] getProperties() {
		return new Property[] {DECAY};
	}

	public void harvestBlock(World worldIn, EntityNPC player, BlockPos pos, State state, TileEntity te) {
		if(!worldIn.client && player.getCurrentEquippedItem() != null && player.getCurrentEquippedItem().getItem() instanceof ItemShears) {
			spawnAsEntity(worldIn, pos, new ItemStack(this.getItem()));
		}
		else {
			super.harvestBlock(worldIn, player, pos, state, te);
		}
	}
	
    public State onBlockPlaced(World worldIn, BlockPos pos, Facing facing, float hitX, float hitY, float hitZ, EntityLiving placer) {
    	return this.getState().withProperty(DECAY, false);
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	return this.subType.isTinted() ? provider.getModel(name).add().all().tint() :
    			provider.getModel(name).add().all();
    }

    public Property<?>[] getIgnoredProperties() {
    	return new Property[] {DECAY};
    }
	
	protected Item getItemToRegister() {
		return new ItemColored(this);
	}
}
