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

package com.hypixel.hytale.component.system.data;

import java.util.Collection;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import javax.annotation.Nullable;
import java.util.function.IntConsumer;
import com.hypixel.hytale.component.task.ParallelRangeTask;
import com.hypixel.hytale.component.task.ParallelTask;
import java.util.List;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.ArchetypeChunk;

public abstract class EntityDataSystem<ECS_TYPE, Q, R> extends ArchetypeDataSystem<ECS_TYPE, Q, R>
{
    public boolean isParallel() {
        return false;
    }
    
    @Override
    public void fetch(@Nonnull final ArchetypeChunk<ECS_TYPE> archetypeChunk, @Nonnull final Store<ECS_TYPE> store, @Nonnull final CommandBuffer<ECS_TYPE> commandBuffer, final Q query, final List<R> results) {
        doFetch(this, archetypeChunk, store, commandBuffer, query, results);
    }
    
    public abstract void fetch(final int p0, final ArchetypeChunk<ECS_TYPE> p1, final Store<ECS_TYPE> p2, final CommandBuffer<ECS_TYPE> p3, final Q p4, final List<R> p5);
    
    public static <ECS_TYPE, Q, R> void doFetch(@Nonnull final EntityDataSystem<ECS_TYPE, Q, R> system, @Nonnull final ArchetypeChunk<ECS_TYPE> archetypeChunk, @Nonnull final Store<ECS_TYPE> store, @Nonnull final CommandBuffer<ECS_TYPE> commandBuffer, final Q query, final List<R> results) {
        if (system.isParallel()) {
            final int size = archetypeChunk.size();
            if (size == 0) {
                return;
            }
            final ParallelTask<SystemTaskData<ECS_TYPE, ?, ?>> task = store.getFetchTask();
            final ParallelRangeTask<SystemTaskData<ECS_TYPE, ?, ?>> systemTask = task.appendTask();
            systemTask.init(0, size);
            for (int i = 0, systemTaskSize = systemTask.size(); i < systemTaskSize; ++i) {
                systemTask.get(i).init(system, archetypeChunk, store, commandBuffer.fork(), query);
            }
        }
        else {
            for (int index = 0, archetypeChunkSize = archetypeChunk.size(); index < archetypeChunkSize; ++index) {
                system.fetch(index, archetypeChunk, store, commandBuffer, query, results);
            }
        }
    }
    
    public static class SystemTaskData<ECS_TYPE, Q, R> implements IntConsumer
    {
        private final List<R> results;
        @Nullable
        private EntityDataSystem<ECS_TYPE, Q, R> system;
        @Nullable
        private ArchetypeChunk<ECS_TYPE> archetypeChunk;
        @Nullable
        private Store<ECS_TYPE> store;
        @Nullable
        private CommandBuffer<ECS_TYPE> commandBuffer;
        @Nullable
        private Q query;
        
        public SystemTaskData() {
            this.results = new ObjectArrayList<R>();
        }
        
        public void init(final EntityDataSystem<ECS_TYPE, Q, R> system, final ArchetypeChunk<ECS_TYPE> archetypeChunk, final Store<ECS_TYPE> store, final CommandBuffer<ECS_TYPE> commandBuffer, final Q query) {
            this.system = system;
            this.archetypeChunk = archetypeChunk;
            this.store = store;
            this.commandBuffer = commandBuffer;
            this.query = query;
        }
        
        @Override
        public void accept(final int index) {
            assert this.commandBuffer.setThread();
            this.system.fetch(index, this.archetypeChunk, this.store, this.commandBuffer, this.query, this.results);
        }
        
        public void clear() {
            this.system = null;
            this.archetypeChunk = null;
            this.store = null;
            this.commandBuffer = null;
            this.query = null;
            this.results.clear();
        }
        
        public static <ECS_TYPE, Q, R> void invokeParallelTask(@Nonnull final ParallelTask<SystemTaskData<ECS_TYPE, Q, R>> parallelTask, @Nonnull final CommandBuffer<ECS_TYPE> commandBuffer, @Nonnull final List<R> results) {
            final int parallelTaskSize = parallelTask.size();
            if (parallelTaskSize > 0) {
                parallelTask.doInvoke();
                for (int x = 0; x < parallelTaskSize; ++x) {
                    final ParallelRangeTask<SystemTaskData<ECS_TYPE, Q, R>> systemTask = parallelTask.get(x);
                    for (int i = 0, systemTaskSize = systemTask.size(); i < systemTaskSize; ++i) {
                        final SystemTaskData<ECS_TYPE, Q, R> taskData = systemTask.get(i);
                        results.addAll((Collection<? extends R>)taskData.results);
                        taskData.commandBuffer.mergeParallel(commandBuffer);
                        taskData.clear();
                    }
                }
            }
        }
    }
}
