<?php
/**
 * Arr Class
 *
 * @version     1.0.$Revision:$
 * @version     SVN: $Id:$
 * @package     bplan-base/globals
 * @subpackage  Support
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 * @copyright   Copyright (C) 2025, 2026 bplan-solutions GmbH & Co. KG <https://www.bplan-solutions.de/>
 * /Δ\
 */

namespace BplanBase\Globals\Support;


/**
 * Arr Class
 *
 * Ergänzende Array-Hilfsmethoden, die in Laravel's Illuminate\Support\Arr
 * nicht vorhanden sind.
 *
 * @version     1.0.0 / 2026-05-10
 * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
 */
class Arr
{


/* +++ TRAITS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS CONSTANTS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT MEMBERS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS MEMBERS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ OBJECT METHODS +++ +++++++++++++++++++++++++++++++++++++++++++++++++++ */


/* +++ CLASS METHODS +++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ */


    /**
     * Sortiert einen Array anhand einer vorgegebenen Schlüsselreihenfolge.
     *
     * Elemente, deren Schlüssel in `$order` enthalten sind, werden gemäß der
     * Reihenfolge in `$order` neu positioniert. Alle übrigen Elemente behalten
     * ihre ursprüngliche Reihenfolge.
     *
     * Mit `$appendToEnd = true` (Standard) werden die sortierten Elemente
     * hinten angehängt: `[remaining] + [ordered]`.
     * Mit `$appendToEnd = false` werden sie vorne gestellt: `[ordered] + [remaining]`.
     *
     * Für numerisch indizierte Arrays werden die Elemente anhand ihres `name`-
     * Attributs abgeglichen. `$appendToEnd` hat dort keine Auswirkung, da
     * `usort()` eine vollständige Neuordnung vornimmt.
     *
     * @param       array  &$array
     *              Der zu sortierende Array (by reference).
     *
     * @param       array  $order
     *              Gewünschte Schlüsselreihenfolge.
     *
     * @param       bool   $appendToEnd
     *              true  → sortierte Elemente werden hinten angehängt.
     *              false → sortierte Elemente werden vorne gestellt (Standard).
     *
     * @return      void
     *
     * @version     1.0.0 / 2026-05-10
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     */
    public static function ksortArray(array & $array, array $order, bool $appendToEnd = false): void
    {
        if (empty($order) === true || empty($array) === true) {
            return;
        }

        $isNumeric = array_is_list($array);

        if ($isNumeric === true) {
            usort($array, function ($a, $b) use ($order) {
                $nameA = isset($a->name) ? $a->name : null;
                $nameB = isset($b->name) ? $b->name : null;

                $posA = ($nameA !== null) ? array_search($nameA, $order, true) : false;
                $posB = ($nameB !== null) ? array_search($nameB, $order, true) : false;

                if ($posA === false && $posB === false) {
                    return 0;
                }
                if ($posA === false) {
                    return 1;
                }
                if ($posB === false) {
                    return -1;
                }

                return $posA - $posB;
            });

        } else {
            $ordered   = [];
            $remaining = [];

            foreach ($order as $key) {
                if (array_key_exists($key, $array) === true) {
                    $ordered[$key] = $array[$key];
                }
            }

            foreach ($array as $key => $value) {
                if (array_key_exists($key, $ordered) === false) {
                    $remaining[$key] = $value;
                }
            }

            $array = ($appendToEnd === true)
                ? array_merge($remaining, $ordered)
                : array_merge($ordered, $remaining);
        }

    } // ksortArray()


    /**
     * Sortiert die Schlüssel eines Arrays.
     *
     * Die neue Reihenfolge der Schlüssel ergibt sich aus den in $sortOrder
     * angegebenen Werten. Indizies in $sortOrder, die in $array nicht existieren,
     * werden ignoriert. Schlüssel die in $sortOrder nicht definiert sind, werden
     * in ihrer ursprünglichen Reihenfolge hinten angehängt.
     *      Beispiel:
     *          $array = array('rot' => 1, 'schwarz' => 1, 'gold' => 1);
     *          $sortOrder = array('schwarz', 'rot');
     *
     *          ksort_array($array, $sortOrder);
     *
     *      Ergebnis:
     *              array(
     *                  'schwarz' => 1,
     *                  'rot' => 1,
     *                  'gold' => 1,
     *              );
     *
     * @deprecated  Use ksortArray($array, $sortOrder) instead.
     *
     * @param       array $array
     *
     * @param       array $sortOrder
     *
     * @version     1.0.0 / 2026-05-10
     * @author      Wassilios Meletiadis <wassilios.meletiadis@bplan-solutions.de>
     *
     */
    public static function ksortByArray(array & $array, array $sortOrder): void
    {
        $sorted = array();

        foreach ($sortOrder as $key) {
            if (isset($array[$key])) {
                $sorted[$key] = $array[$key];

                unset($array[$key]);
            }
        }
        $array = array_merge($sorted, $array);

    } // ksortByArray()


} // class Arr {}
