<?php
//#### START ########################################################
define('SYSTEM_VERSION', '2.21j');
define('SYSTEM_BASEPATH', __DIR__);
require_once(SYSTEM_BASEPATH . "/sys/Autoload.php");
require_once(SYSTEM_BASEPATH . "/storage/system/config.php");


//#### INIT ########################################################
// get path without parameters (rawurldecode(strtok($_SERVER['REQUEST_URI'], '?'));)
$path = "/";
if (isset($_GET['path'])) {
    $path .= str_replace(' ', '+', $_GET['path']);
}
// rewrite rule check
if ($path === '/rewrite-rule-check') {
    header("HTTP/1.1 200 OK");
    echo "Rewrite Rule check passed";
    exit;
}

//#### ADMIN #######################################################
if ($path === '/admin' || str_starts_with($path, '/admin/')) {
    if ($path === '/admin' || $path === '/admin/') {
        require(SYSTEM_BASEPATH . "/admin/index.php");
        exit;
    } elseif (preg_match('/^\/admin\/[a-z0-9]+$/i', $path, $match)) {
        require(SYSTEM_BASEPATH . $path . ".php");
        exit;
    } elseif (preg_match('/^\/admin\/api\/(auth|cms|site|service)\/([A-Za-z0-9-_:\/]+)$/i', $path, $match)) {
        $_GET['request'] = $match[2];
        require(SYSTEM_BASEPATH . "/admin/api/" . $match[1] . ".php");
        exit;
    }
}

//#### SERVE #######################################################
if (str_starts_with($path, CMS_ORIGINAL_IMAGE_BASEPATH) || str_starts_with($path, WEBSITE_CACHE_IMAGE_BASEPATH)) {
    if (preg_match('/^.+\.(jpg|jpeg|pjpeg|jfif|pjp|png|gif|webp)$/i', $path)) {
        if (!str_contains($_SERVER['REQUEST_URI'], "index.php")) { // disallow direct serving via /index.php?path=...
            require(SYSTEM_BASEPATH . "/serve.php");
            exit;
        }
    }
}

//#### SITE ########################################################
/* SETTINGS + LANG array and CmsService */
$SETTINGS = [];
$LANG = [];
$CmsService = CreateClassInstance('CmsService', [SYSTEM_BASEPATH]);
$CmsService->Initialize($SETTINGS, $LANG);
$CmsDatabaseConnection = CreateClassInstance('DatabaseConnection', [CMS_DB_HOSTNAME, CMS_DB_USERNAME, CMS_DB_PASSWORD, CMS_DB_DATABASE]);

// System Logging
/*
SystemUtils::LogSystemMetrics('index', 'start', $path, SYSTEM_BASEPATH . '/system_metrics.csv');
register_shutdown_function(function ()use ($path)  {
    SystemUtils::LogSystemMetrics('index', 'end', $path, SYSTEM_BASEPATH . '/system_metrics.csv');
});
*/

// site cache
$CmsCacheService = CreateClassInstance('CmsCacheService', [SYSTEM_BASEPATH]);
if ($SETTINGS['SITECACHING']) {
    header('Content-type: ' . (str_ends_with($path, '.xml') ? 'application/xml' : 'text/html') . '; charset=utf-8');
    if ($CmsCacheService->LoadCache($path, $_GET, true)) {
        exit;
    }
    if (isset($_GET) && !empty(array_diff(array_keys($_GET), ['path']))) {
        $SETTINGS['SITECACHING'] = false;
    }
}

// SITE array
$SITE = [];
$SITE['multi_lang'] = null; // active lang code (single-language site: null, multi-language sites: en, de, ...)
$SITE['path'] = ''; // path without parameters starting with /
$SITE['query'] = null; // query parameters
$SITE['basepath'] = '';
$SITE['subpath'] = '';
$SITE['template'] = null;
$SITE['reference_type'] = null;
$SITE['reference_id'] = null;
$SITE['active_link_id'] = null;
$SITE['title'] = null;
$SITE['title2'] = null; // shorter title version
$SITE['frontpage'] = false;
$SITE['custom_settings'] = null;
$SITE['custom_html'] = null;
$SITE['custom_css'] = null;
$SITE['path_accesss'] = null;
$SITE['SCRIPT'] = ['header' => "", 'footer' => ""];
$SITE['META'] = ['title' => null, 'description' => null, 'keywords' => null];
$SITE['BREADCRUMBS'] = []; // array with ['title' => "", 'url' => ""] entries
$SITE['ASSETS'] = []; // array with entries like 'asset_type' => asset_id
$SITE['PATHPROTECTIONS'] = []; // array with path protections
$SITE['LINK'] = null;
$SITE['LINKS'] = [];

// 1. Redirects and Adaptions
// init
$SITE['multi_lang'] = null;
$SITE['path'] = $path; // path starting with / and without parameters
$QUERY_PARAMETERS = $_GET;
unset($QUERY_PARAMETERS['path']);
$SITE['query'] = (count($QUERY_PARAMETERS) > 0) ? '?' . http_build_query($QUERY_PARAMETERS) : ''; // query parameters

// take language from path and load language translation
// define WEBSITE_FETCHTRANSLATIONCODE => fetching asset translations, WEBSITE_LANGDIR => url part ("/en")
if($SETTINGS['LANGS'] !== null){
    if(count($SETTINGS['LANGS']) > 1){ 
        // multi-language site
        foreach ($SETTINGS['LANGS'] as $LANGUAGE) { // detect lang from path
            $lang_code = $LANGUAGE['code'];
            if (str_starts_with($path, "/$lang_code/") || $path === "/$lang_code") { // match "/xx/..." or exactly "/xx"
                $CmsService->InitializeLangByCode($LANG, $lang_code);
                $SITE['multi_lang'] = $lang_code;
                $SITE['path'] = substr($SITE['path'], 3); // path without /{lang_code}                
                define('WEBSITE_LANGDIR', '/'. $lang_code);
                if($lang_code !== $SETTINGS['LANGS'][0]['code']){ define('WEBSITE_FETCHTRANSLATIONCODE', $lang_code); }
                break;
            }
        }
    } else if(count($SETTINGS['LANGS']) === 1) { 
        // single-language site (with selected language)
        $CmsService->InitializeLangByCode($LANG, $SETTINGS['LANGS'][0]['code']);
    }
}
if (!defined('WEBSITE_LANGDIR')) { define('WEBSITE_LANGDIR', ''); }


// LINKS array
$LINKS = [];
$CmsLinksService = CreateClassInstance('CmsLinksService', [$CmsDatabaseConnection]);
if ($CmsDatabaseConnection->STATUS() === true) {
    //$LINKS = $CmsLinksService->GetLinkData();
    $LINKS = SystemUtils::ApcuCache([$CmsLinksService, 'GetLinkData'], preg_replace('/[^a-z0-9]/i', '', WEBSITE_URL) . 'cms_links_selectall' . ($SITE['multi_lang'] !== null ? '_' .$SITE['multi_lang'] :'')); //$LINKS = $CmsLinksService->GetLinkData();
}
$SITE['LINKS'] = $LINKS;
if (empty($LINKS)) {
    $SITE['template'] = 'error404';
    $SITE['basepath'] = '/error404';
}

// redirects
if (!str_starts_with($_SERVER['REQUEST_URI'], '/index.php')) {
    // redirect non https and redirect to specified host
    if (!empty($_SERVER['HTTP_HOST'])) {
        if ((str_starts_with(WEBSITE_URL, 'https://') && !SystemUtils::ConnectionHasSSL()) ||
            (strtok($_SERVER['HTTP_HOST'], ':') !== parse_url(WEBSITE_URL, PHP_URL_HOST))
        ) {
            header("HTTP/1.1 301 Moved Permanently");
            header("Location: " . WEBSITE_URL . WEBSITE_LANGDIR . $SITE['path'] . $SITE['query']);
            exit;
        }
    }
    // redirect missing lang code on multi-language site
    if($SETTINGS['LANGS'] !== null && count($SETTINGS['LANGS']) > 1 && $SITE['multi_lang'] === null){
        header("Location: " . WEBSITE_URL . WEBSITE_LANGDIR . "/" . $SETTINGS['LANGS'][0]['code'] . $SITE['path'] . $SITE['query']);
        exit;
    }
    // redirect front page
    if ($SITE['path'] === "" || $SITE['path'] === "/") {
        $SITE['path'] = null;
        foreach ($LINKS as $LINK) if ($LINK['frontpage'] === true) { // set path to designated fronpage
            $SITE['path'] = WEBSITE_DIRECTORY . $LINK['path'] . WEBSITE_TRAILINGSLASH;
            $SITE['path'] = substr($SITE['path'], strlen(WEBSITE_DIRECTORY));
            break;
        }
        if ($SITE['path'] === null) { // redirect, if no frontpage assigned
            foreach ([1, 2, 0] as $section) { 
                foreach ($LINKS as $LINK) if ($LINK['section'] === $section) {
                    header("Location: " . WEBSITE_URL . WEBSITE_LANGDIR . $LINK['path'] . WEBSITE_TRAILINGSLASH . $SITE['query']);
                    exit;
                } 
            }
        }
        if ($SITE['path'] === null) { $SITE['path'] = ""; }
    } else {
        foreach ($LINKS as $LINK) if ($LINK['frontpage'] === true && $SITE['path'] === $LINK['path']) {
            header("HTTP/1.1 301 Moved Permanently"); // redirect /frontpage to /
            header("Location: " . WEBSITE_URL . WEBSITE_LANGDIR . WEBSITE_TRAILINGSLASH . $SITE['query']);
            exit;
        }
    }
    // redirect trailing slash
    if (!str_ends_with($SITE['path'], '.xml') && str_ends_with($SITE['path'], '/') !== $SETTINGS['TRAILINGSLASH']) {
        unset($_GET['path']);
        if ($SETTINGS['TRAILINGSLASH']) {
            header("HTTP/1.1 301 Moved Permanently");
            header("Location: " . WEBSITE_URL . WEBSITE_LANGDIR . $SITE['path'] . "/" . $SITE['query']);
        } else {
            header("HTTP/1.1 301 Moved Permanently");
            header("Location: " . WEBSITE_URL . WEBSITE_LANGDIR . substr($SITE['path'], 0, -1) . $SITE['query']);
        }
        exit;
    }
}
// check trailing slash
if (!str_ends_with($SITE['path'], '.xml') && str_ends_with($SITE['path'], '/') !== $SETTINGS['TRAILINGSLASH']) {
    $SITE['template'] = 'error404';
    $SITE['basepath'] = '/error404';
}
// remove trailing slash from $SITE['path']
if (str_ends_with($SITE['path'], '/')) {
    $SITE['path'] =  substr($SITE['path'], 0, -1);
}

// 2. Path Template Matching
// check menu links [template: ...]
if ($SITE['template'] === null) {
    foreach ($LINKS as $index => $LINK) if ($LINK['template'] !== null) {
        if (
            $SITE['path'] === $LINK['path'] ||
            (!in_array($LINK['template'], ['page', 'site', 'startshowcase', 'startlanding']) && str_starts_with($SITE['path'] . '/', $LINK['path'] . '/'))
        ) {
            $SITE['basepath'] = $LINK['path'];
            $SITE['subpath'] = substr($SITE['path'], strlen($LINK['path']));
            $SITE['template'] = $LINK['template'];
            $SITE['reference_type'] = $LINK['reference_type'];
            $SITE['reference_id'] = $LINK['reference_id'];
            $SITE['active_link_id'] = $LINK['id'];
            $SITE['title'] = $LINK['title'];
            $SITE['frontpage'] = $LINK['frontpage'];
            $SITE['custom_settings'] = $LINK['custom_settings'];
            $SITE['custom_html'] = $LINK['custom_html'];
            $SITE['custom_css'] = $LINK['custom_css'];
            $SITE['ASSETS']['link'] = $LINK['id'];
            $SITE['LINK'] = $LINK;
            $SITE['LINK']['index'] = $index;
            CmsService::ApplySettings($SETTINGS, CmsService::GetSettingsFromJson($SITE['custom_settings']));
            break;
        }
    }
}
// no match found [template: _xyz_xml]
if ($SITE['template'] === null && preg_match('/^\/[a-z0-9]*\.xml$/i', $SITE['path'])) {
    $SITE['template'] = '_' . str_replace('/', '', str_replace('.xml', '', $SITE['path'])) . '_xml';
    $SITE['basepath'] = $SITE['path'];
}
// no match found [template: error404]
if ($SITE['template'] === null || $SITE['template'] === 'index') {
    $SITE['template'] = 'error404';
    $SITE['basepath'] = '/error404';
}

// 3. Protection Check
$CmsAccessService = CreateClassInstance('CmsAccessService', [CreateClassInstance('GuardService', ['pathaccess', SYSTEM_BASEPATH . WEBSITE_TEMP_BASEPATH])]);
// logout
if (isset($_GET['logout'])) { 
    $CmsAccessService->RevokeUnlockedPathsProtections();
    foreach ($LINKS as $LINK) if ($LINK['template'] === 'clientlogin' ) { // forward to clientlogin template
        header("Location: " . WEBSITE_DIRECTORY . $LINK['path'] . WEBSITE_TRAILINGSLASH);
        exit;
    }
}
// check url protection
$SITE['PATHPROTECTIONS'] = $CmsAccessService->GetPathProtections($SETTINGS['PASSWORDAREAS'], $LINKS);
$path_accesss = $CmsAccessService->CheckPathAccess($SITE['path'], $SITE['PATHPROTECTIONS']);
if ($path_accesss === false) {
    $SITE['template'] = '_password';
}
if ($path_accesss !== null) {
    $SETTINGS['SITECACHING'] = false;
    $SITE['path_accesss'] = $path_accesss;
}

// 4. Service Starting 
$OR = CreateClassInstance('OutputRenderer', [&$SITE, &$SETTINGS, &$LANG, SYSTEM_BASEPATH]);
$CmsPhotosService = CreateClassInstance('CmsPhotosService', [$CmsDatabaseConnection, SYSTEM_BASEPATH]);
$CmsArticlesService = CreateClassInstance('CmsArticlesService', [$CmsDatabaseConnection]);
$CmsPagesService = CreateClassInstance('CmsPagesService', [$CmsDatabaseConnection]);
$EditorElementsRenderer = CreateClassInstance('EditorElementsRenderer', [$OR, $CmsLinksService, $CmsPhotosService, $CmsArticlesService, SYSTEM_BASEPATH]);

// 5. Content Serving 
// include template file
if (file_exists(SYSTEM_BASEPATH . "/templates/" . $SITE['template'] . ".php") || file_exists(SYSTEM_BASEPATH . "/storage/custom/" . $SITE['template'] . ".php") ) {
    ob_start();
    header('Content-type: ' . (str_ends_with($SITE['path'], '.xml') ? 'application/xml' : 'text/html') . '; charset=utf-8');
    if (file_exists(SYSTEM_BASEPATH . "/storage/custom/{$SITE['template']}.php")) {
        require(SYSTEM_BASEPATH . "/storage/custom/{$SITE['template']}.php");
    } else {
        require(SYSTEM_BASEPATH . "/templates/{$SITE['template']}.php");
    }
    if ($SETTINGS['SITECACHING']) {
        $CmsCacheService->SaveCache($path, $_GET, ob_get_contents());
    }
    ob_end_flush();
} else {
    header("HTTP/1.1 400 Bad Request");
    echo "Template not found!";
}
