import java.util.Random;

/**
 * Sammlung einfacher Array-Hilfsfunktionen für int-Arrays.
 * 
 * Entwickelt von Ulrich Helmich 11/2025.
 * Geprüft von ChatGPT 11/2025.
 * JavaDoc-Kommentare von ChatGPT 11/2025.
 */
public class ArrayTools
{
    // ------------------------------------------------------------------
    // Erzeugung & Befüllung
    // ------------------------------------------------------------------

    /**
     * Erzeugt ein int-Array mit der angegebenen Länge.
     *
     * @param laenge Länge des Arrays; bei {@code laenge <= 0} wird ein leeres Array zurückgegeben
     * @return neues int-Array der gewünschten Länge (niemals {@code null})
     */
    public static int[] erzeugeArray(int laenge)
    {
        if (laenge <= 0)
            return new int[0];

        return new int[laenge];
    }

    /**
     * Füllt die ersten {@code anzahl} Elemente des Arrays mit Zufallszahlen
     * aus dem Wertebereich [{@code min}, {@code max}].
     *
     * @param array   zu füllendes Array (muss nicht vollständig gefüllt werden)
     * @param anzahl  Anzahl der zu schreibenden Werte (wird auf {@code array.length} begrenzt)
     * @param min     untere Grenze (inklusive)
     * @param max     obere Grenze (inklusive)
     */
    public static void fuelleArrayMitZufallszahlen(int[] array, int anzahl, int min, int max)
    {
        // Plausibilitätsprüfungen
        if (array == null || anzahl <= 0 || min > max)
            return;

        Random wuerfel = new Random();
        int limit = Math.min(anzahl, array.length);

        // Füllen der ersten 'limit' Positionen
        for (int i = 0; i < limit; i++)
        {
            array[i] = wuerfel.nextInt(max - min + 1) + min; // inklusiv
        }
    }

    /**
     * Dies ist eine sogenannte Komfortmethode, sie füllt das komplette Array mit Zufallszahlen
     * aus dem inklusiven Bereich [{@code min}, {@code max}], bedient sich dabei aber der
     * zuvor definierten Methode gleichen Namens.
     *
     * @param array zu füllendes Array
     * @param min   untere Grenze (inklusive)
     * @param max   obere Grenze (inklusive)
     */
    public static void fuelleArrayMitZufallszahlen(int[] array, int min, int max)
    {
        if (array == null)
            return;

        fuelleArrayMitZufallszahlen(array, array.length, min, max);
    }

    // ------------------------------------------------------------------
    // Ausgabe
    // ------------------------------------------------------------------

    /**
     * Gibt die ersten {@code anzahl} Elemente des Arrays in Spalten aus.
     * Nach jeweils 10 Werten wird ein Zeilenumbruch eingefügt.
     *
     * @param array  Array (kann {@code null} sein)
     * @param anzahl Anzahl der auszugebenden Elemente (wird auf {@code array.length} begrenzt)
     */
    public static void zeigeArray(int[] array, int anzahl)
    {
        if (array == null || anzahl <= 0)
        {
            System.out.println("(keine Daten)");
            return;
        }

        int limit = Math.min(anzahl, array.length);

        for (int i = 0; i < limit; i++)
        {
            System.out.printf("%5d", array[i]);
            if ((i + 1) % 10 == 0)
                System.out.println();
        }
        System.out.println();
    }

    /**
     * Gibt das komplette Array aus (siehe {@link #zeigeArray(int[], int)}).
     *
     * @param array Array (kann {@code null} sein)
     */
    public static void zeigeArray(int[] array)
    {
        if (array == null)
        {
            System.out.println("(keine Daten)");
            return;
        }
        zeigeArray(array, array.length);
    }

    // ------------------------------------------------------------------
    // Sortieren
    // ------------------------------------------------------------------

    /**
     * Interner Hilfstausch (ohne Bounds-Prüfung, da nur intern genutzt).
     */
    private static void tausche(int[] array, int index1, int index2)
    {
        if (index1 == index2) // überflüssigen Tausch vermeiden
            return;

        int temp = array[index1];
        array[index1] = array[index2];
        array[index2] = temp;
    }

    /**
     * Bubblesort (aufsteigend).
     * Enthält eine kleine Optimierung: Falls in einem Durchgang nicht getauscht wurde,
     * ist das Array bereits sortiert (Frühabbruch).
     *
     * @param array zu sortierendes Array (wird in-place verändert)
     */
    public static void bubblesort(int[] array)
    {
        if (array == null || array.length < 2)
            return;

        int n = array.length;

        for (int durchgang = 0; durchgang < n - 1; durchgang++)
        {
            boolean getauscht = false;

            for (int i = 0; i < n - 1 - durchgang; i++)
            {
                if (array[i] > array[i + 1])
                {
                    tausche(array, i, i + 1);
                    getauscht = true;
                }
            }

            if (!getauscht) // bereits sortiert
                break;
        }
    }

    /**
     * Selectionsort über die ersten {@code n} Elemente (Teilarray [0, n)).
     *
     * @param array Array (darf nicht {@code null} sein)
     * @param n     Anzahl der zu sortierenden Elemente ab Index 0
     */
    public static void selectionSortTeilarray(int[] array, int n)
    {
        if (array == null || n <= 1)
            return;

        int limit = Math.min(n, array.length); 

        for (int start = 0; start < limit - 1; start++)
        {
            int miniPos = start;

            for (int i = start + 1; i < limit; i++)
            {
                if (array[i] < array[miniPos])
                    miniPos = i;
            }

            // Nur tauschen, wenn wirklich kleineres Element gefunden wurde
            if (miniPos != start)
                tausche(array, start, miniPos);
        }
    }

    // ------------------------------------------------------------------
    // Einfügen & Löschen in festen Arrays
    // ------------------------------------------------------------------

    /**
     * Löscht das Element an {@code index}, verschiebt alle rechts davon
     * liegenden Elemente um 1 nach links und setzt das letzte Element auf 0.
     *
     * @param numbers Zielarray
     * @param index   zu löschender Index (0-basiert)
     */
    public static void delete(int[] numbers, int index)
    {
        if (numbers == null || numbers.length == 0)
            return;

        if (index < 0 || index >= numbers.length)
            return;

        for (int i = index; i < numbers.length - 1; i++)
        {
            numbers[i] = numbers[i + 1];
        }

        numbers[numbers.length - 1] = 0; // „Lücke“ am Ende neutralisieren
    }

    /**
     * Fügt {@code value} an Position {@code index} ein, verschiebt alle Elemente
     * ab {@code index} um 1 nach rechts. Das letzte Element fällt dabei heraus
     * (wird überschrieben).
     *
     * @param numbers Zielarray
     * @param index   Einfügeposition (0-basiert)
     * @param value   einzufügender Wert
     */
    public static void insert(int[] numbers, int index, int value)
    {
        if (numbers == null || numbers.length == 0)
            return;

        if (index < 0 || index >= numbers.length)
            return;

        // von rechts nach links verschieben
        for (int i = numbers.length - 1; i > index; i--)
        {
            numbers[i] = numbers[i - 1];
        }

        numbers[index] = value;
    }

    // ------------------------------------------------------------------
    // Suchen & Zählen
    // ------------------------------------------------------------------

    /**
     * Prüft, ob {@code value} im Array mindestens einmal vorkommt.
     *
     * @param numbers Array
     * @param value   gesuchter Wert
     * @return {@code true}, falls gefunden; sonst {@code false}
     */
    public static boolean enthaeltWert(int[] numbers, int value)
    {
        if (numbers == null || numbers.length == 0)
            return false;

        for (int i = 0; i < numbers.length; i++)
        {
            if (numbers[i] == value)
                return true;
        }

        return false;
    }

    /**
     * Zählt, wie oft {@code value} im Array vorkommt.
     *
     * @param array Array
     * @param value gesuchter Wert
     * @return Anzahl der Vorkommen (0 bei {@code null} oder leerem Array)
     */
    public static int enthaeltWertWieOft(int[] array, int value)
    {
        if (array == null || array.length == 0)
            return 0;

        int count = 0;

        for (int i = 0; i < array.length; i++)
        {
            if (array[i] == value)
                count++;
        }

        return count;
    }
}