<?php

$ConfigFileName = dirname(__FILE__).'/../Config/Config.php';
if (file_exists($ConfigFileName)) include_once($ConfigFileName);
else
{
  $ConfigFileName = '/etc/isp-central/Config.php';
  if (file_exists($ConfigFileName)) include_once($ConfigFileName); 
}

include_once(dirname(__FILE__).'/Version.php');
include_once(dirname(__FILE__).'/../Common/Global.php');
include_once(dirname(__FILE__).'/FormClasses.php');
include_once(dirname(__FILE__).'/FullInstall.php');
include_once(dirname(__FILE__).'/UpdateTrace.php');
include_once(dirname(__FILE__).'/BaseView.php');
include_once(dirname(__FILE__).'/DefaultConfig.php');

class Core extends System
{
  public Type $Type;
  public array $Bars;
  public FormManager $FormManager;
  public array $Config;
  public Config $ConfigManager;
  public array $PathItems;
  public string $RootURLFolder;
  public bool $ShowPage;
  public array $PageHeaders;
  public BaseView $BaseView;
  public LocaleManager $LocaleManager;
  public array $LinkLocaleExceptions;
  public float $ScriptTimeStart;

  function __construct()
  {
    parent::__construct();
    $this->Config = array();
    $this->ModuleManager->FileName = dirname(__FILE__).'/../Config/ModulesConfig.php';
    $this->FormManager = new FormManager($this->Database);
    $this->ShowPage = true;
    $this->ConfigManager = new Config();
    $this->RootURLFolder = $_SERVER['SCRIPT_NAME'];
    if (substr($this->RootURLFolder, -10, 10) == '/index.php')
      $this->RootURLFolder = substr($this->RootURLFolder, 0, -10);
    $this->PageHeaders = array();
    $this->LinkLocaleExceptions = array();
  }

  function SearchPage(array $PathItems, array $Pages): ?string
  {
    if (count($PathItems) > 0) $PathItem = $PathItems[0];
      else $PathItem = '';
    if (array_key_exists($PathItem, $Pages))
    {
      if (is_array($Pages[$PathItem]))
      {
        array_shift($PathItems);
        return $this->SearchPage($PathItems, $Pages[$PathItem]);
      } else return $Pages[$PathItem];
    } else return '';
  }

  function ShowPage(): void
  {
    $this->BaseView = new BaseView($this);
    if (isset($this->Config['Web']['FormatHTML']))
      $this->BaseView->FormatHTML = $this->Config['Web']['FormatHTML'];
    if (isset($this->Config['Web']['ShowRuntimeInfo']))
      $this->BaseView->ShowRuntimeInfo = $this->Config['Web']['ShowRuntimeInfo'];
    if (isset($this->Config['Web']['Charset']))
      $this->BaseView->Encoding = $this->Config['Web']['Charset'];
    if (isset($this->Config['Web']['Style']))
      $this->BaseView->Style = $this->Config['Web']['Style'];

    /* @var $Page Page */
    $ClassName = $this->SearchPage($this->PathItems, $this->Pages);
    if ($ClassName != '')
    {
      $Page = new $ClassName($this);
    } else
    {
      $Page = new PageMissing($this);
    }
    echo($this->BaseView->GetOutput($Page));
  }

  function ModulePresent(string $Name): bool
  {
    return array_key_exists($Name, $this->ModuleManager->Modules);
  }

  function HumanDate(int $Time): string
  {
    return date('j.n.Y', $Time);
  }

  function Link(string $Target): string
  {
    return $this->RootURLFolder.$Target;
  }

  function RunCommon(): void
  {
    global $Database, $ConfigFileName, $Config, $GlobalLocaleManager;

    date_default_timezone_set('Europe/Prague');
    mb_internal_encoding("UTF-8");
    $this->ScriptTimeStart = GetMicrotime();

    // SQL injection hack protection
    foreach ($_POST as $Index => $Item) $_POST[$Index] = addslashes($Item);
    foreach ($_GET as $Index => $Item) $_GET[$Index] = addslashes($Item);

    if (isset($_SERVER['REMOTE_ADDR'])) session_start();

    $ConfigFileName = dirname(dirname(__FILE__)).'/config.php';
    if (file_exists($ConfigFileName))
      $this->ConfigManager->LoadFromFile($ConfigFileName);
    //$this->Config = $this->ConfigManager->GetAsArray();
    $this->Config = &$Config;

    try
    {
      $this->Database->Connect($this->Config['Database']['Host'], $this->Config['Database']['User'],
        $this->Config['Database']['Password'], $this->Config['Database']['Database']);
      $this->Database->Prefix = $this->Config['Database']['Prefix'];
      $this->Database->charset($this->Config['Database']['Charset']);
      $this->Database->ShowSQLError = $this->Config['Web']['ShowSQLError'];
      $this->Database->ShowSQLQuery = $this->Config['Web']['ShowSQLQuery'];
      if (isset($this->Config['Web']['LogSQLQuery']))
        $this->Database->LogSQLQuery = $this->Config['Web']['LogSQLQuery'];
      if (isset($this->Config['Web']['MeasureQueryDuration']))
        $this->Database->MeasureDuration = $this->Config['Web']['MeasureQueryDuration'];
    } catch (Exception $E)
    {
      //$Output .= 'Nelze se připojit k databázi.';
    }

    $this->LocaleManager = new LocaleManager($this);
    $this->LocaleManager->Dir = dirname(dirname(__FILE__)).'/locale';
    $this->LocaleManager->Available = array(
      'cs' => array('Code' => 'cs', 'Title' => 'Česky'),
      'en' => array('Code' => 'en', 'Title' => 'English'),
    );
    $GlobalLocaleManager = $this->LocaleManager;
    $this->LinkLocaleExceptions = array('images', 'style', 'files');

    if (isset($this->Config['Web']['RootFolder']))
      $this->RootURLFolder = $this->Config['Web']['RootFolder'];
    $this->FormManager->RootURL = $this->RootURLFolder;

    $this->RegisterPageBar('Top');

    $Database = $this->Database;
    RegisterFormClasses($this->FormManager);

    $this->StartModules();
  }

  function StartModules(): void
  {
    $ModuleSetup = $this->ModuleManager->LoadModule(dirname(__FILE__).'/../Packages/Common/Modules/Setup.php');
    $ModuleSetup->Install();
    $ModuleSetup->Start();
    $this->ModuleManager->LoadModules();
    $this->ModuleManager->LoadModule(dirname(__FILE__).'/../Packages/Common/Modules/ModuleManager.php');
    if (file_exists($this->ModuleManager->FileName)) $this->ModuleManager->LoadState();
    if (ModuleSetup::Cast($ModuleSetup)->CheckState())
    {
      $this->ModuleManager->StartAll(array(ModuleCondition::Enabled));
    }
  }

  function Run(): void
  {
    $this->RunCommon();
    if ($this->ShowPage)
    {
      $this->PathItems = ProcessURL();

      // Detect interface locale
      if (isset($this->Config['Web']['Locale']))
        $this->LocaleManager->DefaultLangCode = $this->Config['Web']['Locale'];
      $this->LocaleManager->LangCode = $this->LocaleManager->DefaultLangCode;
      if (count($this->PathItems) > 0)
      {
         $NewLangCode = $this->PathItems[0];
         if (array_key_exists($NewLangCode, $this->LocaleManager->Available))
         {
           array_shift($this->PathItems);
           $this->LocaleManager->LangCode = $NewLangCode;
         }
      }
      if (array_key_exists($this->LocaleManager->LangCode, $this->LocaleManager->Available))
        $this->LocaleManager->LoadLocale($this->LocaleManager->LangCode);

      $this->ShowPage();
    }
  }

  function RunCommandLine(): void
  {
    global $argv;

    $this->RunCommon();
    if (count($argv) > 1)
    {
      if (array_key_exists($argv[1], $this->CommandLine))
      {
        $Command = $this->CommandLine[$argv[1]];
        $Output = call_user_func($Command->Callback, $argv);
      } else $Output = 'Command "'.$argv[1].'" not supported.'."\n";
    } else $Output = 'No command was given as parameter. Use "list" to show available commands.'."\n";
    echo($Output);
  }

  function RegisterPageBar(string $Name): void
  {
    $this->Bars[$Name] = array();
  }

  function UnregisterPageBar(string $Name): void
  {
    unset($this->Bars[$Name]);
  }

  function RegisterPageBarItem(string $BarName, string $ItemName, callable $Callback): void
  {
    $this->Bars[$BarName][$ItemName] = $Callback;
  }

  function UnregisterPageBarItem(string $BarName, string $ItemName): void
  {
    unset($this->Bars[$BarName][$ItemName]);
  }

  function RegisterPageHeader(string $Name, callable $Callback): void
  {
    $this->PageHeaders[$Name] = $Callback;
  }

  function UnregisterPageHeader(string $Name): void
  {
    unset($this->PageHeaders[$Name]);
  }

  static function Cast(System $System): Core
  {
    if ($System instanceof Core)
    {
      return $System;
    }
    throw new Exception('Expected Core type but '.gettype($System));
  }
}

class PageMissing extends Page
{
  function __construct(System $System)
  {
    parent::__construct($System);
    $this->Title = 'Stránka nenalezena';
    $this->ParentClass = 'PagePortal';
  }

  function Show(): string
  {
    Header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
    return '<h3 align="center">Požadovaná stránka neexistuje.</h3>';
  }
}
