<?php

$ConfigFileName = dirname(__FILE__).'/../Config/Config.php';
if (file_exists($ConfigFileName)) include_once($ConfigFileName);

include_once(dirname(__FILE__).'/../Packages/Common/PackageCommon.php');
include_once(dirname(__FILE__).'/../Packages/FormManager/PackageFormManager.php');
include_once(dirname(__FILE__).'/Version.php');
include_once(dirname(__FILE__).'/BaseView.php');
include_once(dirname(__FILE__).'/PageMissing.php');
include_once(dirname(__FILE__).'/UpdateTrace.php');
include_once(dirname(__FILE__).'/DefaultConfig.php');
include_once(dirname(__FILE__).'/../Global.php');

class Core extends System
{
  public bool $ShowPage;
  public string $BaseURL;
  public array $Config;
  public array $HeadItems;
  public array $Bars;
  public array $PathItems;
  public FormManager $FormManager;
  public BaseView $BaseView;
  public User $User;

  function __construct()
  {
    parent::__construct();
    $this->Pages = array();
    $this->Bars = array();
    $this->HeadItems = array();
    $this->ShowPage = true;
    $this->BaseURL = $_SERVER['SCRIPT_NAME'];
    $BaseScriptName = '/index.php';
    if (substr($this->BaseURL, -strlen($BaseScriptName), strlen($BaseScriptName)) == $BaseScriptName)
      $this->BaseURL = substr($this->BaseURL, 0, -strlen($BaseScriptName));
    $this->FormManager = new FormManager($this->Database);
  }

  function RunCommon()
  {
    global $Config, $DatabaseRevision;

    session_start();

    $ErrorHandler = new ErrorHandler();
    $ErrorHandler->ShowError = $Config['Web']['ShowPHPError'];
    $ErrorHandler->Start();

    $this->Config = &$Config;

    if (isset($this->Config['Database']))
    {
      $this->Database->Connect($Config['Database']['Host'], $Config['Database']['User'],
        $Config['Database']['Password'], $Config['Database']['Database']);
      $this->Database->Prefix = $Config['Database']['Prefix'];
      $this->Database->charset($Config['Database']['Charset']);
      $this->Database->ShowSQLError = $Config['Web']['ShowSQLError'];
      $this->Database->ShowSQLQuery = $Config['Web']['ShowSQLQuery'];
    }

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

    $this->RegisterPageBar('Top');
    $this->RegisterPageBar('TopLeft');

    $this->StartModules();
  }

  function StartModules(): void
  {
    $ModuleSetup = $this->ModuleManager->LoadModule(dirname(__FILE__).'/../Packages/Common/Modules/ModuleSetup.php');
    $ModuleSetup->Install();
    $ModuleSetup->Start();
    $this->ModuleManager->LoadModules();
    $this->ModuleManager->LoadModule(dirname(__FILE__).'/../Packages/Common/Modules/ModuleAdmin.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();
      $this->ShowPage();
    }
  }

  function ShowPage()
  {
    $this->BaseView = new BaseView($this);

    /* @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 RegisterPageBar($Name)
  {
    $this->Bars[$Name] = array();
  }

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

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

  function SearchPage($PathItems, $Pages)
  {
    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 Link($Target): string
  {
    return $this->BaseURL.$Target;
  }

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