<?php

class ModelDef
{
  public string $Title;
  public array $OnChange;

  function __construct()
  {
    $this->OnChange = array();
  }

  function DoOnChange(): void
  {
    foreach ($this->OnChange as $Callback)
    {
      call_user_func($Callback);
    }
  }

  function RegisterOnChange(string $SysName, callable $Callback): void
  {
    $this->OnChange[$SysName] = $Callback;
  }

  function UnregisterOnChange(string $SysName): void
  {
    unset($this->OnChange[$SysName]);
  }
}

class Command
{
  public string $Name;
  public string $Description;
  public $Callback;

  function __construct(string $Name, string $Description, callable $Callback)
  {
    $this->Name = $Name;
    $this->Description = $Description;
    $this->Callback = $Callback;
  }
}

class System
{
  public Database $Database;
  public string $Name;
  public ModuleManager $ModuleManager;
  public array $Models;
  public array $CommandLine;
  public array $Pages;

  function __construct()
  {
    $this->Database = new Database();
    $this->Name = 'System';
    $this->ModuleManager = new ModuleManager($this);
    $this->Models = array();
    $this->CommandLine = array();
    $this->Pages = array();

    $this->RegisterCommandLine('list', 'Prints available commands', array($this, 'ListCommands'));
  }

  function GetModule(string $Name): Module
  {
    if (array_key_exists($Name, $this->ModuleManager->Modules))
      return $this->ModuleManager->Modules[$Name];
      else return null;
  }

  function RegisterModel(string $SysName, array $Model): void
  {
    $NewModelDef = new ModelDef();
    $NewModelDef->Title = $Model['Title'];
    $this->Models[$SysName] = $NewModelDef;
  }

  function UnregisterModel(string $SysName): void
  {
    unset($this->Models[$SysName]);
  }

  function RegisterCommandLine(string $Name, string $Description, callable $Callback): void
  {
    $this->CommandLine[$Name] = new Command($Name, $Description, $Callback);
  }

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

  function ListCommands(array $Parameters)
  {
    $Output = 'Available commands:'."\n";
    foreach ($this->CommandLine as $Command)
    {
      $Output .= ' '.$Command->Name.' - '.$Command->Description."\n";
    }
    echo($Output."\n");
  }

  function RegisterPage(array $Path, string $Handler): void
  {
    $Page = &$this->Pages;
    $LastKey = array_pop($Path);
    foreach ($Path as $PathItem)
    {
      $Page = &$Page[$PathItem];
    }
    if (!is_array($Page)) $Page = array('' => $Page);
    $Page[$LastKey] = $Handler;
  }

  function UnregisterPage(array $Path): void
  {
    $Page = &$this->Pages;
    $LastKey = array_pop($Path);
    foreach ($Path as $PathItem)
    {
      $Page = &$Page[$PathItem];
    }
    unset($Page[$LastKey]);
  }

  function Run(): void
  {
  }

  function Link(string $Target): string
  {
    return $Target;
  }

  function AbsoluteLink(string $Target): string
  {
    return $Target;
  }
}
