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

package com.hypixel.hytale.builtin.mounts;

import com.hypixel.hytale.math.vector.Vector3f;
import java.util.Collection;
import javax.annotation.Nullable;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import com.hypixel.hytale.component.ComponentType;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.mountpoints.BlockMountPoint;
import java.util.Map;
import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
import com.hypixel.hytale.math.vector.Vector3i;
import com.hypixel.hytale.protocol.BlockMountType;
import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
import com.hypixel.hytale.component.Component;

public class BlockMountComponent implements Component<ChunkStore>
{
    private BlockMountType type;
    private Vector3i blockPos;
    private BlockType expectedBlockType;
    private int expectedRotation;
    @Nonnull
    private Map<BlockMountPoint, Ref<EntityStore>> entitiesByMountPoint;
    @Nonnull
    private Map<Ref<EntityStore>, BlockMountPoint> mountPointByEntity;
    
    public static ComponentType<ChunkStore, BlockMountComponent> getComponentType() {
        return MountPlugin.getInstance().getBlockMountComponentType();
    }
    
    public BlockMountComponent() {
        this.entitiesByMountPoint = new Object2ObjectOpenHashMap<BlockMountPoint, Ref<EntityStore>>();
        this.mountPointByEntity = new Object2ObjectOpenHashMap<Ref<EntityStore>, BlockMountPoint>();
    }
    
    public BlockMountComponent(final BlockMountType type, final Vector3i blockPos, final BlockType expectedBlockType, final int expectedRotation) {
        this.entitiesByMountPoint = new Object2ObjectOpenHashMap<BlockMountPoint, Ref<EntityStore>>();
        this.mountPointByEntity = new Object2ObjectOpenHashMap<Ref<EntityStore>, BlockMountPoint>();
        this.type = type;
        this.blockPos = blockPos;
        this.expectedBlockType = expectedBlockType;
        this.expectedRotation = expectedRotation;
    }
    
    public BlockMountType getType() {
        return this.type;
    }
    
    public Vector3i getBlockPos() {
        return this.blockPos;
    }
    
    public BlockType getExpectedBlockType() {
        return this.expectedBlockType;
    }
    
    public int getExpectedRotation() {
        return this.expectedRotation;
    }
    
    public boolean isDead() {
        this.clean();
        return this.entitiesByMountPoint.isEmpty();
    }
    
    private void clean() {
        this.entitiesByMountPoint.values().removeIf(ref -> !ref.isValid());
        this.mountPointByEntity.keySet().removeIf(ref -> !ref.isValid());
    }
    
    public void putSeatedEntity(@Nonnull final BlockMountPoint mountPoint, @Nonnull final Ref<EntityStore> seatedEntity) {
        this.entitiesByMountPoint.put(mountPoint, seatedEntity);
        this.mountPointByEntity.put(seatedEntity, mountPoint);
    }
    
    public void removeSeatedEntity(@Nonnull final Ref<EntityStore> seatedEntity) {
        final BlockMountPoint seat = this.mountPointByEntity.remove(seatedEntity);
        if (seat != null) {
            this.entitiesByMountPoint.remove(seat);
        }
    }
    
    @Nullable
    public BlockMountPoint getSeatBlockBySeatedEntity(final Ref<EntityStore> seatedEntity) {
        return this.mountPointByEntity.get(seatedEntity);
    }
    
    @Nonnull
    public Collection<? extends Ref<EntityStore>> getSeatedEntities() {
        return this.entitiesByMountPoint.values();
    }
    
    @Nullable
    public BlockMountPoint findAvailableSeat(@Nonnull final Vector3i targetBlock, @Nonnull final BlockMountPoint[] choices, @Nonnull final Vector3f whereWasClicked) {
        this.clean();
        double minDistSq = Double.MAX_VALUE;
        BlockMountPoint closestSeat = null;
        for (final BlockMountPoint choice : choices) {
            if (!this.entitiesByMountPoint.containsKey(choice)) {
                final Vector3f seatInWorldSpace = choice.computeWorldSpacePosition(targetBlock);
                final double distSq = whereWasClicked.distanceSquaredTo(seatInWorldSpace);
                if (distSq < minDistSq) {
                    minDistSq = distSq;
                    closestSeat = choice;
                }
            }
        }
        return closestSeat;
    }
    
    @Nonnull
    @Override
    public Component<ChunkStore> clone() {
        final BlockMountComponent seat = new BlockMountComponent();
        seat.type = this.type;
        seat.blockPos = this.blockPos;
        seat.expectedBlockType = this.expectedBlockType;
        seat.entitiesByMountPoint = new Object2ObjectOpenHashMap<BlockMountPoint, Ref<EntityStore>>(this.entitiesByMountPoint);
        seat.mountPointByEntity = new Object2ObjectOpenHashMap<Ref<EntityStore>, BlockMountPoint>(this.mountPointByEntity);
        return seat;
    }
}
