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

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

import javax.annotation.Nullable;
import java.util.function.IntConsumer;
import com.hypixel.hytale.component.task.ParallelTask;
import com.hypixel.hytale.component.CommandBuffer;
import com.hypixel.hytale.component.Store;
import javax.annotation.Nonnull;
import com.hypixel.hytale.component.ArchetypeChunk;
import com.hypixel.hytale.component.task.ParallelRangeTask;

public abstract class EntityTickingSystem<ECS_TYPE> extends ArchetypeTickingSystem<ECS_TYPE>
{
    protected static boolean maybeUseParallel(final int archetypeChunkSize, final int taskCount) {
        return false;
    }
    
    protected static boolean useParallel(final int archetypeChunkSize, final int taskCount) {
        return taskCount > 0 || archetypeChunkSize > ParallelRangeTask.PARALLELISM;
    }
    
    public boolean isParallel(final int archetypeChunkSize, final int taskCount) {
        return false;
    }
    
    @Override
    public void tick(final float dt, @Nonnull final ArchetypeChunk<ECS_TYPE> archetypeChunk, @Nonnull final Store<ECS_TYPE> store, @Nonnull final CommandBuffer<ECS_TYPE> commandBuffer) {
        doTick(this, dt, archetypeChunk, store, commandBuffer);
    }
    
    public abstract void tick(final float p0, final int p1, @Nonnull final ArchetypeChunk<ECS_TYPE> p2, @Nonnull final Store<ECS_TYPE> p3, @Nonnull final CommandBuffer<ECS_TYPE> p4);
    
    public static <ECS_TYPE> void doTick(@Nonnull final EntityTickingSystem<ECS_TYPE> system, final float dt, @Nonnull final ArchetypeChunk<ECS_TYPE> archetypeChunk, @Nonnull final Store<ECS_TYPE> store, @Nonnull final CommandBuffer<ECS_TYPE> commandBuffer) {
        final int archetypeChunkSize = archetypeChunk.size();
        if (archetypeChunkSize == 0) {
            return;
        }
        final ParallelTask<SystemTaskData<ECS_TYPE>> task = store.getParallelTask();
        if (system.isParallel(archetypeChunkSize, task.size())) {
            final ParallelRangeTask<SystemTaskData<ECS_TYPE>> systemTask = task.appendTask();
            systemTask.init(0, archetypeChunkSize);
            for (int i = 0, systemTaskSize = systemTask.size(); i < systemTaskSize; ++i) {
                systemTask.get(i).init(system, dt, archetypeChunk, store, commandBuffer.fork());
            }
            return;
        }
        for (int index = 0; index < archetypeChunkSize; ++index) {
            system.tick(dt, index, archetypeChunk, store, commandBuffer);
        }
    }
    
    public static class SystemTaskData<ECS_TYPE> implements IntConsumer
    {
        @Nullable
        private EntityTickingSystem<ECS_TYPE> system;
        private float dt;
        @Nullable
        private ArchetypeChunk<ECS_TYPE> archetypeChunk;
        @Nullable
        private Store<ECS_TYPE> store;
        @Nullable
        private CommandBuffer<ECS_TYPE> commandBuffer;
        
        public void init(final EntityTickingSystem<ECS_TYPE> system, final float dt, final ArchetypeChunk<ECS_TYPE> archetypeChunk, final Store<ECS_TYPE> store, final CommandBuffer<ECS_TYPE> commandBuffer) {
            this.system = system;
            this.dt = dt;
            this.archetypeChunk = archetypeChunk;
            this.store = store;
            this.commandBuffer = commandBuffer;
        }
        
        @Override
        public void accept(final int index) {
            assert this.commandBuffer.setThread();
            this.system.tick(this.dt, index, this.archetypeChunk, this.store, this.commandBuffer);
        }
        
        public void clear() {
            this.system = null;
            this.archetypeChunk = null;
            this.store = null;
            this.commandBuffer = null;
        }
        
        public static <ECS_TYPE> void invokeParallelTask(@Nonnull final ParallelTask<SystemTaskData<ECS_TYPE>> parallelTask, @Nonnull final CommandBuffer<ECS_TYPE> commandBuffer) {
            final int parallelTaskSize = parallelTask.size();
            if (parallelTaskSize <= 0) {
                return;
            }
            parallelTask.doInvoke();
            for (int x = 0; x < parallelTaskSize; ++x) {
                final ParallelRangeTask<SystemTaskData<ECS_TYPE>> systemTask = parallelTask.get(x);
                for (int i = 0, systemTaskSize = systemTask.size(); i < systemTaskSize; ++i) {
                    final SystemTaskData<ECS_TYPE> taskData = systemTask.get(i);
                    taskData.commandBuffer.mergeParallel(commandBuffer);
                    taskData.clear();
                }
            }
        }
    }
}
