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

package com.hypixel.hytale.component.task;

import java.util.concurrent.ForkJoinPool;
import java.util.function.Supplier;
import javax.annotation.Nonnull;
import java.util.concurrent.CountedCompleter;
import java.util.function.IntConsumer;

public class ParallelRangeTask<D extends IntConsumer> extends CountedCompleter<Void>
{
    public static final int PARALLELISM;
    public static final int TASK_COUNT;
    @Nonnull
    private final SubTask<D>[] subTasks;
    private int size;
    public volatile boolean running;
    
    public ParallelRangeTask(@Nonnull final Supplier<D> supplier) {
        this(null, supplier);
    }
    
    public ParallelRangeTask(final CountedCompleter<?> completer, @Nonnull final Supplier<D> supplier) {
        super(completer);
        this.subTasks = new SubTask[ParallelRangeTask.TASK_COUNT];
        for (int i = 0; i < this.subTasks.length; ++i) {
            this.subTasks[i] = new SubTask<D>(this, supplier.get());
        }
    }
    
    @Override
    public void reinitialize() {
        if (this.running) {
            throw new IllegalStateException("ParallelRangeTask has already been started");
        }
        super.reinitialize();
    }
    
    @Nonnull
    public ParallelRangeTask<D> init(int from, final int to) {
        this.reinitialize();
        final int perTask = Math.max((to - from + (this.subTasks.length - 1)) / this.subTasks.length, 1);
        this.size = 0;
        while (this.size < this.subTasks.length && from < to) {
            final int next = Math.min(from + perTask, to);
            this.subTasks[this.size].init(from, next);
            from = next;
            ++this.size;
        }
        if (from < to) {
            throw new IllegalStateException("Failed to distribute the whole range to tasks!");
        }
        return this;
    }
    
    public int size() {
        return this.size;
    }
    
    public D get(final int i) {
        return this.subTasks[i].getData();
    }
    
    public void set(final int i, final D data) {
        if (this.running) {
            throw new IllegalStateException("ParallelRangeTask has already been started");
        }
        this.subTasks[i].setData(data);
    }
    
    @Override
    public void compute() {
        this.setPendingCount(this.size - 1);
        for (int i = 0; i < this.size - 1; ++i) {
            this.subTasks[i].fork();
        }
        this.subTasks[this.size - 1].compute();
    }
    
    static {
        PARALLELISM = Math.max(ForkJoinPool.getCommonPoolParallelism(), 1);
        TASK_COUNT = Math.max(ForkJoinPool.getCommonPoolParallelism() << 2, 1);
    }
    
    static class SubTask<D extends IntConsumer> extends CountedCompleter<Void>
    {
        private int from;
        private int to;
        private D data;
        
        SubTask(final ParallelRangeTask parent, final D data) {
            super(parent);
            this.data = data;
        }
        
        void init(final int from, final int to) {
            this.reinitialize();
            this.from = from;
            this.to = to;
        }
        
        D getData() {
            return this.data;
        }
        
        void setData(final D data) {
            this.data = data;
        }
        
        @Override
        public void compute() {
            for (int i = this.from; i < this.to; ++i) {
                this.data.accept(i);
            }
            this.propagateCompletion();
        }
    }
}
