package common.block.tech;

import common.block.Block;
import common.block.Material;
import common.entity.Entity;
import common.entity.item.EntityTnt;
import common.entity.npc.EntityNPC;
import common.entity.projectile.EntityArrow;
import common.entity.types.EntityLiving;
import common.init.Items;
import common.init.SoundEvent;
import common.item.CheatTab;
import common.item.Item;
import common.item.block.ItemTNT;
import common.model.Model;
import common.model.ModelProvider;
import common.properties.Property;
import common.properties.PropertyBool;
import common.util.BlockPos;
import common.util.ExtMath;
import common.util.Facing;
import common.world.Explosion;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockTNT extends Block
{
    public static final PropertyBool EXPLODE = PropertyBool.create("explode");
    public static final BlockTNT[] TNTS = new BlockTNT[8];
    
    private final int power;
    
    public static BlockTNT getByPower(int power) {
    	return TNTS[ExtMath.clampi(power, 0, TNTS.length - 1)];
    }

    public BlockTNT(int power)
    {
        super(Material.EXPLOSIVE);
        this.power = power;
        this.setDefaultState(this.getBaseState().withProperty(EXPLODE, Boolean.valueOf(false)));
        this.setTab(CheatTab.TECHNOLOGY);
        this.setFlammable(15, 100);
        TNTS[power] = this;
    }
    
    public int getExplosionPower() {
    	return this.power;
    }

    public void onBlockAdded(AWorldServer worldIn, BlockPos pos, State state)
    {
        super.onBlockAdded(worldIn, pos, state);

        if (worldIn.isBlockPowered(pos))
        {
            this.onBlockDestroyedByPlayer(worldIn, pos, state.withProperty(EXPLODE, Boolean.valueOf(true)));
            worldIn.setBlockToAir(pos);
        }
    }

    /**
     * Called when a neighboring block changes.
     */
    public void onNeighborBlockChange(World worldIn, BlockPos pos, State state, Block neighborBlock)
    {
        if (worldIn.isBlockPowered(pos))
        {
            this.onBlockDestroyedByPlayer(worldIn, pos, state.withProperty(EXPLODE, Boolean.valueOf(true)));
            worldIn.setBlockToAir(pos);
        }
    }

    /**
     * Called when this Block is destroyed by an Explosion
     */
    public void onBlockDestroyedByExplosion(World worldIn, BlockPos pos, Explosion explosionIn, State prevState)
    {
        if (!worldIn.client)
        {
            EntityTnt entitytntprimed = new EntityTnt(worldIn, (double)((float)pos.getX() + 0.5F), (double)pos.getY(), (double)((float)pos.getZ() + 0.5F), explosionIn.getExplosivePlacedBy(), this.power);
            entitytntprimed.fuse = worldIn.rand.zrange(entitytntprimed.fuse / 4) + entitytntprimed.fuse / 8;
            worldIn.spawnEntityInWorld(entitytntprimed);
        }
    }

    /**
     * Called when a player destroys this Block
     */
    public void onBlockDestroyedByPlayer(World worldIn, BlockPos pos, State state)
    {
        this.explode(worldIn, pos, state, (EntityLiving)null);
    }

    public void explode(World worldIn, BlockPos pos, State state, EntityLiving igniter)
    {
        if (!worldIn.client)
        {
            if (((Boolean)state.getValue(EXPLODE)).booleanValue())
            {
                EntityTnt entitytntprimed = new EntityTnt(worldIn, (double)((float)pos.getX() + 0.5F), (double)pos.getY(), (double)((float)pos.getZ() + 0.5F), igniter, this.power);
                worldIn.spawnEntityInWorld(entitytntprimed);
                worldIn.playSoundAtEntity(entitytntprimed, SoundEvent.FUSE, 1.0F);
            }
        }
    }

    public boolean onBlockActivated(World worldIn, BlockPos pos, State state, EntityNPC playerIn, Facing side, float hitX, float hitY, float hitZ)
    {
        if (playerIn.getCurrentEquippedItem() != null)
        {
            Item item = playerIn.getCurrentEquippedItem().getItem();

            if (item == Items.flint_and_steel || item == Items.fire_charge)
            {
                this.explode(worldIn, pos, state.withProperty(EXPLODE, Boolean.valueOf(true)), playerIn);
                worldIn.setBlockToAir(pos);

                if (item == Items.flint_and_steel)
                {
                    playerIn.getCurrentEquippedItem().damageItem(1, playerIn);
                }
                else // if (!playerIn.creative)
                {
                    --playerIn.getCurrentEquippedItem().size;
                }

                return true;
            }
        }

        return super.onBlockActivated(worldIn, pos, state, playerIn, side, hitX, hitY, hitZ);
    }

    /**
     * Called When an Entity Collided with the Block
     */
    public void onEntityCollidedWithBlock(World worldIn, BlockPos pos, State state, Entity entityIn)
    {
        if (!worldIn.client && entityIn instanceof EntityArrow)
        {
            EntityArrow entityarrow = (EntityArrow)entityIn;

            if (entityarrow.isBurning())
            {
                this.explode(worldIn, pos, worldIn.getState(pos).withProperty(EXPLODE, Boolean.valueOf(true)), entityarrow.shootingEntity instanceof EntityLiving ? (EntityLiving)entityarrow.shootingEntity : null);
                worldIn.setBlockToAir(pos);
            }
        }
    }

    /**
     * Return whether this block can drop from an explosion.
     */
    public boolean canDropFromExplosion(Explosion explosionIn)
    {
        return false;
    }

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(EXPLODE, Boolean.valueOf((meta & 1) > 0));
    }

    /**
     * Convert the BlockState into the correct metadata value
     */
    public int getMetaFromState(State state)
    {
        return ((Boolean)state.getValue(EXPLODE)).booleanValue() ? 1 : 0;
    }

    protected Property[] getProperties()
    {
        return new Property[] {EXPLODE};
    }
    
    public boolean isXrayVisible()
    {
        return true;
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	String power = this.power == 0 ? "" : ("_" + this.power);
    	return provider.getModel("tnt_side" + power).add().nswe().d("tnt_bottom" + power).u("tnt_top" + power);
    }

    public Property<?>[] getIgnoredProperties() {
    	return new Property[] {EXPLODE};
    }

    public void onDestroyedByFire(World world, BlockPos pos, State state) {
    	this.onBlockDestroyedByPlayer(world, pos, state.withProperty(BlockTNT.EXPLODE, Boolean.valueOf(true)));
    }
	
	protected Item getItemToRegister() {
		return new ItemTNT(this);
	}
}
