// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.server.npc.blackboard.view.event.block;

import com.hypixel.hytale.server.npc.blackboard.view.IBlackboardView;
import com.hypixel.hytale.protocol.InteractionType;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.server.core.modules.entity.player.PlayerSettings;
import com.hypixel.hytale.protocol.GameMode;
import com.hypixel.hytale.server.core.entity.entities.Player;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.server.core.event.events.ecs.BreakBlockEvent;
import com.hypixel.hytale.server.core.event.events.ecs.DamageBlockEvent;
import it.unimi.dsi.fastutil.ints.IntSet;
import com.hypixel.hytale.server.npc.blackboard.Blackboard;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.npc.blackboard.view.event.EventTypeRegistration;
import com.hypixel.hytale.server.npc.entities.NPCEntity;
import com.hypixel.hytale.server.core.modules.blockset.BlockSetModule;
import com.hypixel.hytale.server.core.event.events.player.PlayerInteractEvent;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.server.npc.blackboard.view.event.EventNotification;
import com.hypixel.hytale.server.npc.blackboard.view.event.EventView;

public class BlockEventView extends EventView<BlockEventView, BlockEventType, EventNotification>
{
    public BlockEventView(@Nonnull final World world) {
        super(BlockEventType.class, BlockEventType.VALUES, new EventNotification(), world);
        this.eventRegistry.register(PlayerInteractEvent.class, world.getName(), this::onPlayerInteraction);
        for (final BlockEventType eventType : BlockEventType.VALUES) {
            this.entityMapsByEventType.put((EventType)eventType, (EventTypeRegistration<EventType, NotificationType>)new EventTypeRegistration<Enum<EventType>, EventNotification>((EventType)eventType, (set, blockId) -> BlockSetModule.getInstance().blockInSet(set, blockId), NPCEntity::notifyBlockChange));
        }
    }
    
    @Override
    public BlockEventView getUpdatedView(@Nonnull final Ref<EntityStore> ref, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final World entityWorld = componentAccessor.getExternalData().getWorld();
        if (!entityWorld.equals(this.world)) {
            final Blackboard blackboardResource = componentAccessor.getResource(Blackboard.getResourceType());
            return blackboardResource.getView(BlockEventView.class, ref, componentAccessor);
        }
        return this;
    }
    
    @Override
    public void initialiseEntity(@Nonnull final Ref<EntityStore> ref, @Nonnull final NPCEntity npcComponent) {
        for (int i = 0; i < BlockEventType.VALUES.length; ++i) {
            final BlockEventType type = BlockEventType.VALUES[i];
            final IntSet eventSets = npcComponent.getBlackboardBlockChangeSet(type);
            if (eventSets != null) {
                this.entityMapsByEventType.get(type).initialiseEntity(npcComponent.getReference(), eventSets);
            }
        }
    }
    
    @Override
    protected void onEvent(final int senderTypeId, final double x, final double y, final double z, final Ref<EntityStore> initiator, final Ref<EntityStore> skip, @Nonnull final ComponentAccessor<EntityStore> componentAccessor, final BlockEventType type) {
        super.onEvent(senderTypeId, x + 0.5, y + 0.5, z + 0.5, initiator, skip, componentAccessor, type);
    }
    
    public void onEntityDamageBlock(@Nonnull final Ref<EntityStore> ref, @Nonnull final DamageBlockEvent event) {
        if (event.isCancelled()) {
            return;
        }
        this.processDamagedBlock(ref, event.getBlockType().getId(), event.getTargetBlock(), BlockEventType.DAMAGE);
    }
    
    public void onEntityBreakBlock(@Nonnull final Ref<EntityStore> ref, @Nonnull final BreakBlockEvent event) {
        if (event.isCancelled()) {
            return;
        }
        this.processDamagedBlock(ref, event.getBlockType().getId(), event.getTargetBlock(), BlockEventType.DESTRUCTION);
    }
    
    private void processDamagedBlock(@Nonnull final Ref<EntityStore> initiatorRef, final String block, @Nonnull final Vector3i position, @Nonnull final BlockEventType type) {
        final Store<EntityStore> store = initiatorRef.getStore();
        final Player playerComponent = store.getComponent(initiatorRef, Player.getComponentType());
        if (playerComponent != null && playerComponent.getGameMode() == GameMode.Creative) {
            final PlayerSettings playerSettingsComponent = store.getComponent(initiatorRef, PlayerSettings.getComponentType());
            if (playerSettingsComponent == null || !playerSettingsComponent.creativeSettings().allowNPCDetection()) {
                return;
            }
        }
        final int blockId = BlockType.getAssetMap().getIndex(block);
        if (blockId == Integer.MIN_VALUE) {
            throw new IllegalArgumentException("Unknown key! " + block);
        }
        this.onEvent(blockId, position.x, position.y, position.z, initiatorRef, null, store, type);
    }
    
    private void onPlayerInteraction(@Nonnull final PlayerInteractEvent event) {
        if (event.isCancelled()) {
            return;
        }
        final Player playerComponent = event.getPlayer();
        final Ref<EntityStore> ref = event.getPlayerRef();
        final Store<EntityStore> store = ref.getStore();
        if (playerComponent.getGameMode() == GameMode.Creative) {
            final PlayerSettings playerSettingsComponent = store.getComponent(ref, PlayerSettings.getComponentType());
            if (playerSettingsComponent == null || !playerSettingsComponent.creativeSettings().allowNPCDetection()) {
                return;
            }
        }
        final Vector3i blockPosition = event.getTargetBlock();
        if (blockPosition == null || event.getActionType() != InteractionType.Use) {
            return;
        }
        final World world = store.getExternalData().getWorld();
        final int blockId = world.getBlock(blockPosition.x, blockPosition.y, blockPosition.z);
        final Vector3i targetBlock = event.getTargetBlock();
        this.onEvent(blockId, targetBlock.x, targetBlock.y, targetBlock.z, ref, null, store, BlockEventType.INTERACTION);
    }
}
