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

package com.hypixel.hytale.builtin.deployables.component;

import com.hypixel.hytale.server.core.entity.knockback.KnockbackComponent;
import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent;
import com.hypixel.hytale.server.core.modules.entity.damage.DamageCause;
import com.hypixel.hytale.server.core.modules.entity.damage.Damage;
import com.hypixel.hytale.builtin.deployables.config.DeployableConfig;
import java.util.Iterator;
import java.util.Collection;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
import com.hypixel.hytale.server.core.universe.world.World;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.builtin.deployables.DeployablesPlugin;
import com.hypixel.hytale.component.ComponentType;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.Ref;
import it.unimi.dsi.fastutil.Pair;
import java.util.List;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Component;

public class DeployableOwnerComponent implements Component<EntityStore>
{
    @Nonnull
    private final List<Pair<String, Ref<EntityStore>>> deployables;
    @Nonnull
    private final Object2IntMap<String> deployableCountPerId;
    @Nonnull
    private final List<Ref<EntityStore>> deployablesForDestruction;
    private final List<Pair<String, Ref<EntityStore>>> tempDestructionList;
    
    public DeployableOwnerComponent() {
        this.deployables = new ObjectArrayList<Pair<String, Ref<EntityStore>>>();
        this.deployableCountPerId = new Object2IntOpenHashMap<String>();
        this.deployablesForDestruction = new ObjectArrayList<Ref<EntityStore>>();
        this.tempDestructionList = new ObjectArrayList<Pair<String, Ref<EntityStore>>>();
    }
    
    @Nonnull
    public static ComponentType<EntityStore, DeployableOwnerComponent> getComponentType() {
        return DeployablesPlugin.get().getDeployableOwnerComponentType();
    }
    
    private static int getMaxDeployablesForId(@Nonnull final DeployableComponent comp) {
        return comp.getConfig().getMaxLiveCount();
    }
    
    private static int getMaxDeployablesGlobal(@Nonnull final Store<EntityStore> store) {
        final World world = store.getExternalData().getWorld();
        final GameplayConfig gameplayConfig = world.getGameplayConfig();
        return gameplayConfig.getPlayerConfig().getMaxDeployableEntities();
    }
    
    public void tick(@Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        this.handleOverMaxDeployableDestruction(commandBuffer);
    }
    
    public void registerDeployable(@Nonnull final Ref<EntityStore> owner, @Nonnull final DeployableComponent deployableComp, @Nonnull final String id, @Nonnull final Ref<EntityStore> deployable, @Nonnull final Store<EntityStore> store) {
        this.deployables.add(Pair.of(id, deployable));
        this.incrementId(id);
        this.handlePerDeployableLimit(id, deployableComp);
        this.handleGlobalDeployableLimit(store, owner);
    }
    
    public void deRegisterDeployable(@Nonnull final String id, @Nonnull final Ref<EntityStore> deployable) {
        this.deployables.remove(Pair.of(id, deployable));
        this.decrementId(id);
    }
    
    private void incrementId(@Nonnull final String id) {
        if (!this.deployableCountPerId.containsKey(id)) {
            this.deployableCountPerId.put(id, 1);
            return;
        }
        this.deployableCountPerId.put(id, this.deployableCountPerId.getInt(id) + 1);
    }
    
    private void decrementId(@Nonnull final String id) {
        if (!this.deployableCountPerId.containsKey(id)) {
            this.deployableCountPerId.put(id, 0);
            return;
        }
        this.deployableCountPerId.put(id, this.deployableCountPerId.getInt(id) - 1);
    }
    
    private int getCurrentDeployablesById(@Nonnull final String id) {
        return this.deployableCountPerId.getOrDefault(id, 0);
    }
    
    private void handlePerDeployableLimit(@Nonnull final String id, @Nonnull final DeployableComponent deployableComponent) {
        final int limit = getMaxDeployablesForId(deployableComponent);
        final int current = this.getCurrentDeployablesById(id);
        if (current <= limit) {
            return;
        }
        int diff = current - limit;
        this.tempDestructionList.clear();
        for (final Pair<String, Ref<EntityStore>> deployablePair : this.deployables) {
            if (deployablePair.key().equals(id)) {
                this.deployablesForDestruction.add(deployablePair.value());
                this.tempDestructionList.add(deployablePair);
                --diff;
            }
            if (diff <= 0) {
                break;
            }
        }
        this.deployables.removeAll(this.tempDestructionList);
        this.tempDestructionList.clear();
    }
    
    private void handleGlobalDeployableLimit(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> owner) {
        final int limit = 1;
        int current = 0;
        for (final Pair<String, Ref<EntityStore>> deployablePair : this.deployables) {
            final DeployableComponent deployableComponent = store.getComponent(deployablePair.value(), DeployableComponent.getComponentType());
            assert deployableComponent != null;
            final DeployableConfig deployableConfig = deployableComponent.getConfig();
            if (!deployableConfig.getCountTowardsGlobalLimit()) {
                continue;
            }
            ++current;
        }
        if (current <= 1) {
            return;
        }
        int diff = current - 1;
        this.tempDestructionList.clear();
        for (final Pair<String, Ref<EntityStore>> deployablePair2 : this.deployables) {
            final Ref<EntityStore> deployableRef = deployablePair2.value();
            final DeployableComponent deployableComponent2 = store.getComponent(deployableRef, DeployableComponent.getComponentType());
            assert deployableComponent2 != null;
            final DeployableConfig deployableConfig2 = deployableComponent2.getConfig();
            if (!deployableConfig2.getCountTowardsGlobalLimit()) {
                continue;
            }
            this.deployablesForDestruction.add(deployableRef);
            this.tempDestructionList.add(deployablePair2);
            if (--diff <= 0) {
                break;
            }
        }
        this.deployables.removeAll(this.tempDestructionList);
        this.tempDestructionList.clear();
    }
    
    private void handleOverMaxDeployableDestruction(@Nonnull final CommandBuffer<EntityStore> commandBuffer) {
        if (this.deployablesForDestruction.isEmpty()) {
            return;
        }
        for (final Ref<EntityStore> deployableEntityRef : this.deployablesForDestruction) {
            DeathComponent.tryAddComponent(commandBuffer, deployableEntityRef, new Damage(Damage.NULL_SOURCE, DamageCause.COMMAND, 0.0f));
        }
        this.deployablesForDestruction.clear();
    }
    
    @Override
    public Component<EntityStore> clone() {
        return new KnockbackComponent();
    }
}
