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

package com.hypixel.hytale.server.core.entity.group;

import java.util.Collection;
import java.util.function.Predicate;
import com.hypixel.hytale.function.consumer.IntBiObjectConsumer;
import com.hypixel.hytale.function.consumer.IntTriObjectConsumer;
import com.hypixel.hytale.function.consumer.QuadConsumer;
import com.hypixel.hytale.function.consumer.TriConsumer;
import com.hypixel.hytale.server.core.modules.entity.EntityModule;
import com.hypixel.hytale.component.ComponentType;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.HashSet;
import javax.annotation.Nullable;
import java.util.List;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.Ref;
import java.util.Set;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.Component;

public class EntityGroup implements Component<EntityStore>
{
    @Nonnull
    private final Set<Ref<EntityStore>> memberSet;
    @Nonnull
    private final List<Ref<EntityStore>> memberList;
    @Nullable
    private Ref<EntityStore> leaderRef;
    private boolean dissolved;
    
    public EntityGroup() {
        this.memberSet = new HashSet<Ref<EntityStore>>();
        this.memberList = new ObjectArrayList<Ref<EntityStore>>();
    }
    
    public static ComponentType<EntityStore, EntityGroup> getComponentType() {
        return EntityModule.get().getEntityGroupComponentType();
    }
    
    @Nullable
    public Ref<EntityStore> getLeaderRef() {
        return this.leaderRef;
    }
    
    public void setLeaderRef(@Nonnull final Ref<EntityStore> leaderRef) {
        this.leaderRef = leaderRef;
    }
    
    public void add(@Nonnull final Ref<EntityStore> reference) {
        if (!this.memberSet.add(reference)) {
            throw new IllegalStateException("Attempting to add entity " + String.valueOf(reference) + " that is already a member of the group!");
        }
        this.memberList.add(reference);
    }
    
    public void remove(@Nonnull final Ref<EntityStore> reference) {
        if (!this.memberSet.remove(reference)) {
            throw new IllegalStateException("Attempting to remove entity " + String.valueOf(reference) + " that is not a member of the group!");
        }
        this.memberList.remove(reference);
    }
    
    @Nullable
    public Ref<EntityStore> getFirst() {
        return this.memberList.isEmpty() ? null : this.memberList.getFirst();
    }
    
    @Nonnull
    public List<Ref<EntityStore>> getMemberList() {
        return this.memberList;
    }
    
    public int size() {
        return this.memberSet.size();
    }
    
    public boolean isDissolved() {
        return this.dissolved;
    }
    
    public void setDissolved(final boolean dissolved) {
        this.dissolved = dissolved;
    }
    
    public void clear() {
        this.memberSet.clear();
        this.memberList.clear();
        this.leaderRef = null;
        this.dissolved = true;
    }
    
    public boolean isMember(final Ref<EntityStore> reference) {
        return !this.dissolved && this.memberSet.contains(reference);
    }
    
    public <T> void forEachMemberExcludingLeader(@Nonnull final TriConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T arg) {
        this.forEachMember(consumer, sender, arg, this.leaderRef);
    }
    
    public <T> void forEachMemberExcludingSelf(@Nonnull final TriConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T arg) {
        this.forEachMember(consumer, sender, arg, sender);
    }
    
    public <T> void forEachMember(@Nonnull final TriConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T arg) {
        this.forEachMember(consumer, sender, arg, null);
    }
    
    public <T> void forEachMember(@Nonnull final TriConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T arg, final Ref<EntityStore> excludeReference) {
        for (int i = 0; i < this.memberList.size(); ++i) {
            final Ref<EntityStore> member = this.memberList.get(i);
            if (member.isValid()) {
                if (!member.equals(excludeReference)) {
                    consumer.accept(member, sender, arg);
                }
            }
        }
    }
    
    public <T, V> void forEachMemberExcludingLeader(@Nonnull final QuadConsumer<Ref<EntityStore>, Ref<EntityStore>, T, V> consumer, final Ref<EntityStore> sender, final T t, final V v) {
        this.forEachMember(consumer, sender, t, v, this.leaderRef);
    }
    
    public <T, V> void forEachMemberExcludingSelf(@Nonnull final QuadConsumer<Ref<EntityStore>, Ref<EntityStore>, T, V> consumer, final Ref<EntityStore> sender, final T t, final V v) {
        this.forEachMember(consumer, sender, t, v, sender);
    }
    
    public <T, V> void forEachMember(@Nonnull final QuadConsumer<Ref<EntityStore>, Ref<EntityStore>, T, V> consumer, final Ref<EntityStore> sender, final T t, final V v) {
        this.forEachMember(consumer, sender, t, v, null);
    }
    
    public <T, V> void forEachMember(@Nonnull final QuadConsumer<Ref<EntityStore>, Ref<EntityStore>, T, V> consumer, final Ref<EntityStore> sender, final T t, final V v, final Ref<EntityStore> excludeReference) {
        for (int i = 0; i < this.memberList.size(); ++i) {
            final Ref<EntityStore> member = this.memberList.get(i);
            if (member.isValid()) {
                if (!member.equals(excludeReference)) {
                    consumer.accept(member, sender, t, v);
                }
            }
        }
    }
    
    public <T, V> void forEachMemberExcludingLeader(@Nonnull final IntTriObjectConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T t, final int value) {
        this.forEachMember(consumer, sender, t, value, this.leaderRef);
    }
    
    public <T, V> void forEachMemberExcludingSelf(@Nonnull final IntTriObjectConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, @Nonnull final Ref<EntityStore> sender, final T t, final int value) {
        this.forEachMember(consumer, sender, t, value, sender);
    }
    
    public <T> void forEachMember(@Nonnull final IntTriObjectConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T t, final int value) {
        this.forEachMember(consumer, sender, t, value, null);
    }
    
    public <T> void forEachMember(@Nonnull final IntTriObjectConsumer<Ref<EntityStore>, Ref<EntityStore>, T> consumer, final Ref<EntityStore> sender, final T t, final int value, final Ref<EntityStore> excludeReference) {
        for (int i = 0; i < this.memberList.size(); ++i) {
            final Ref<EntityStore> member = this.memberList.get(i);
            if (member.isValid()) {
                if (!member.equals(excludeReference)) {
                    consumer.accept(value, member, sender, t);
                }
            }
        }
    }
    
    public <T> void forEachMember(@Nonnull final IntBiObjectConsumer<Ref<EntityStore>, T> consumer, final T t) {
        for (int i = 0; i < this.memberList.size(); ++i) {
            final Ref<EntityStore> member = this.memberList.get(i);
            if (member.isValid()) {
                consumer.accept(i, member, t);
            }
        }
    }
    
    @Nullable
    public Ref<EntityStore> testMembers(@Nonnull final Predicate<Ref<EntityStore>> predicate, final boolean skipLeader) {
        for (int i = 0; i < this.memberList.size(); ++i) {
            final Ref<EntityStore> member = this.memberList.get(i);
            if (member.isValid() && (!skipLeader || !member.equals(this.leaderRef)) && predicate.test(member)) {
                return member;
            }
        }
        return null;
    }
    
    @Nonnull
    @Override
    public Component<EntityStore> clone() {
        final EntityGroup group = new EntityGroup();
        group.memberSet.addAll(this.memberSet);
        group.memberList.addAll(this.memberList);
        group.leaderRef = this.leaderRef;
        group.dissolved = this.dissolved;
        return group;
    }
    
    @Nonnull
    @Override
    public String toString() {
        return "EntityGroup{leader=" + String.valueOf(this.leaderRef) + ", memberSet=" + String.valueOf(this.memberSet) + ", memberList=" + String.valueOf(this.memberList) + ", dissolved=" + this.dissolved;
    }
}
