package common.block.tech;

import common.block.Block;
import common.block.ITileEntityProvider;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.Blocks;
import common.init.Items;
import common.init.SoundEvent;
import common.item.CheatTab;
import common.item.Item;
import common.item.block.ItemSmallBlock;
import common.model.Model;
import common.model.ModelProvider;
import common.model.ModelRotation;
import common.properties.Property;
import common.properties.PropertyBool;
import common.properties.PropertyEnum;
import common.rng.Random;
import common.tileentity.TileEntity;
import common.tileentity.TileEntityComparator;
import common.util.BlockPos;
import common.util.Facing;
import common.util.Identifyable;
import common.world.IWorldAccess;
import common.world.State;
import common.world.World;
import common.world.AWorldServer;

public class BlockRedstoneComparator extends BlockRedstoneDiode implements ITileEntityProvider
{
    public static final PropertyBool POWERED = PropertyBool.create("powered");
    public static final PropertyEnum<BlockRedstoneComparator.Mode> MODE = PropertyEnum.<BlockRedstoneComparator.Mode>create("mode", BlockRedstoneComparator.Mode.class);

    public BlockRedstoneComparator(boolean powered)
    {
        super(powered);
        this.setDefaultState(this.getBaseState().withProperty(FACING, Facing.NORTH).withProperty(POWERED, Boolean.valueOf(false)).withProperty(MODE, BlockRedstoneComparator.Mode.COMPARE));
        this.hasTile = true;
    }

//    /**
//     * Gets the localized name of this block. Used for the statistics page.
//     */
//    public String getLocalizedName()
//    {
//        return "Redstone-Komparator";
//    }

    /**
     * Get the Item that this Block should drop when harvested.
     */
    public Item getItemDropped(State state, Random rand, int fortune)
    {
        return Items.comparator;
    }

    public Item getItem(World worldIn, BlockPos pos)
    {
        return Items.comparator;
    }

    protected int getDelay(State state)
    {
        return 2;
    }

    protected State getPoweredState(State unpoweredState)
    {
        Boolean obool = (Boolean)unpoweredState.getValue(POWERED);
        BlockRedstoneComparator.Mode blockredstonecomparator$mode = (BlockRedstoneComparator.Mode)unpoweredState.getValue(MODE);
        Facing enumfacing = (Facing)unpoweredState.getValue(FACING);
        return Blocks.powered_comparator.getState().withProperty(FACING, enumfacing).withProperty(POWERED, obool).withProperty(MODE, blockredstonecomparator$mode);
    }

    protected State getUnpoweredState(State poweredState)
    {
        Boolean obool = (Boolean)poweredState.getValue(POWERED);
        BlockRedstoneComparator.Mode blockredstonecomparator$mode = (BlockRedstoneComparator.Mode)poweredState.getValue(MODE);
        Facing enumfacing = (Facing)poweredState.getValue(FACING);
        return Blocks.comparator.getState().withProperty(FACING, enumfacing).withProperty(POWERED, obool).withProperty(MODE, blockredstonecomparator$mode);
    }

    protected boolean isPowered(State state)
    {
        return this.isRepeaterPowered || ((Boolean)state.getValue(POWERED)).booleanValue();
    }

    protected int getActiveSignal(IWorldAccess worldIn, BlockPos pos, State state)
    {
        TileEntity tileentity = worldIn.getTileEntity(pos);
        return tileentity instanceof TileEntityComparator ? ((TileEntityComparator)tileentity).getOutputSignal() : 0;
    }

    private int calculateOutput(World worldIn, BlockPos pos, State state)
    {
        return state.getValue(MODE) == BlockRedstoneComparator.Mode.SUBTRACT ? Math.max(this.calculateInputStrength(worldIn, pos, state) - this.getPowerOnSides(worldIn, pos, state), 0) : this.calculateInputStrength(worldIn, pos, state);
    }

    protected boolean shouldBePowered(World worldIn, BlockPos pos, State state)
    {
        int i = this.calculateInputStrength(worldIn, pos, state);

        if (i >= 15)
        {
            return true;
        }
        else if (i == 0)
        {
            return false;
        }
        else
        {
            int j = this.getPowerOnSides(worldIn, pos, state);
            return j == 0 ? true : i >= j;
        }
    }

    protected int calculateInputStrength(World worldIn, BlockPos pos, State state)
    {
        int i = super.calculateInputStrength(worldIn, pos, state);
        Facing enumfacing = (Facing)state.getValue(FACING);
        BlockPos blockpos = pos.offset(enumfacing);
        Block block = worldIn.getState(blockpos).getBlock();

        if (block.hasComparatorInputOverride())
        {
            i = block.getComparatorInputOverride(worldIn, blockpos);
        }
        else if (i < 15 && block.isNormalCube())
        {
            blockpos = blockpos.offset(enumfacing);
            block = worldIn.getState(blockpos).getBlock();

            if (block.hasComparatorInputOverride())
            {
                i = block.getComparatorInputOverride(worldIn, blockpos);
            }
//            else if (block == Blocks.air)
//            {
//                EntityFrame entityitemframe = this.findItemFrame(worldIn, enumfacing, blockpos);
//
//                if (entityitemframe != null)
//                {
//                    i = entityitemframe.getItemRotation();
//                }
//            }
        }

        return i;
    }

//    private EntityFrame findItemFrame(World worldIn, final Facing facing, BlockPos pos)
//    {
//        List<EntityFrame> list = worldIn.<EntityFrame>getEntitiesWithinAABB(EntityFrame.class, new BoundingBox((double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), (double)(pos.getX() + 1), (double)(pos.getY() + 1), (double)(pos.getZ() + 1)), new Predicate<Entity>()
//        {
//            public boolean test(Entity p_apply_1_)
//            {
//                return p_apply_1_ != null && p_apply_1_.getHorizontalFacing() == facing;
//            }
//        });
//        return list.size() == 1 ? (EntityFrame)list.get(0) : null;
//    }

    public boolean onBlockActivated(World worldIn, BlockPos pos, State state, EntityNPC playerIn, Facing side, float hitX, float hitY, float hitZ)
    {
//        if (!playerIn.capabilities.allowEdit)
//        {
//            return false;
//        }
//        else
//        {
        state = state.cycleProperty(MODE);
        worldIn.playSound(SoundEvent.CLICK, (double)pos.getX() + 0.5D, (double)pos.getY() + 0.5D, (double)pos.getZ() + 0.5D, 0.3F);
        worldIn.setState(pos, state, 2);
        this.onStateChange(worldIn, pos, state);
        return true;
//        }
    }

    protected void updateState(World worldIn, BlockPos pos, State state)
    {
        if (worldIn.client || !((AWorldServer)worldIn).isBlockTickPending(pos, this))
        {
            int i = this.calculateOutput(worldIn, pos, state);
            TileEntity tileentity = worldIn.getTileEntity(pos);
            int j = tileentity instanceof TileEntityComparator ? ((TileEntityComparator)tileentity).getOutputSignal() : 0;

            if (i != j || this.isPowered(state) != this.shouldBePowered(worldIn, pos, state))
            {
                if (this.isFacingTowardsRepeater(worldIn, pos, state))
                {
                	if(!worldIn.client)
                		((AWorldServer)worldIn).updateBlockTick(pos, this, 2, -1);
                }
                else
                {
                	if(!worldIn.client)
                		((AWorldServer)worldIn).updateBlockTick(pos, this, 2, 0);
                }
            }
        }
    }

    private void onStateChange(World worldIn, BlockPos pos, State state)
    {
        int i = this.calculateOutput(worldIn, pos, state);
        TileEntity tileentity = worldIn.getTileEntity(pos);
        int j = 0;

        if (tileentity instanceof TileEntityComparator)
        {
            TileEntityComparator tileentitycomparator = (TileEntityComparator)tileentity;
            j = tileentitycomparator.getOutputSignal();
            tileentitycomparator.setOutputSignal(i);
        }

        if (j != i || state.getValue(MODE) == BlockRedstoneComparator.Mode.COMPARE)
        {
            boolean flag1 = this.shouldBePowered(worldIn, pos, state);
            boolean flag = this.isPowered(state);

            if (flag && !flag1)
            {
                worldIn.setState(pos, state.withProperty(POWERED, Boolean.valueOf(false)), 2);
            }
            else if (!flag && flag1)
            {
                worldIn.setState(pos, state.withProperty(POWERED, Boolean.valueOf(true)), 2);
            }

            this.notifyNeighbors(worldIn, pos, state);
        }
    }

    public void updateTick(AWorldServer worldIn, BlockPos pos, State state, Random rand)
    {
        if (this.isRepeaterPowered)
        {
            worldIn.setState(pos, this.getUnpoweredState(state).withProperty(POWERED, Boolean.valueOf(true)), 4);
        }

        this.onStateChange(worldIn, pos, state);
    }

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

    public void onBlockRemoved(AWorldServer worldIn, BlockPos pos, State state)
    {
        super.onBlockRemoved(worldIn, pos, state);
        worldIn.removeTileEntity(pos);
        this.notifyNeighbors(worldIn, pos, state);
    }

    /**
     * Called on both Client and Server when World#addBlockEvent is called
     */
    public boolean onBlockEventReceived(World worldIn, BlockPos pos, State state, int eventID, int eventParam)
    {
        super.onBlockEventReceived(worldIn, pos, state, eventID, eventParam);
        TileEntity tileentity = worldIn.getTileEntity(pos);
        return tileentity == null ? false : tileentity.receiveClientEvent(eventID, eventParam);
    }

    /**
     * Returns a new instance of a block's tile entity class. Called on placing the block.
     */
    public TileEntity createNewTileEntity(World worldIn)
    {
        return new TileEntityComparator();
    }

    /**
     * Convert the given metadata into a BlockState for this Block
     */
    public State getStateFromMeta(int meta)
    {
        return this.getState().withProperty(FACING, Facing.getHorizontal(meta)).withProperty(POWERED, Boolean.valueOf((meta & 8) > 0)).withProperty(MODE, (meta & 4) > 0 ? BlockRedstoneComparator.Mode.SUBTRACT : BlockRedstoneComparator.Mode.COMPARE);
    }

    /**
     * Convert the BlockState into the correct metadata value
     */
    public int getMetaFromState(State state)
    {
        int i = 0;
        i = i | ((Facing)state.getValue(FACING)).getHorizontalIndex();

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

        if (state.getValue(MODE) == BlockRedstoneComparator.Mode.SUBTRACT)
        {
            i |= 4;
        }

        return i;
    }

    protected Property[] getProperties()
    {
        return new Property[] {FACING, MODE, POWERED};
    }

    /**
     * Called by ItemBlocks just before a block is actually set in the world, to allow for adjustments to the
     * IBlockstate
     */
    public State onBlockPlaced(World worldIn, BlockPos pos, Facing facing, float hitX, float hitY, float hitZ, EntityLiving placer)
    {
        return this.getState().withProperty(FACING, placer.getHorizontalFacing().getOpposite()).withProperty(POWERED, Boolean.valueOf(false)).withProperty(MODE, BlockRedstoneComparator.Mode.COMPARE);
    }

    public Model getModel(ModelProvider provider, String name, State state) {
    	return (state.getValue(POWERED) ? (state.getValue(MODE) == Mode.SUBTRACT ? provider.getModel("comparator_on")
			.add(0, 0, 0, 16, 2, 16)
				.d("double_stone_top").uv(0, 0, 16, 16)
				.u().uv(0, 0, 16, 16).noCull()
				.n("double_stone_top").uv(0, 14, 16, 16)
				.s("double_stone_top").uv(0, 14, 16, 16)
				.w("double_stone_top").uv(0, 14, 16, 16)
				.e("double_stone_top").uv(0, 14, 16, 16)
			.add(4, 7, 11, 6, 7, 13)
				.u("redstone_torch").uv(7, 6, 9, 8).noCull()
			.add(4, 2, 10, 6, 8, 14)
				.w("redstone_torch").uv(6, 5, 10, 11).noCull()
				.e("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(3, 2, 11, 7, 8, 13)
				.n("redstone_torch").uv(6, 5, 10, 11).noCull()
				.s("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(10, 7, 11, 12, 7, 13)
				.u("redstone_torch").uv(7, 6, 9, 8).noCull()
			.add(10, 2, 10, 12, 8, 14)
				.w("redstone_torch").uv(6, 5, 10, 11).noCull()
				.e("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(9, 2, 11, 13, 8, 13)
				.n("redstone_torch").uv(6, 5, 10, 11).noCull()
				.s("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(7, 5, 2, 9, 5, 4)
				.u("redstone_torch").uv(7, 6, 9, 8).noCull()
			.add(7, 2, 1, 9, 6, 5)
				.w("redstone_torch").uv(6, 5, 10, 9).noCull()
				.e("redstone_torch").uv(6, 5, 10, 9).noCull()
			.add(6, 2, 2, 10, 6, 4)
				.n("redstone_torch").uv(6, 5, 10, 9).noCull()
				.s("redstone_torch").uv(6, 5, 10, 9).noCull() : provider.getModel("comparator_on")
			.add(0, 0, 0, 16, 2, 16)
				.d("double_stone_top").uv(0, 0, 16, 16)
				.u().uv(0, 0, 16, 16).noCull()
				.n("double_stone_top").uv(0, 14, 16, 16)
				.s("double_stone_top").uv(0, 14, 16, 16)
				.w("double_stone_top").uv(0, 14, 16, 16)
				.e("double_stone_top").uv(0, 14, 16, 16)
			.add(4, 7, 11, 6, 7, 13)
				.u("redstone_torch").uv(7, 6, 9, 8).noCull()
			.add(4, 2, 10, 6, 8, 14)
				.w("redstone_torch").uv(6, 5, 10, 11).noCull()
				.e("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(3, 2, 11, 7, 8, 13)
				.n("redstone_torch").uv(6, 5, 10, 11).noCull()
				.s("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(10, 7, 11, 12, 7, 13)
				.u("redstone_torch").uv(7, 6, 9, 8).noCull()
			.add(10, 2, 10, 12, 8, 14)
				.w("redstone_torch").uv(6, 5, 10, 11).noCull()
				.e("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(9, 2, 11, 13, 8, 13)
				.n("redstone_torch").uv(6, 5, 10, 11).noCull()
				.s("redstone_torch").uv(6, 5, 10, 11).noCull()
			.add(7, 2, 2, 9, 4, 4)
				.d("unlit_redstone_torch").uv(7, 13, 9, 15).noCull()
				.u("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.n("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.s("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.w("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.e("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()) 
    			: (state.getValue(MODE) == Mode.SUBTRACT ? provider.getModel("comparator_off")
			.add(0, 0, 0, 16, 2, 16)
				.d("double_stone_top").uv(0, 0, 16, 16)
				.u().uv(0, 0, 16, 16).noCull()
				.n("double_stone_top").uv(0, 14, 16, 16)
				.s("double_stone_top").uv(0, 14, 16, 16)
				.w("double_stone_top").uv(0, 14, 16, 16)
				.e("double_stone_top").uv(0, 14, 16, 16)
			.add(4, 2, 11, 6, 7, 13)
				.d("unlit_redstone_torch").uv(7, 13, 9, 15).noCull()
				.u("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.n("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.s("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.w("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.e("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
			.add(10, 2, 11, 12, 7, 13)
				.d("unlit_redstone_torch").uv(7, 13, 9, 15).noCull()
				.u("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.n("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.s("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.w("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.e("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
			.add(7, 5, 2, 9, 5, 4)
				.u("redstone_torch").uv(7, 6, 9, 8).noCull()
			.add(7, 2, 1, 9, 6, 5)
				.w("redstone_torch").uv(6, 5, 10, 9).noCull()
				.e("redstone_torch").uv(6, 5, 10, 9).noCull()
			.add(6, 2, 2, 10, 6, 4)
				.n("redstone_torch").uv(6, 5, 10, 9).noCull()
				.s("redstone_torch").uv(6, 5, 10, 9).noCull() : provider.getModel("comparator_off")
			.add(0, 0, 0, 16, 2, 16)
				.d("double_stone_top").uv(0, 0, 16, 16)
				.u().uv(0, 0, 16, 16).noCull()
				.n("double_stone_top").uv(0, 14, 16, 16)
				.s("double_stone_top").uv(0, 14, 16, 16)
				.w("double_stone_top").uv(0, 14, 16, 16)
				.e("double_stone_top").uv(0, 14, 16, 16)
			.add(4, 2, 11, 6, 7, 13)
				.d("unlit_redstone_torch").uv(7, 13, 9, 15).noCull()
				.u("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.n("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.s("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.w("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.e("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
			.add(10, 2, 11, 12, 7, 13)
				.d("unlit_redstone_torch").uv(7, 13, 9, 15).noCull()
				.u("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.n("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.s("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.w("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
				.e("unlit_redstone_torch").uv(7, 6, 9, 11).noCull()
			.add(7, 2, 2, 9, 4, 4)
				.d("unlit_redstone_torch").uv(7, 13, 9, 15).noCull()
				.u("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.n("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.s("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.w("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()
				.e("unlit_redstone_torch").uv(7, 6, 9, 8).noCull()))
    			.rotate(ModelRotation.getNorthRot(state.getValue(FACING).getOpposite()));
    }
	
	protected Item getItemToRegister() {
		return this.isRepeaterPowered ? null : new ItemSmallBlock(this).setDisplay("Redstone-Komparator").setTab(CheatTab.TECHNOLOGY);
	}

    public static enum Mode implements Identifyable
    {
        COMPARE("compare"),
        SUBTRACT("subtract");

        private final String name;

        private Mode(String name)
        {
            this.name = name;
        }

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

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