<?php

declare(strict_types=1);

/**
 * This file is part of LEPTON Core, released under the GNU GPL
 * Please see LICENSE and COPYING files in your package for details, specially for terms and warranties.
 * 
 * NOTICE:LEPTON CMS Package has several different licenses.
 * Please see the individual license in the header of each single file or info.php of modules and templates.
 *
 * @author          LEPTON Project
 * @copyright       2010-2026 LEPTON Project
 * @link            https://lepton-cms.org
 * @license         https://gnu.org/licenses/gpl.html
 * @license_terms   please see LICENSE and COPYING files in your package
 *
 */


/**
 *  Class to handle the "admin" in the backend.
 *  The basic "jobs" of this class is e.g. to build/construct the mainmenu
 *  and the footer of the backend-interface.
 *
 */
class LEPTON_admin extends LEPTON_core
{

    /**
     *  The db-handle of this class.
     *
     *  @access	private
     *  @type   LEPTON_database Instance
     */
    private LEPTON_database $database;
	
    /**
     *  Public header storage for external/internal files of the used modules.
     *
     *  @access	public
     *  @type   array
     */
    public array $header_storage = [
        'css' => [],
        'js' => [],
        'html' => [],
        'modules' => []
    ];

    /**
     *  Output storage, needed e.g. inside method print_footer for the leptoken-hashes and/or droplets.
     *
     *  @access	private
     *  @type   string
     */
    private string $html_output_storage = "";

    /**
     *	Private flag for the droplets.
     *
     *	@access	private
     *  @type   boolean
     */
    private bool $droplets_ok = false;

    private array $adminTools = [];
    
    protected string $section_name = "";
    protected string $section_permission = "";

    /**
     * Internal Twig-template-engine instance
     * @var lib_twig_box|null
     * @since 4.3
     */
    public ?lib_twig_box $oTWIG = null;
    
    /**
     *  @type    object  The reference to the *Singleton* instance of this class.
     *  @notice         Keep in mind that a child-object has to have his own one!
     */
    public static $instance;

    /**
     *  Return the singleton instance of this class.
     *
     *	@param	string  $section_name       The section name.
     *	@param	string  $section_permission The section permissions belongs too.
     *	@param	bool    $auto_header        Boolean to print out the header. Default is 'true'.
     *	@param	bool    $auto_auth          Boolean for the auto authentication. Default is 'true'.
     *
     * @return object                      The generated instance of theis class
     */

    #[\Override]
    public static function getInstance(): object
    {
        if (null === static::$instance)
        {
            $section_name       = "Pages";
            $section_permission = "start";
            $auto_header        = true;
            $auto_auth          = true;

            switch( func_num_args() )
            {
                case 1:
                    $section_name = func_get_arg(0);
                    break;
                case 2:
                    $section_name = func_get_arg(0);
                    $section_permission = func_get_arg(1);
                    break;
                case 3:
                    $section_name = func_get_arg(0);
                    $section_permission = func_get_arg(1);
                    $auto_header = func_get_arg(2);
                    break;
                case 4:
                    $section_name = func_get_arg(0);
                    $section_permission = func_get_arg(1);
                    $auto_header = func_get_arg(2);
                    $auto_auth = func_get_arg(3);
                    break;
                default:
                    // nothing
                    break;
            }
            static::$instance = new static($section_name, $section_permission, $auto_header, $auto_auth);
        }
        return static::$instance;
    }
    
    /**
     *	Constructor of the class
     *
     *	Authenticate user then auto print the header
     *
     *	@param	string  $section_name       The section name.
     *	@param	string  $section_permission The section permissions belongs too.
     *	@param	bool    $auto_header        Boolean to print out the header. Default is 'true'.
     *	@param	bool    $auto_auth          Boolean for the auto authentication. Default is 'true'.
     *
     */
    public function __construct(
        string $section_name = "Pages",
        string $section_permission = 'start',
        bool $auto_header = true,
        bool $auto_auth = true
    )
    {
        global $database, $MESSAGE, $section_id, $page_id;

        parent::__construct();

        static::$instance = $this;

        $section_id = (isset ($_POST['section_id']) ? intval($_POST['section_id']) : 0);
        if ($section_id == 0 )
        {
            $section_id = (isset ($_GET['section_id'])? intval($_GET['section_id']): 0);
        }

        $page_id = (isset ($_POST['page_id']) ? intval($_POST['page_id']) : 0);
        if ($page_id == 0 )
        {
            $page_id = (isset ($_GET['page_id']) ? intval($_GET['page_id']) : 0);
        }

        /**	*********************
         *  TWIG Template Engine
         */
        if (is_null($this->oTWIG))
        {
            $this->oTWIG = lib_twig_box::getInstance();
            $this->oTWIG->loader->prependPath( THEME_PATH."/templates/", "theme" );
        }

        /**
         *	Droplet support
         *
         */
        if (true === $auto_auth)
        {
            ob_start();
        }

        $this->database = LEPTON_database::getInstance();

        // Specify the current applications name
        $this->section_name       = $section_name;
        $this->section_permission = $section_permission;
        // Authenticate the user for this application
        if ($auto_auth === true)
        {
            // [a1] First check if the user is logged-in
            if ($this->is_authenticated() === false)
            {
                header('Location:' . ADMIN_URL . '/login/index.php');
                exit();
            }

            // [a2] Now check whether he has a valid token
            if (!$this->checkLepToken())
            {
                $pin_set = $this->database->get_one("SELECT `pin_set` FROM `".TABLE_PREFIX."users` WHERE `user_id` = '".$_SESSION['USER_ID']."' ");
                if ($pin_set == 2)
                {
                    $this->database->simple_query("UPDATE `" . TABLE_PREFIX . "users` SET `pin_set` = 1 WHERE user_id = '" . $_SESSION['USER_ID'] . "' ");
                }
                unset($_SESSION['USER_ID']);
                header('Location:' . ADMIN_URL . '/login/index.php');
                exit();
            }

            // [a3] Now check if they are allowed in this section
            if ($this->get_permission($section_permission) === false)
            {
                if ($section_permission === "admintools")
                {
                    if (false == $this->userHasAdminToolPermission())
                    {
                        die($MESSAGE['ADMIN_INSUFFICIENT_PRIVILEGES']." [007-002]");            
                    }
                    
                } else {
                    die($MESSAGE['ADMIN_INSUFFICIENT_PRIVILEGES']." [007-001]");
                }
            }
        }

        // Check if the backend language is also the selected language. If not, send headers again.
        $user_language = [];
        $this->database->execute_query(
            "SELECT `language` FROM `" . TABLE_PREFIX . "users` WHERE `user_id` = '" . (int) $this->getValue('user_id', 'integer', 'session') . "'",
            true,
            $user_language,
            false
        );
        // prevent infinite loop if language file is not XX.php (e.g. DE_de.php)
        $user_language = (!isset($user_language['language']))
            ? "" 
            : substr($user_language['language'], 0,2)
            ;

        // obtain the admin folder (e.g. /admin)
        $admin_folder      = str_replace(LEPTON_PATH, '', ADMIN_PATH);
        if ((LANGUAGE != $user_language) && file_exists(LEPTON_PATH . '/languages/' . $user_language . '.php') && strpos($_SERVER['SCRIPT_NAME'], $admin_folder . '/') !== false)
        {
            // check if page_id is set
            $page_id_url    = (isset($_GET['page_id'])) ? '&page_id=' . (int) $_GET['page_id'] : '';
            $section_id_url = (isset($_GET['section_id'])) ? '&section_id=' . (int) $_GET['section_id'] : '';
            if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '') // check if there is an query-string
            {
                header('Location: ' . $_SERVER['SCRIPT_NAME'] . '?lang=' . $user_language . $page_id_url . $section_id_url . '&' . $_SERVER['QUERY_STRING']);
            }
            else
            {
                header('Location: ' . $_SERVER['SCRIPT_NAME'] . '?lang=' . $user_language . $page_id_url . $section_id_url);
            }
            exit();
        }

        // [a2.1] Auto header code
        if ($auto_header === true)
        {
            $this->print_header();
        }
		
		// include cronjob file for external call
		// @DEPRECATED_TEMP 20251010: this class will be removed in L* > 7.5.0, use external cronjobs instead
		if(CRONJOB == 2 || CRONJOB == 3)
		{
			$_POST['ikey'] = LEPTON_cronjob::getInstance()->cj_key;
			LEPTON_handle::include_files("/modules/cronjob.php");
		}	
    }

    /**
     *	Return a system permission
     *
     *	@param	string  $name   A name.
     *	@param	string  $type   A type - default is 'system'
     *  @return boolean
     */
    public function get_permission(string $name, string $type = 'system'): bool
    {
        // [p.1] Append to permission type
        $type .= '_permissions';
        // [p.2] Check if we have a section to check for
        if ($name === 'start')
        {
            return true;
        }
        else
        {
            if (true === self::userHasAdminRights())
            {
                return true;
            }

            $aTemp = match (strtolower($type))
            {
                "system_permissions" => ($this->getValue('system_permissions', 'string', 'session') ?? []),
                "module_permissions" => ($this->getValue('module_permissions', 'string', 'session') ?? []),
                default => []
            };
            return in_array($name, $aTemp);
        }
    }

    /**
     *  Get details from the database about a given user (id)
     *
     *  @param  int $user_id    A valid user-id.
     *  @return array   Assoc. array with the username and displayname
     */
    public static function get_user_details(int $user_id): array
    {
        $user = [];
        LEPTON_database::getInstance()->execute_query(
            "SELECT `username`,`display_name` FROM `".TABLE_PREFIX."users` WHERE `user_id` = ".$user_id,
            true,
            $user,
            false
        );

        if (empty($user))
        {
            $user['display_name'] = 'Unknown';
            $user['username']     = 'unknown';
        }
        return $user;
    }

    /**
     *  Get details about a given page via id
     *
     *  @param  int $page_id    A valid page_id.
     *  @return array   An assoc array with id, title, menu_title and modif. dates.
     *
     */
    public function get_page_details(int $page_id): array
    {
        $aResults = [];
        $this->database->execute_query(
            "SELECT * from ".TABLE_PREFIX."pages WHERE page_id = ".$page_id,
            true,
            $aResults,
            false
        );

        if (empty($aResults))
        {
            $this->print_header();
            $this->print_error($GLOBALS['MESSAGE']['PAGES_NOT_FOUND']);
        }
        return $aResults;
    }

    /**
     *	Function get_page_permission takes either a numerical page_id,
     *	upon which it looks up the permissions in the database,
     *	or an array with keys admin_groups
     *
     *  @param  int			$page   A valid page_id
     *  @param  string      $action Current backend or frontend user (default "admin")
     *  @return boolean
     *
     */
    public function get_page_permission(int $page_id, string $action = 'admin'): bool
    {
        $action_groups = $action.'_groups';

		$sGroups = $this->database->get_one("SELECT ".$action_groups." FROM ".TABLE_PREFIX."pages WHERE page_id = ".$page_id);
		
		$aGroups = explode(',',$sGroups);
	
        $aUserPermissions = $this->getValue('groups_id', 'string', 'session',',');
		
		$in_group = !empty(array_intersect($aGroups,$aUserPermissions));
		
        return $in_group;
    }

    /**
     *	Returns a system permission for a menu link.
     *  See: print_Header(). Line ~490 ff.
     * 
     *  @param  string  $title A valid menu item name
     *  @return boolean
     *
     */
    public function get_link_permission(string $title): bool
    {
        if (true === self::userHasAdminRights())
        {
            return true;
        }
            
        $titleLower  = strtolower(str_replace('_blank', '', $title));

        // Set system permissions var
        $system_permissions = $this->getValue('system_permissions', 'string_clean', 'session');

        // Return true if system perm = 1
        return (is_numeric(array_search($titleLower, $system_permissions)));
    }
    /**
     * 
     * @param string $what  Possible values are: '*', 'view', 'add', 'modify', 'delete'.
     *                      Where '*' means "min. one of them", NOT 'all'!
     * @return bool
     */
    public function getGroupsPermissions(string $what): bool
    {
        if (self::userHasAdminRights())
        {
            return true;
        }
        
        $lookFor = strtolower($what);
        
        switch ($lookFor)
        {
            case '*':
                $terms = ["groups", "groups_view", "groups_add", "groups_modify", "groups_delete"];
                break;
            
            case 'view':
            case 'add':
            case 'modify':
            case 'delete':
                $terms = ["groups_".$lookFor];
                break;
            
            default:
                echo LEPTON_tools::display_dev("[1023] No valid group key!", "pre", "ui message red");
                $terms = [];
                break;
        }
        return !empty(array_intersect($terms, $_SESSION['SYSTEM_PERMISSIONS']));
    }
    
    /**
     * 
     * @param string $what  Possible values are: '*', 'view', 'add', 'modify', 'delete'.
     *                      Where '*' means "min. one of them", NOT 'all'!
     * 
     * @return bool
     */
    public function getUsersPermissions(string $what): bool
    {
        if (self::userHasAdminRights())
        {
            return true;
        }
        
        $lookFor = strtolower($what);
        
        switch ($lookFor)
        {
            case '*':
                $terms = ["users", "users_view", "users_add", "users_modify", "users_delete"];
                break;
            
            case 'view':
            case 'add':
            case 'modify':
            case 'delete':
                $terms = ["users_".$lookFor];
                break;
            
            default:
                echo LEPTON_tools::display_dev("[1024] No valid users key!", "pre", "ui message red");
                $terms = [];
                break;
        }
        return !empty(array_intersect($terms, $_SESSION['SYSTEM_PERMISSIONS']));
    }
    
    /**
     * 
     * @param string $what  Possible values are: '*', 'view', 'add', 'modify', 'delete'.
     *                      Where '*' means "min. one of them", NOT 'all'!
     * 
     * @return bool
     */
    public function getPagesPermissions(string $what): bool
    {
        if (self::userHasAdminRights())
        {
            return true;
        }
        
        $lookFor = strtolower($what);
        
        switch ($lookFor)
        {
            case '*':
                $terms = ["pages", "pages_settings", "pages_view", "pages_add", "pages_modify", "pages_delete"];
                break;
            
            case 'view':
            case 'add':
            case 'modify':
            case 'settings':
            case 'delete':
                $terms = ["pages_".$lookFor];
                break;
            
            default:
                echo LEPTON_tools::display_dev("[1025] No valid pages key!", "pre", "ui message red");
                $terms = [];
                break;
        }
        return !empty(array_intersect($terms, $_SESSION['SYSTEM_PERMISSIONS']));
    }
    
    /**
     *	Print the admin header
     *
     */
    public function print_header(): void
    {
        LEPTON_handle::register("get_page_headers");
        // Get vars from the language file
        global $MENU;
        global $MESSAGE;
        global $TEXT;

        // Get website title
        $title = $this->database->get_one("SELECT `value` FROM `".TABLE_PREFIX."settings` WHERE `name`='website_title'");

        $charset = (true === defined('DEFAULT_CHARSET')) ? DEFAULT_CHARSET : 'utf-8';

        // Work out the URL for the 'View menu' link in the WB backend
        // if the page_id is set, show this page otherwise show the root directory of WB
        $view_url = LEPTON_URL;
        if (isset($_GET['page_id']))
        {
            // Extract page link from the database
            $result = $this->database->get_one("SELECT `link` FROM `" . TABLE_PREFIX . "pages` WHERE `page_id`= '" . (int) addslashes($_GET['page_id']) . "'");
            if (!is_null($result))
            {
                $view_url .= PAGES_DIRECTORY.$result.PAGE_EXTENSION;
            }
        }

        /**
         *	Try to get the current version of the backend-theme from the database
         *
         */
        $backend_theme_version = "";
        if (defined('DEFAULT_THEME'))
        {
            $backend_theme_version = $this->database->get_one("SELECT `version` from `" . TABLE_PREFIX . "addons` where `directory`='" . DEFAULT_THEME . "'");
        }

        $header_vars = [
            'SECTION_NAME'  => $MENU[strtoupper($this->section_name)],
            'WEBSITE_TITLE' => $title,
            'BACKEND_TITLE' => BACKEND_TITLE,
            'TEXT_ADMINISTRATION' => $TEXT['ADMINISTRATION'],
            'CURRENT_USER'  => $MESSAGE['START_CURRENT_USER'],
            'DISPLAY_NAME'  => $this->getValue('display_name', 'string', 'session'),
            'CHARSET'       => $charset,
            'LANGUAGE'      => strtolower(LANGUAGE),
            'LEPTON_VERSION' => LEPTON_VERSION,
            'SUBVERSION'    => SUBVERSION,
            'LEPTON_URL'    => LEPTON_URL,
            'ADMIN_URL'     => ADMIN_URL,
            'THEME_URL'     => THEME_URL,
            'TITLE_START'   => $MENU['START'],
            'TITLE_VIEW'    => $MENU['VIEW'],
            'TITLE_HELP'    => $MENU['HELP'],
            'TITLE_LOGOUT'  => $MENU['LOGOUT'],
// additional marker links/text in semantic BE-header
            //'PAGES'         => $MENU['PAGES'],
            //'MEDIA'         => $MENU['MEDIA'],
            //'ADDONS'        => $MENU['ADDONS'],
            //'PREFERENCES'   => $MENU['PREFERENCES'],
            //'SETTINGS'      => $MENU['SETTINGS'],
            //'ADMINTOOLS'    => $MENU['ADMINTOOLS'],
            //'ACCESS'        => $MENU['ACCESS'],
// end additional marks
            'URL_VIEW' => $view_url,
            'URL_HELP' => ' https://lepton-cms.org/',
            'GET_PAGE_HEADERS' => get_page_headers('backend', false),
            'THEME_VERSION' => $backend_theme_version,
            'THEME_NAME' => DEFAULT_THEME,
            //	permissions
            'p_pages'           => $this->get_link_permission('pages'),
            'p_pages_settings'  => $this->getUserPermission('pages_settings'),  // 1
            'p_pages_add'       => $this->getUserPermission('pages_add'),       // 2
            
            'p_media'       => $this->get_link_permission('media'),
            'p_addons'      => $this->get_link_permission('addons'),
            'p_preferences' => $this->getUserPermission('preferences'), // 1
            'p_settings'    => $this->get_link_permission('settings'),
            'p_admintools'  => $this->userHasAdminToolPermission(), // $this->get_link_permission('admintools'),
            'p_access'      => $this->get_link_permission('access'),
            // -- [groups]
            'p_groups'          => $this->getGroupsPermissions("*"),
            'p_groups_view'     => $this->getGroupsPermissions("view"),
            'p_groups_add'      => $this->getGroupsPermissions("add"),
            'p_groups_moddify'  => $this->getGroupsPermissions("modify"),
            'p_groups_delete'   => $this->getGroupsPermissions("delete"),
            // -- [users]
            'p_users'           => $this->getUsersPermissions("*"),
            'p_users_view'      => $this->getUsersPermissions("view"),
            'p_users_add'       => $this->getUsersPermissions("add"),
            'p_users_moddify'   => $this->getUsersPermissions("modify"),
            'p_users_delete'    => $this->getUsersPermissions("delete")
        ];

        echo $this->oTWIG->render(
            '@theme/header.lte',
            $header_vars
        );
    }

    /**
     * Print the admin backend footer
     * @notice: Aldus - 2023-02-13: Not clear wherever the ob-buffer started!
     * At this point it is not entirely clear whether the backend or the frontend is meant!
     * @Aldus - 2026-01-14: as this is the admin class it has to be backend only!
     */
    public function print_footer(): void
    {
		LEPTON_handle::register("get_page_footers");		
        $footer_vars = [
            'GET_PAGE_FOOTERS' => get_page_footers('backend'),
//            'LEPTON_URL' => LEPTON_URL,
//            'LEPTON_PATH' => LEPTON_PATH,
//            'ADMIN_URL' => ADMIN_URL,
//            'THEME_URL' => THEME_URL
        ];

        echo $this->oTWIG->render(
        	"@theme/footer.lte",
        	$footer_vars
        );

        /**
         *	Droplet support
         *  @notice This is the point!
         *          It is not(!) clear wherever the ob-buffer started!
         *          At this point it is not entirely clear whether the backend or the frontend is meant!
         *
         *  @notice ob - Level?
         */
        $this->html_output_storage = ob_get_clean();
        if (true === $this->droplets_ok)
        {
            evalDroplets($this->html_output_storage);
        }

        // CSRF protection - add tokens to internal links
        if ($this->is_authenticated() )
        {
			LEPTON_core::getInstance()->getProtectedFunctions($this->html_output_storage, $this);
        }

        echo $this->html_output_storage;
    }

    /**
     *	Print a success message which then automatically redirects the user to another page
     *
     *	@param	string|array  $message        A string within the message, or an array with a couple of messages.
     *	@param	string        $redirect       A redirect url. Default is "index.php".
     *	@param	bool          $auto_footer    An optional flag to 'print' the footer. Default is true.
     *
     */
    public function print_success(string|array $message, string $redirect = 'index.php', bool $auto_footer = true): void
    {
        global $TEXT;
        global $section_id;

        LEPTON_abstract::saveLastEditSection();

        if (true === is_array($message))
        {
            $message = implode("<br />", $message);
        }

        // add template variables
        $page_vars = [
            'NEXT' => $TEXT['NEXT'],
            'BACK' => $TEXT['BACK'],
            'MESSAGE' => $message,
            'THEME_URL' => THEME_URL,
            'REDIRECT' => $redirect,
            'REDIRECT_TIMER' => REDIRECT_TIMER
        ];

        echo $this->oTWIG->render(
            '@theme/success.lte',
            $page_vars
        );

        if (true === $auto_footer)
        {
            $this->print_footer();
        }
        exit();
    }

    /**
     *	Print an error message
     *
     * @param string|array  $message     A string or an array within the error messages.
     * @param string        $link        A redirect url. Default is "index.php".
     * @param bool          $auto_footer An optional boolean to 'print' the footer. Default is true;
     *
     */
    public function print_error(string|array $message, string $link = 'index.php', bool $auto_footer = true): void
    {
        global $TEXT;

        LEPTON_abstract::saveLastEditSection();

        if (true === is_array($message))
        {
            $message = implode("<br />", $message);
        }

        $page_vars = [
            'MESSAGE' => $message,
            'LINK'	=> $link,
            'BACK'	=> $TEXT['BACK'],
            'THEME_URL' => THEME_URL
        ];

        echo $this->oTWIG->render(
            '@theme/error.lte',
            $page_vars
        );

        if (true === $auto_footer && method_exists($this, "print_footer"))
        {
            $this->print_footer();
        }
        exit();
    }

    /**
     *  Test a given permission-name against the systempermissions.
     *
     *  @param  string  $sPermissionName    Any valid permission-name, e.g. "backend_access"
     *
     *  @return boolean
     */
    static public function getUserPermission(string $sPermissionName = "" ): bool
    {
        if (self::userHasAdminRights())
        {
            return true;
        }

        if (!isset($_SESSION['SYSTEM_PERMISSIONS']))
        {
            return false;
        }

        return (in_array($sPermissionName, $_SESSION['SYSTEM_PERMISSIONS']));
    }

    /**
     * @return array
     */
    public function getHeaderStorage(): array
    {
        return $this->header_storage;
    }

    public function resetObject()
    {
        static::$instance = null;
        return self::getInstance();
    }
    
    /**
     *
     *  @return bool    True, if the user has at last access to one admintool.
     */
    public function userHasAdminToolPermission(): bool
    {
        if (LEPTON_core::userHasAdminRights() == true)
        {
            return true;
        }
        
        if (empty($this->adminTools))
        {
            $aAllAdminToolsStorage = [];
            $this->database->execute_query(
                "SELECT `directory` FROM `".TABLE_PREFIX."addons` WHERE `function` = 'tool'",
                true,
                $aAllAdminToolsStorage,
                true
            );
            
            foreach ($aAllAdminToolsStorage as $tempTool)
            {
                $this->adminTools[] = $tempTool['directory'];
            }
        }
        //  Keep in mind that module_permissions is an array! 
        $aUserModules = LEPTON_core::getValue("module_permissions", "array", "session");
        
        return !empty(array_intersect($aUserModules, $this->adminTools));
    }
	
    /**
     *  Displays a message-box via template, whenever you cannot use admin->print_success or _error or _footer
     *
     *  @param string   $sType          The "class" type of the message: success, error, positiv, whatever.
     *  @param string   $sMessage       Any Message array | string.
     *  @param string   $sRedirect      Any ADMIN redirect (URL), 
     *  @param int      $iRedirectTime  The redirect time. Keep in mind that this are js-milliseconds! 3000 are 3 sec! A value like -1 means no timeout; stand still.
     *  @param string   $sTemplateName  Any name of the .lte file in folder DEFAULT_THEME."/backend/backend/
     *  @param bool     $bDirectOutput  Prompt the message direct (echo), false returns the generated source. Default is true == prompt!
     *
     *  @code:
     *      $aMessage = ['header','text1']
     *      LEPTON_admin::displayMessage(
     *           "success",
     *           $aMessage,
     *           ADMIN_URL . '/admintools/tool.php?tool=cookie',
     *           5000 // very long time; -1 means: stand still
     *          "message_custom.lte"
     *        );
     */ 
    public static function displayMessage(
        string       $sType ="success",
        array|string $aMessage = [],
        string       $sRedirect = "",
        int          $iRedirectTime = -1,
        string       $sTemplateName = "message.lte",
        bool         $bDirectOutput = true
    ): string
    {
        $oTwig = lib_twig_box::getInstance();

        if (!is_array($aMessage))
        {
            $aMessage = [$aMessage];
        }

        if (empty($sRedirect))
        {
			die(LEPTON_tools::display('Please set $sRedirect! ', 'pre','ui red message'));
        }

		if(stripos('leptoken=',$sRedirect) == 0)
		{
			$sRedirect.='&leptoken='.get_leptoken();
		}
				
        // [1] Is there a lte file inside the THEME dir?
        if (file_exists(LEPTON_PATH."/templates/".DEFAULT_THEME."/backend/backend/message.lte"))
        {
            // [1.1] File is inside the fTHEME - so we are using this path.
            $oTwig->registerPath(LEPTON_PATH."/templates/".DEFAULT_THEME."/backend/backend/", "backend");
        }

        $data = [
            'type' => $sType,
            'message' => $aMessage,
            'redirect' => $sRedirect,
            'redirect_time' => $iRedirectTime
        ];

        $sHTML_rendered = $oTwig->render(
            "@backend/".$sTemplateName,
            $data
        );
        
        if ($bDirectOutput == true)
        {
            echo $sHTML_rendered;
            return "";
        }
        
        return $sHTML_rendered;
    }	
}
