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

package com.hypixel.hytale.builtin.hytalegenerator;

import java.util.function.BiFunction;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;

public class ArrayUtil
{
    @Nonnull
    public static <T> T[] brokenCopyOf(@Nonnull final T[] a) {
        final T[] copy = (T[])new Object[a.length];
        System.arraycopy(a, 0, copy, 0, a.length);
        return copy;
    }
    
    public static <T> void copy(@Nonnull final T[] source, @Nonnull final T[] destination) {
        if (source.length != destination.length) {
            throw new IllegalArgumentException("arrays must have the same size");
        }
        System.arraycopy(source, 0, destination, 0, source.length);
    }
    
    @Nonnull
    public static <T> T[] append(@Nonnull final T[] a, final T e) {
        final T[] expanded = (T[])new Object[a.length + 1];
        System.arraycopy(a, 0, expanded, 0, a.length);
        expanded[a.length] = e;
        return expanded;
    }
    
    @Nonnull
    public static <T> List<List<T>> split(@Nonnull final List<T> list, final int partCount) {
        if (partCount < 1) {
            throw new IllegalArgumentException("parts must be greater than 0");
        }
        if (partCount == 1) {
            return Collections.singletonList(list);
        }
        final List<List<T>> out = new ArrayList<List<T>>(partCount);
        final int listSize = list.size();
        if (listSize <= partCount) {
            for (int i = 0; i < listSize; ++i) {
                out.add(List.of(list.get(i)));
            }
            for (int i = listSize; i < partCount; ++i) {
                out.add(List.of());
            }
            return out;
        }
        final int[] partSizes = getPartSizes(listSize, partCount);
        int elementIndex = 0;
        for (final int partSize : partSizes) {
            final List<T> partList = new ArrayList<T>(partSize);
            for (int j = 0; j < partSize; ++j) {
                partList.add(list.get(elementIndex++));
            }
            out.add(partList);
        }
        return out;
    }
    
    public static int[] getPartSizes(final int total, final int partCount) {
        if (total < 0 || partCount < 1) {
            throw new IllegalArgumentException("total and/or parts must be greater than 0");
        }
        if (total == 0) {
            return new int[] { total };
        }
        final int[] sizes = new int[partCount];
        final int baseSize = total / partCount;
        final int remainder = total % partCount;
        for (int i = 0; i < partCount; ++i) {
            if (i < remainder) {
                sizes[i] = baseSize + 1;
            }
            else {
                sizes[i] = baseSize;
            }
        }
        return sizes;
    }
    
    public static <T, G> int sortedSearch(@Nonnull final List<T> sortedList, @Nonnull final G gauge, @Nonnull final BiFunction<G, T, Integer> comparator) {
        final int BINARY_SIZE_THRESHOLD = 250;
        if (sortedList.isEmpty()) {
            return -1;
        }
        if (sortedList.size() == 1) {
            if (comparator.apply(gauge, sortedList.getFirst()) == 0) {
                return 0;
            }
            return -1;
        }
        else {
            if (sortedList.size() <= 250) {
                for (int i = 0; i < sortedList.size(); ++i) {
                    if (comparator.apply(gauge, sortedList.get(i)) == 0) {
                        return i;
                    }
                }
                return -1;
            }
            return binarySearch((List<Object>)sortedList, gauge, (BiFunction<Object, Object, Integer>)comparator);
        }
    }
    
    public static <T, G> int binarySearch(@Nonnull final List<T> sortedList, @Nonnull final G gauge, @Nonnull final BiFunction<G, T, Integer> comparator) {
        if (sortedList.isEmpty()) {
            return -1;
        }
        int min = 0;
        int max = sortedList.size();
        while (true) {
            final int index = (max + min) / 2;
            final T item = sortedList.get(index);
            final int comparison = comparator.apply(gauge, item);
            if (comparison == 0) {
                return index;
            }
            if (min == max - 1) {
                return -1;
            }
            if (comparison == -1) {
                max = index;
            }
            if (comparison != 1) {
                continue;
            }
            min = index;
        }
    }
}
