<?PHP
/**
 * Generic collection of functions used in CSVXML.
 *
 * @file
 *
 * @author
 */
declare(strict_types = 1);

// Set autoloader
# \error_reporting(E_ALL);
# \ini_set('display_errors', "1");
\spl_autoload_register("mdCsvxmlAutoloader");
\set_exception_handler("mdExceptionHandler");
\set_error_handler("mdErrorHandler", E_ALL);

require_once __DIR__ . '/../inc/constants.php';
require_once __DIR__ . '/../vendor/autoload.php';

/**
 * Autoloader for museum-digital.org.
 *
 * @param string $className Name of the class to load.
 *
 * @return void
 */
function mdCsvxmlAutoloader(string $className):void {

    // Try using class map as defined through /scripts/buildClassMap.php

    if (isset(AUTOLOAD_CLASS_MAP[$className])) {
        include AUTOLOAD_CLASS_MAP[$className];
        return;
    }

    // Fallback: Load classes by autoload directories

    foreach (AUTOLOAD_DIRS as $classDir) {
        if (\file_exists("$classDir/$className.php")) {
            include "$classDir/$className.php";
            return;
        }
    }

}

/**
 * Own error handler: Set to enforce exit on any error.
 *
 * @param integer $errno  Error number.
 * @param string  $string Error message.
 * @param string  $file   File in which the error occured.
 * @param integer $line   Line number.
 *
 * @return void
 */
function mdErrorHandler(int $errno, string $string, string $file, int $line):void {

    $getStr = [];
    foreach ($_GET as $key => $value) {
        if (is_array($value)) continue;
        $getStr[] = $key . "=" . $value;
    }

    $userMsg = "";
    if (isset($_SESSION['anmnam']))   $userMsg .= " User: " . $_SESSION["anmnam"];
    if (isset($_SESSION['username'])) $userMsg .= " (" . $_SESSION["username"] . ")";
    if ($userMsg) $userMsg = " |--" . $userMsg;

    $errorMsg = "";

    if (!empty($_SERVER) && !empty($_SERVER["HTTP_HOST"])) {

        $errorPage = $_SERVER['PHP_SELF'] . "?" . implode("&", $getStr);
        $errorPageFull   = "https://" . $_SERVER["HTTP_HOST"] . $errorPage;

        $errorMsg  = "*$errno (<a href='https://www.google.de/search?q=php+" . str_replace(" ", "+", $string) . "'>$string</a>) at $file: line_ $line _";
        $errorMsg .= $userMsg;
        $errorMsg .= " |-- Error generating page: <a href='$errorPageFull'>$errorPage</a>";
        $errorMsg .= " |-- Used RAM / Peak RAM / Allowed: " . MD_STD::human_filesize(memory_get_usage()) . " / " . MD_STD::human_filesize(memory_get_peak_usage()) . " / " . ini_get("memory_limit");

        $errorMsg = str_replace(PHP_EOL, " ", $errorMsg);

        error_log($errorMsg);

    }

    if ($errno == E_ERROR) exit;

}

/**
 * Exception handler to also be able to handle custom exceptions.
 *
 * @param Throwable $exception Exception.
 *
 * @return void
 */
function mdExceptionHandler(Throwable $exception):void {

    $formatErrorPage = function(string $errorMsg = "", string $versionName = "") :string {

        if (PHP_SAPI === "cli") {
            return $errorMsg . PHP_EOL;
        }

        $output = '<!DOCTYPE html>
<html id="errorPage">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <meta name="description" content="Validate import CSV files for museum-digital" />
    <link rel="manifest" href="./manifest.webmanifest" />
    <link rel="stylesheet" type="text/css" href="assets/css/csvxml.min.css" />
    <meta name="theme-color" content="#aa4400" />
    <meta name="robots" content="noindex" />
    <link rel="shortcut icon" sizes="128x128" href="assets/img/mdlogo-csvxml.svg" />';
        $output .= '
    <title>Error :: ';
        $output .= $versionName;
        $output .= '</title>
</head>
<body>

    <main>
        <img src="/assets/img/mdlogo-csvxml.svg" alt="" />
        <p>' . $errorMsg . '</p>

        <nav>
            <a href="index.php?t=home">Home</a>
            <a href="index.php?t=museum">Museum</a>
            <a href="index.php?t=collection">Collection</a>
            <a href="index.php?t=exhibitions_overview">Exhibition</a>
            <a href="index.php?t=events">Event</a>
            <a href="index.php?t=topics">Topics</a>
            <a href="index.php?t=listen&sv=+&done=yes">Objects</a>
        </nav>
        <nav>
            <a href="index.php?t=kontakt">Contact</a>
            <a href="index.php?t=impressum">Impressum</a>
            <a href="index.php?t=privacy">Privacy Policy</a>
        </nav>
    </main>

</body>
</html>';

        return $output;
    };

    $errorReporter = new MDErrorReporter("md:csvxml", "bugs-csvxml@museum-digital.de");
    $errorCategory = MDErrorReporter::categorizeError($exception);

    http_response_code(404);

    switch ($errorCategory) {
    case MDErrorReporter::MD_ERROR_KNOWN:

        if (isset($_GET["output"]) and $_GET['output'] === "json") {
            header('Content-type: application/json');
            $output = [
                "status" => "Error",
                "msg"    => $exception->getMessage(),
            ];
            echo MD_STD::json_encode($output);
            exit;
        }

        echo $formatErrorPage($exception->getMessage(), "");
        exit;

    default:
        $errorReporter->sendErrorReport($exception, "joshua@museum-digital.de");
        echo $formatErrorPage("Uncaught exception ...<br />Our team has been notified and will get to fixing this error shortly.", "");
        exit;
    }

}

/**
 * Function for generating the HTML head.
 *
 * @param string $injected Additional code to inject into the head, e.g. a
 *                         reference to JS files.
 *
 * @return string
 */
function printHTMLHead(string $injected = ""):string {

    $output = '<!DOCTYPE HTML>
<html lang="en">
<head>

    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <meta name="description" content="Validate import CSV files for museum-digital" />

    <link rel="stylesheet" type="text/css" href="assets/css/csvxml.min.css" />
    <meta name="theme-color" content="#aa4400" />
    <link rel="shortcut icon" sizes="128x128" href="assets/img/mdlogo-csvxml.svg" />
    <script src="assets/js/csvxml-overview.min.js" type="text/javascript" defer></script>
    <meta name="robots" content="noindex" />

    <title>CSVXML :: museum-digital</title>

    <meta name="keywords" content="Imports, museum-digital" />
';

    $output .= $injected;

    $output .= '

</head>
<body>

<h1>
    <img src="assets/img/mdlogo-csvxml.svg" alt="" />
    <span>museum-digital:csvxml</span>
</h1>
';

    return $output;

}

/**
 * Function generateHelpTooltip returns a tooltip for hovering over using the common settings.
 *
 * @param string  $identifier   ID attribute of the tooltip.
 * @param string  $title        Title of the tooltip.
 * @param string  $explica      More in-depth explanation: body of the tooltip.
 * @param boolean $setParagraph If set to true (default), the content of the tooltip will be put into a <p> element. Optional.
 *
 * @return array
 */
function generateHelpTooltip(string $identifier, string $title, string $explica, bool $setParagraph = true):array {

    $outputTag = '<a class="newToolTipTag icons iconsHelp" data-for="' . $identifier . '" title="Help"></a>';
    $output = '<span class="newToolTip" id="tooltip_' . $identifier . '" data-title="' . $title . '">';
    if ($setParagraph) $output .= '<p class="toolTipCont">';
    $output .= $explica;
    if ($setParagraph) $output .= '</p>';
    $output .= '</span>';

    return [$output, $outputTag];

}

/**
 * Outputs a DOMDocument with correct header and then aborts.
 * Used mainly for debugging.
 *
 * @param DOMDocument $xmlDoc XML object.
 *
 * @return string
 */
function printDOMDocToXML(DOMDocument $xmlDoc):string {

    return '<?xml version="1.0" encoding="UTF-8"?>' . $xmlDoc->saveXML($xmlDoc->documentElement);

}

/**
 * Function for creating a DOMElement with a text node inside.
 *
 * @param DOMDocument $xmlDoc  XML document.
 * @param string      $tag     Tag.
 * @param string      $content Text content.
 *
 * @return DOMElement
 */
function createTextDomElement(DOMDocument $xmlDoc, string $tag, string $content):DOMElement {

    try {
        $element = $xmlDoc->createElement($tag);
    }
    catch (DOMException $e) {
        echo "Error at " . __FILE__ . ", line #" . __LINE__ . PHP_EOL . "<br/>";
        echo "Cannot create DOM element for $tag / $content";
        exit;
    }

    $element->appendChild($xmlDoc->createTextNode($content));

    return $element;

}

/**
 * Function for creating a DOMDocument record channel.
 *
 * @return array
 */
function getBlankRecordChannel():array {

    $xmlDoc = new DOMDocument("1.0", "UTF-8");
    $xmlMainElem = $xmlDoc->createElement("record");
    $record_node = $xmlDoc->appendChild($xmlMainElem); //add RSS element to XML node

    return [$xmlDoc, $record_node];

}

/**
 * Function for removing a directory with all its contents.
 *
 * @param string $dir File path of the directory to remove.
 *
 * @return void
 */
function rrmdir(string $dir):void {
    if (is_dir($dir)) {
        $objects = scandir($dir);
        foreach ($objects as $object) {
            if ($object != "." && $object != "..") {
                if (filetype($dir . "/" . $object) == "dir") rrmdir($dir . "/" . $object);
                else unlink($dir . "/" . $object);
            }
        }
        reset($objects);
        rmdir($dir);
    }

}

/**
 * Function for checking if two arrays have identical values / contents.
 *
 * @param array $arrayA First array to compare.
 * @param array $arrayB Second array to compare.
 *
 * @return boolean
 */
function identical_values(array $arrayA, array $arrayB):bool {
    sort($arrayA);
    sort($arrayB);
    return $arrayA == $arrayB;

}