<?php

include_once(dirname(__FILE__).'/../../Common/Global.php');

class PageIS extends Page
{
  public array $MenuItems;
  public bool $HideMenu;
  public bool $ShowActionName;

  function __construct($System)
  {
    parent::__construct($System);
    $this->Title = 'Správa dat';
    $this->ParentClass = 'PagePortal';

    $this->MenuItems = array();
    $this->HideMenu = false;
    $this->ShowActionName = false;
  }

  function Show(): string
  {
    if (!ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission('IS', 'Manage'))
      return 'Nemáte oprávnění';
    $this->System->FormManager->ShowRelation = true;

    // a - action
    if (array_key_exists('a', $_GET)) $Action = $_GET['a'];
      else $Action = '';
    // t - table
    if (array_key_exists('t', $_GET)) $Table = $_GET['t'];
      else $Table = '';
    // i - index of item
    if (array_key_exists('i', $_GET)) $ItemId = $_GET['i'];
      else $ItemId = 0;
    // fc - preset colum
    if (array_key_exists('fn', $_GET)) $FilterName = $_GET['fn'];
      else $FilterName = '';
    if (array_key_exists('fv', $_GET)) $FilterValue = $_GET['fv'];
      else $FilterValue = '';
    if (array_key_exists('menutype', $_COOKIE)) $MenuType = $_COOKIE['menutype'];
      else $MenuType = 0;
    if (array_key_exists('menutype', $_GET) and is_numeric($_GET['menutype'])) $MenuType = $_GET['menutype'] * 1;
    setcookie('menutype', $MenuType, time() + 60 * 60 * 24 * 365);

    if ($Action == 'list') {
      if ($FilterName == '') $Content = $this->ShowList($Table);
        else $Content = $this->ShowList($Table, '', '', $FilterName, $FilterValue);
    }
    else if ($Action == 'select') $Content = $this->ShowSelect($Table);
    else if ($Action == 'mapselect') $Content = $this->ShowMapSelect($Table);
    else if ($Action == 'edit') $Content = $this->ShowEdit($Table, $ItemId);
    else if ($Action == 'clone') $Content = $this->ShowClone($Table, $ItemId);
    else if ($Action == 'add') $Content = $this->ShowAdd($Table);
    else if ($Action == 'addsub') $Content = $this->ShowAddSub($Table);
    else if ($Action == 'view') $Content = $this->ShowView($Table, $ItemId);
    else if ($Action == 'delete') $Content = $this->ShowDelete($Table, $ItemId);
    else if ($Action == 'fav_add') $Content = $this->ShowFavoriteAdd($Table, $ItemId);
    else if ($Action == 'fav_del') $Content = $this->ShowFavoriteDel($Table, $ItemId);
    else $Content = $this->Dashboard();
    if ($this->HideMenu == false)
    {
      $Output = '<table style="width: 100%"><tr><td style="width: 20%; vertical-align: top;">';
      $MenuTypeText = '<a href="?menutype=0">Nabídka</a>';
      if ($MenuType == 0) $MenuTypeText = '<strong>'.$MenuTypeText.'</strong>';
      $Output .= $MenuTypeText.' ';
      $MenuTypeText = '<a href="?menutype=1">Oblíbené</a>';
      if ($MenuType == 1) $MenuTypeText = '<strong>'.$MenuTypeText.'</strong>';
      $Output .= $MenuTypeText.' ';
      if ($MenuType == 0) $Output .= $this->ShowMenu();
      if ($MenuType == 1) $Output .= $this->ShowFavorites();
      $Output .= '</td><td style="width: 80%; vertical-align: top;">';
      $Output .= $Content;
      $Output .= '</td></tr></table>';
    } else $Output = $Content;

    return $Output;
  }

  function Dashboard(): string
  {
    $Output = '<strong>Nástěnka:</strong><br/>';
    foreach (ModuleIS::Cast($this->System->GetModule('IS'))->DashboardItems as $Item)
    {
      if (is_string($Item['Callback'][0]))
      {
        $Class = new $Item['Callback'][0]($this->System);
        $Method = $Item['Callback'][1];
        $Output .= $Class->$Method();
      } else $Output .= call_user_func($Item['Callback']);
    }
    return $Output;
  }

  function ShowFavoriteAdd(string $Table, string $ItemId): string
  {
    $DbResult = $this->Database->select('MenuItemFavorite', 'Id', '(`MenuItem`='.($_GET['i'] * 1).') AND (`User`='.ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id'].')');
    if ($DbResult->num_rows > 0)
    {
      $Output = $this->SystemMessage('Oblíbené', 'Již existuje v oblíbených');
    } else
    {
      $this->Database->insert('MenuItemFavorite', array('MenuItem' => ($_GET['i'] * 1), 'User' => ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id']));
      $Output = $this->SystemMessage('Oblíbené', 'Přidáno do oblíbených');
    }
    $Output .= $this->ShowList($Table);
    return $Output;
  }

  function ShowFavoriteDel(string $Table, string $ItemId): string
  {
    $DbResult = $this->Database->select('MenuItemFavorite', 'Id', '(`MenuItem`='.($_GET['i'] * 1).') AND (`User`='.ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id'].')');
    if ($DbResult->num_rows > 0)
    {
      $DbRow = $DbResult->fetch_assoc();
      $this->Database->delete('MenuItemFavorite', '`Id`= '.$DbRow['Id']);
      $Output = $this->SystemMessage('Oblíbené', 'Odstraněno z oblíbených');
    } else
    {
      $Output = $this->SystemMessage('Oblíbené', 'Nenalezeno v oblíbených');
    }
    $Output .= $this->ShowList($Table);
    return $Output;
  }

  function LogChange(Form $Form, string $Action, string $NewId, string $OldId): void
  {
    $Values = $Form->Definition['Table'].' (Id: '.$OldId.' => '.$NewId.'):'."\n";
    // Compare old values loaded from database with new values in Form variable
    $NewValues = $Form->Values;
    if ($OldId != 0)
    {
      $FormOld = new Form($this->System->FormManager);
      $FormOld->SetClass($Form->Definition['Table']);
      $FormOld->LoadValuesFromDatabase($OldId);
      $OldValues = $FormOld->Values;
      // Keep only changes values
      foreach ($NewValues as $Index => $Value)
      {
        if ($OldValues[$Index] != $NewValues[$Index])
        {
          $Values .= $Index.': '.$FormOld->GetValue($Index);
          if ($NewId != 0) $Values .= ' => '.$Form->GetValue($Index);
          $Values .= "\n";
        }
      }
    } else
    {
      foreach ($NewValues as $Index => $Value)
      {
        $Values .= $Index.': '.$Form->GetValue($Index)."\n";
      }
    }
    ModuleLog::Cast($this->System->GetModule('Log'))->NewRecord('IS', $Action, $Values);
  }

  function ShowEdit(string $Table, string $Id): string
  {
    $Output = '';
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write'))
      return $this->SystemMessage('Oprávnění', 'Nemáte oprávnění');
    $Form = new Form($this->System->FormManager);
    $Form->SetClass($Table);    
    if ($Form->HasAllPostVariables())
    {
      $Form->LoadValuesFromForm();
      $this->Title .= ' - '.$Form->Definition['Title'].' úprava';
      try
      {
        $Form->Validate();
        if (array_key_exists('BeforeModify', $Form->Definition))
        {
          $Class = $Form->Definition['BeforeModify'][0];
          $Method = $Form->Definition['BeforeModify'][1];
          $Form->Values = $Class->$Method($Form, $Id);
        }
        $this->LogChange($Form, 'Edit', $Id, $Id);
        $Form->SaveValuesToDatabase($Id);
        $Output .= $this->SystemMessage('Úprava položky', 'Položka upravena');
        $Output .= $this->ShowView($Table, $Id);
        if (array_key_exists('AfterModify', $Form->Definition))
        {
          $Class = $Form->Definition['AfterModify'][0];
          $Method = $Form->Definition['AfterModify'][1];
          $Form->Values = $Class->$Method($Form, $Id);
        }
      } catch (Exception $E)
      {
        $Output .= $this->SystemMessage('Úprava položky', 'Položku se nepodařilo uložit. Opravte problém a opakujte akci.<br/>'.$E->getMessage());
        $Form->OnSubmit = '?a=edit&amp;t='.$Table.'&amp;i='.$_GET['i'];
        $Output .= $Form->ShowEditForm();
        $Output .= '<ul class="ActionMenu">';
        $Output .= '<li>'.$this->ShowAction('Prohlížet', '?a=view&amp;t='.$Table.'&amp;i='.$Id,
          $this->System->Link('/images/view.png'));
        $Output .= '<li>'.$this->ShowAction('Duplikovat', '?a=clone&amp;t='.$Table.'&amp;i='.$Id,
          $this->System->Link('/images/clone.png'));
        $Output .= '<li>'.$this->ShowAction('Seznam', '?a=list&amp;t='.$Table,
          $this->System->Link('/images/list.png'));
        $Output .= '<li>'.$this->ShowAction('Odstranit', '?a=delete&amp;t='.$Table.'&amp;i='.$Id,
          $this->System->Link('/images/delete.png'), 'Opravdu smazat položku');
        $Output .= '</ul>';
      }
    } else
    {
      $Form->LoadValuesFromDatabase($Id);
      $this->Title .= ' - '.$Form->Definition['Title'].' úprava';
      $Form->OnSubmit = '?a=edit&amp;t='.$Table.'&amp;i='.$_GET['i'];
      $Output .= $Form->ShowEditForm();
      $Output .= '<ul class="ActionMenu">';
      $Output .= '<li>'.$this->ShowAction('Prohlížet', '?a=view&amp;t='.$Table.'&amp;i='.$Id,
        $this->System->Link('/images/view.png'));
      $Output .= '<li>'.$this->ShowAction('Duplikovat', '?a=clone&amp;t='.$Table.'&amp;i='.$Id,
        $this->System->Link('/images/clone.png'));
      $Output .= '<li>'.$this->ShowAction('Seznam', '?a=list&amp;t='.$Table,
        $this->System->Link('/images/list.png'));
      $Output .= '<li>'.$this->ShowAction('Odstranit', '?a=delete&amp;t='.$Table.'&amp;i='.$Id,
        $this->System->Link('/images/delete.png'), 'Opravdu smazat položku?');
      $Output .= '</ul>';
    }
    return $Output;
  }

  function ShowClone(string $Table, string $Id, array $Actions = array()): string
  {
    $Output = '';
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write'))
      return 'Nemáte oprávnění';
    $Form = new Form($this->System->FormManager);
    $Form->SetClass($Table);
    if ($Form->HasAllPostVariables())
    {
      $Form = new Form($this->System->FormManager);
      $Form->SetClass($Table);
      $Form->LoadValuesFromForm();
      $this->Title .= ' - '.$Form->Definition['Title'].' duplikování';
      try
      {
        $Form->Validate();
        if (array_key_exists('BeforeInsert', $Form->Definition))
        {
          $Class = $Form->Definition['BeforeInsert'][0];
          $Method = $Form->Definition['BeforeInsert'][1];
          $Form->Values = $Class->$Method($Form);
        }
        $Form->Validate();
        $Form->SaveValuesToDatabase(0);
        $Id = $this->Database->insert_id;
        $this->LogChange($Form, 'Clone', $Id, 0);
        $Output .= $this->SystemMessage('Duplikování položky', 'Nová kopie položky vytvořena');
        $Output .= $this->ShowView($Table, $Id, $_GET['a'] == 'addsub');
        if (array_key_exists('AfterInsert', $Form->Definition))
        {
          $Class = $Form->Definition['AfterInsert'][0];
          $Method = $Form->Definition['AfterInsert'][1];
          $Form->Values = $Class->$Method($Form, $Id);
        }

      //$this->Database->update($Table, 'Id='.$Id,
      //  array('UserCreate' => ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id'],
      //  'TimeCreate' => 'NOW()'));
      } catch (Exception $E)
      {
        $Output .= $this->SystemMessage('Duplikování položky', 'Položku se nepodařilo duplikovat. Opravte problém a opakujte akci.<br/>'.$E->getMessage());
        $Form->OnSubmit = '?a=clone&amp;t='.$Table;
        $Output .= $Form->ShowEditForm();
        $Actions[] = '<a href="?a=list&amp;t='.$Table.'"><img alt="Seznam" title="Seznam" src="'.
          $this->System->Link('/images/list.png').'"/>Seznam</a>';
      }
    } else
    {
      $Form->LoadValuesFromDatabase($Id);
      $this->Title .= ' - '.$Form->Definition['Title'].' duplikování';
      $Form->OnSubmit = '?a='.$_GET['a'].'&amp;t='.$Table;
      $Output .= $Form->ShowEditForm();
      $Actions[] = $this->ShowAction('Seznam', '?a=list&amp;t='.$Table,
        $this->System->Link('/images/list.png'));
    }
    $Output .= '<ul class="ActionMenu">';
    foreach ($Actions as $Action)
    {
      $Output .= '<li>'.$Action.'</li>';
    }
    $Output .= '</ul>';
    return $Output;
  }

  function ShowDelete(string $Table, string $Id): string
  {
    $Output = '';
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    $FormClass = $this->System->FormManager->Classes[$Table];
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write'))
      return 'Nemáte oprávnění';
    $DbResult = $this->Database->select($Table, '*', '`Id`='.$Id);
    if ($DbResult->num_rows > 0)
    {
      $DbRow = $DbResult->fetch_assoc();
      try
      {
        $Form = new Form($this->System->FormManager);
        $Form->SetClass($Table);
        $Form->LoadValuesFromDatabase($Id);
        $this->Title .= ' - '.$Form->Definition['Title'].' odstranění';
        if (array_key_exists('BeforeDelete', $Form->Definition))
        {
          call_user_func($Form->Definition['BeforeDelete'], $Form, $Id);
        }
        $this->LogChange($Form, 'Delete', 0, $Id);
        $this->Database->delete($Table, '`Id`='.$Id);
        $Output .= $this->SystemMessage('Smazání položky', 'Položka odstraněna');
        if (array_key_exists('AfterDelete', $Form->Definition))
        {
          $Class = $Form->Definition['AfterDelete'][0];
          $Method = $Form->Definition['AfterDelete'][1];
          $Class->$Method($Form, $Id);
        }
      } catch (Exception $E)
      {
        $Output .= $this->SystemMessage('Smazání položky', 'Položku se nepodařilo smazat. Pravděpodobně na ni závisejí další položky.<br/>'.$E->getMessage());
      }
    } else $Output .= $this->SystemMessage('Smazání položky', 'Položka nenalezena');
    $Output .= $this->ShowList($Table);
    return $Output;
  }

  function ShowAdd(string $Table, array $Actions = array()): string
  {
    $Output = '';
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write'))
      return 'Nemáte oprávnění';
    $Form = new Form($this->System->FormManager);
    $Form->SetClass($Table);
    if ($Form->HasAllPostVariables())
    {
      $Form->LoadValuesFromForm();
      $this->Title .= ' - '.$Form->Definition['Title'].' přidání';
      try
      {
        $Form->Validate();
        if (array_key_exists('BeforeInsert', $Form->Definition))
        {
          $Class = $Form->Definition['BeforeInsert'][0];
          $Method = $Form->Definition['BeforeInsert'][1];
          $Form->Values = $Class->$Method($Form);
        }
        $Form->Validate();
        $Form->SaveValuesToDatabase(0);
        $Id = $this->Database->insert_id;
        $this->LogChange($Form, 'Add', $Id, 0);
        $Output .= $this->SystemMessage('Přidání položky', 'Nová položka vytvořena');
        $Output .= $this->ShowView($Table, $Id, $_GET['a'] == 'addsub');
        if (array_key_exists('AfterInsert', $Form->Definition))
        {
          $Class = $Form->Definition['AfterInsert'][0];
          $Method = $Form->Definition['AfterInsert'][1];
          $Form->Values = $Class->$Method($Form, $Id);
        }
        // Add action to update caller form
        if ($_GET['a'] == 'addsub')
        {
          $Type = $this->System->FormManager->FormTypes[$_GET['rt']];
          $DbResult = $this->Database->select($Table, '('.$Type['Name'].') AS Name', 'Id='.$Id);
          $DbRow = $DbResult->fetch_assoc();
          $Actions[] = '<a href="javascript:window.close();" onclick="add_select_item('.$Id.',&quot;'.$DbRow['Name'].'&quot;,&quot;'.
            $_GET['r'].'&quot;); set_return ('.$Id.',&quot;'.
            $_GET['r'].'&quot;);"><img alt="Vybrat" title="Vybrat" src="'.
            $this->System->Link('/images/select.png').'"/> Vybrat</a>';
        }

      //$this->Database->update($Table, 'Id='.$Id,
      //  array('UserCreate' => ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id'],
      //  'TimeCreate' => 'NOW()'));
      } catch (Exception $E)
      {
        $Output .= $this->SystemMessage('Přidání položky', 'Položku se nepodařilo přidat. Opravte problém a opakujte akci.<br/>'.$E->getMessage());
        $Form->OnSubmit = '?a=add&amp;t='.$Table;
        $Output .= $Form->ShowEditForm();
        $Actions[] = '<a href="?a=list&amp;t='.$Table.'"><img alt="Seznam" title="Seznam" src="'.
          $this->System->Link('/images/list.png').'"/>Seznam</a>';
      }
    } else
    {
      $Form = new Form($this->System->FormManager);
      $Form->SetClass($Table);
      $this->Title .= ' - '.$Form->Definition['Title'].' přidání';
      // Load presets from URL
      foreach ($_GET as $Key => $Value)
      {
        if (substr($Key, 0, 6) == 'preset')
        {
          $Key = substr($Key, 6);
          if (($Key != '') and array_key_exists($Key, $Form->Values))
            $Form->Values[$Key] = $Value;
        }
      }
      if (array_key_exists('r', $_GET)) $URL = '&amp;r='.$_GET['r'].'&amp;rt='.$_GET['rt'];
        else $URL = '';
      $Form->OnSubmit = '?a='.$_GET['a'].'&amp;t='.$Table.$URL;
      $Output .= $Form->ShowEditForm();
      $Actions[] = $this->ShowAction('Seznam', '?a=list&amp;t='.$Table,
        $this->System->Link('/images/list.png'));
    }
    $Output .= '<ul class="ActionMenu">';
    foreach ($Actions as $Action)
    {
      $Output .= '<li>'.$Action.'</li>';
    }
    $Output .= '</ul>';
    return $Output;
  }

  function ShowAddSub(string $Table, string $Filter = '', string $Title = ''): string
  {
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write'))
      return 'Nemáte oprávnění';
    $this->BasicHTML = true;
    $this->HideMenu = true;
    $Output = $this->ShowAdd($Table);
    return $Output;
  }

  function ShowTabs(array $Tabs, string $QueryParamName, string $TabContent): string
  {
    $QueryItems = GetQueryStringArray($_SERVER['QUERY_STRING']);
    $QueryItems['a'] = 'view';

    if (array_key_exists($QueryParamName, $_GET)) $TabIndex = $_GET[$QueryParamName];
      else $TabIndex = 0;

    $Output = '<div class="Tab">'.
      '<ul>';
    foreach ($Tabs as $Index => $Tab)
    {
      $QueryItems[$QueryParamName] = $Index;
      if ($Index == $TabIndex) $Selected = ' id="selected"';
        else $Selected = '';
      $Output .= '<li'.$Selected.'><a href="?'.SetQueryStringArray($QueryItems).'">'.$Tab.'</a></li>';
    }
    $Output .= '</ul></div><div class="TabContent">'.$TabContent.'</div>';
    return $Output;
  }

  function ShowView(string $Table, string $Id, bool $WithoutActions = false): string
  {
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    $FormClass = $this->System->FormManager->Classes[$Table];
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Read'))
      return 'Nemáte oprávnění';

    $FormClass = $this->System->FormManager->Classes[$Table];
    if (array_key_exists('BaseTable', $FormClass)) $TableModify = $FormClass['BaseTable'];
      else $TableModify = $Table;

    $Form = new Form($this->System->FormManager);
    $Form->SetClass($Table);
    $this->Title .= ' - '.$Form->Definition['Title'].' položka';
    $Form->LoadValuesFromDatabase($Id);
    $Form->OnSubmit = '?a=view';
    $Output = $Form->ShowViewForm();
    if ($WithoutActions == false)
    {
      $Actions = array(
        $this->ShowAction('Upravit', '?a=edit&amp;t='.$TableModify.'&amp;i='.$Id,
          $this->System->Link('/images/edit.png')),
        $this->ShowAction('Duplikovat', '?a=clone&amp;t='.$TableModify.'&amp;i='.$Id,
          $this->System->Link('/images/clone.png')),
        $this->ShowAction('Seznam', '?a=list&amp;t='.$Table,
          $this->System->Link('/images/list.png')),
        $this->ShowAction('Odstranit', '?a=delete&amp;t='.$Table.'&amp;i='.$Id,
          $this->System->Link('/images/delete.png'), 'Opravdu smazat položku?'),
        $this->ShowAction('Přidat', '?a=add&amp;t='.$TableModify,
          $this->System->Link('/images/add.png'))
      );
      if (array_key_exists('ItemActions', $FormClass))
      {
        foreach ($FormClass['ItemActions'] as $Action)
        {
          $URL = str_replace('#RowId', $Id, $this->System->Link($Action['URL']));
          $Actions[] = $this->ShowAction($Action['Caption'], $URL,
            $this->System->Link('/images/action.png'));
        }
      }
      $Output .= '<ul class="ActionMenu">';
      foreach ($Actions as $Action)
      {
        $Output .= '<li>'.$Action.'</li>';
      }
      $Output .= '</ul><br/>';
    }

    // Show ManyToOne relations
    $Tabs = array();
    foreach ($Form->Definition['Items'] as $Index => $Item)
    {
      if ((array_key_exists($Item['Type'], $this->System->FormManager->FormTypes) and
      ($this->System->FormManager->FormTypes[$Item['Type']]['Type'] == 'ManyToOne')))
      {
        $Tabs[] = $Item['Caption'];
      }
    }
    if (count($Tabs) > 0)
    {
      if (count($Tabs) > 1)
      {
        $Tabs[] = 'Vše';
      }
      if (array_key_exists('tab', $_GET))
      {
        $TabIndex = $_GET['tab'];
        if (($TabIndex < 0) or ($TabIndex >= count($Tabs)))
        {
          $TabIndex = 0;
        }
      } else $TabIndex = 0;

      $TabContent = '';
      $I = 0;
      foreach ($Form->Definition['Items'] as $Index => $Item)
      if ((array_key_exists($Item['Type'], $this->System->FormManager->FormTypes) and
      ($this->System->FormManager->FormTypes[$Item['Type']]['Type'] == 'ManyToOne')))
      {
        $TypeItem = $this->System->FormManager->FormTypes[$Item['Type']];
        if (($TabIndex == $I) or ((count($Tabs) > 1) and ($TabIndex == (count($Tabs) - 1))))
        {
          if ($TypeItem['Ref'] == null)
          {
            $Filter = $TypeItem['Filter'];
            $Filter = str_replace('#Id', $Id, $Filter);
            $TabContent .= $this->ShowList($TypeItem['Table'],
              $Filter, $Item['Caption']).'<br/>';
          } else $TabContent .= $this->ShowList($TypeItem['Table'], '`'.
            $TypeItem['Ref'].'`='.$Id, $Item['Caption'],
            $TypeItem['Ref'], $Id).'<br/>';
        }
        $I++;
      }

      $Output .= $this->ShowTabs($Tabs, 'tab', $TabContent);
    }
    return $Output;
  }

  function GetParam(string $Name, string $Default): string
  {
    $Result = $Default;
    if (array_key_exists($Name, $_POST) and ($_POST[$Name] != ''))
    {
      $Result = $_POST[$Name];
    }
    if (array_key_exists($Name, $_GET) and ($_GET[$Name] != ''))
    {
      $Result = $_GET[$Name];
    }
    return $Result;
  }

  function ShowTable(string $Table, string $Filter = '', string $Title = '', string $RowActions = '', string $ExcludeColumn = ''): string
  {
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    $FormClass = $this->System->FormManager->Classes[$Table];

    if (array_key_exists('SQL', $FormClass))
      $SourceTable = '('.$FormClass['SQL'].') AS `TX`';
      else $SourceTable = '`'.$FormClass['Table'].'` AS `TX`';

    $WhereFilter = $Filter;
    $HavingFilter = '';

    // Build form type filter
    $TypeFilter = '';
    foreach ($FormClass['Items'] as $ItemIndex => $FormItem)
    if (!array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) or
    (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) and
    ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] != 'ManyToOne')))
    if (array_key_exists('Filter', $FormItem) and ($FormItem['Filter'] == true))
    {
      if ($TypeFilter != '') $TypeFilter .= ' AND ';
      $TypeFilter .= '(`'.$ItemIndex.'` = "'.$FormItem['Default'].'")';
    }
    if ($TypeFilter != '')
    {
      if ($HavingFilter != '') $HavingFilter = ' AND';
      $HavingFilter .= ' '.$TypeFilter;
    }

    // Build user filter
    $UserFilter = '';
    $Columns = array('Id' => '`Id`');
    if (array_key_exists('filter', $_GET) and ($_GET['filter'] == 1))
    {
      foreach ($FormClass['Items'] as $ItemIndex => $FormItem)
      if (!array_key_exists('Hidden', $FormItem) or ($FormItem['Hidden'] == false))
      if (!array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) or
      (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) and
      ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] != 'ManyToOne')))
      {
        $UseType = $UseType = $FormItem['Type'];
        if (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes))
        {
          if (!array_key_exists($FormItem['Type'], $this->System->FormManager->Type->TypeDefinitionList))
            $this->System->FormManager->Type->RegisterType($FormItem['Type'], '',
              $this->System->FormManager->FormTypes[$FormItem['Type']]);
          if ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] == 'Reference')
          $UseType = 'OneToMany';
          else
          if ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] == 'Enumeration')
          $UseType = 'Enumeration';
        }
        $FilterName = $this->System->FormManager->Type->ExecuteTypeEvent($UseType, 'OnFilterName',
          array('Name' => $ItemIndex, 'Type' => $FormItem['Type']));

        $SqlOperator = array(
          'like' => 'LIKE',
          'notlike' => 'NOT LIKE',
          'equal' => '=',
          'notequal' => '!=',
          'less' => '<',
          'lessorequal' => '<=',
          'greater' => '>',
          'greaterorequal' => '>=',
          'isnull' => 'IS NULL',
          'isnotnull' => 'IS NOT NULL',
        );
        $Operator = $this->GetParam('FilterOp'.$ItemIndex, 'like');
        if (array_key_exists($Operator, $SqlOperator))
        {
          $OperatorSql = $SqlOperator[$Operator];
        } else $OperatorSql = $SqlOperator['like'];

        $FilterValue = $this->GetParam('Filter'.$ItemIndex, '');
        if ($FilterValue != '')
        {
          if ($UserFilter != '') $UserFilter .= ' AND ';
          $UserFilter .= '('.$FilterName.' '.$OperatorSql;
          if (($Operator == 'like') or ($Operator == 'notlike')) $UserFilter .= ' "%'.$FilterValue.'%")';
            else if (($Operator == 'isnull') or ($Operator == 'isnotnull')) $UserFilter .= ')';
            else $UserFilter .= ' "'.$FilterValue.'")';
        }
      }
    }
    if ($UserFilter != '')
    {
      if ($HavingFilter != '') $HavingFilter .= ' AND';
      $HavingFilter .= ' '.$UserFilter;
    }
    if ($WhereFilter != '') $Filter = ' WHERE '.$WhereFilter;
    if ($HavingFilter != '') $Filter = ' HAVING '.$HavingFilter;


    foreach ($FormClass['Items'] as $ItemIndex => $FormItem)
      if (!array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) or
      (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) and
      ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] != 'ManyToOne')))
      {
        if ($ExcludeColumn != $ItemIndex)
        if (!array_key_exists('Hidden', $FormItem) or ($FormItem['Hidden'] == false))
        if (!array_key_exists('NotInList', $FormItem) or ($FormItem['NotInList'] == false))
          $TableColumns[] = array('Name' => $ItemIndex, 'Title' => $FormItem['Caption']);
        $UseType = $UseType = $FormItem['Type'];
        if (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes))
        {
          if (!array_key_exists($FormItem['Type'], $this->System->FormManager->Type->TypeDefinitionList))
            $this->System->FormManager->Type->RegisterType($FormItem['Type'], '',
                $this->System->FormManager->FormTypes[$FormItem['Type']]);
          if ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] == 'Reference')
            $UseType = 'OneToMany';
          else
            if ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] == 'Enumeration')
            $UseType = 'Enumeration';
        }
        if (array_key_exists('Filter'.$ItemIndex, $_POST) and ($_POST['Filter'.$ItemIndex] != ''))
          $Value = $_POST['Filter'.$ItemIndex];
          else $Value = '';
        if ($ItemIndex == 'Id') unset($Columns['Id']);

        if (!array_key_exists('SQL', $FormItem)) $FormItem['SQL'] = '';
          else $FormItem['SQL'] = str_replace('#Id', '`TX`.`Id`', $FormItem['SQL']);
        $Columns[] = $this->System->FormManager->Type->ExecuteTypeEvent($UseType, 'OnFilterNameQuery',
          array('Value' => $Value, 'Name' => $ItemIndex,
            'Type' => $FormItem['Type'], 'SQL' => $FormItem['SQL']));
      }

    // Get total item count in database
    $Query = 'SELECT COUNT(*) FROM '.$SourceTable;
    $DbResult = $this->Database->query($Query);
    $DbRow = $DbResult->fetch_assoc();
    $TotalCount = $DbRow['COUNT(*)'];

    // Get total filtered item count in database
    $Columns = implode(',', $Columns);
    if ($Filter != '')
    {
      $Query = 'SELECT COUNT(*) FROM (SELECT '.$Columns.' FROM '.$SourceTable.' '.$Filter.') AS `TS`';
      $DbResult = $this->Database->query($Query);
      $DbRow = $DbResult->fetch_row();
      $TotalFilteredCount = $DbRow[0];
    } else $TotalFilteredCount = $TotalCount;
    $PageList = GetPageList($Table, $TotalFilteredCount);

    $Output = $PageList['Output'];
    $Output .= '<table class="WideTable" style="font-size: small;">';

    $TableColumns[] = array('Name' => '', 'Title' => 'Akce');
    if (!array_key_exists('DefaultSortColumn', $FormClass))
      $FormClass['DefaultSortColumn'] = 'Id';
    if (!array_key_exists('DefaultSortOrder', $FormClass))
      $FormClass['DefaultSortOrder'] = 0;
    $Order = GetOrderTableHeader($Table, $TableColumns, $FormClass['DefaultSortColumn'], $FormClass['DefaultSortOrder']);
    $Output .= $Order['Output'];

    // Show search fields
    if (array_key_exists('r', $_GET)) $Addition = '&amp;r='.$_GET['r'];
      else $Addition = '';
    $Output .= '<tr><form action="?a='.$_GET['a'].'&amp;t='.$Table.'&amp;filter=1'.$Addition.'" method="post">';
    foreach ($FormClass['Items'] as $ItemIndex => $FormItem)
    if (!array_key_exists('Hidden', $FormItem) or ($FormItem['Hidden'] == false))
    if (!array_key_exists('NotInList', $FormItem) or ($FormItem['NotInList'] == false))
    if ((!array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) or
    (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) and
    ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] != 'ManyToOne'))) and
    ($ExcludeColumn != $ItemIndex))
    {
      if (array_key_exists('Filter'.$ItemIndex, $_POST) and ($_POST['Filter'.$ItemIndex] != ''))
        $Value = $_POST['Filter'.$ItemIndex];
        else $Value = '';
      $Output .= '<td><input type="text" name="Filter'.$ItemIndex.'" value="'.$Value.'" style="width: 100%"/></td>';
    }
    $Output .= '<td><input type="Submit" value="Hledat"/></td></form></tr>';

    // Load and show items
    $Query = 'SELECT '.$Columns.' FROM '.$SourceTable.' '.
      $Filter.' '.$Order['SQL'].$PageList['SQLLimit'];
    $VisibleItemCount = 0;
    $DbResult = $this->Database->query($Query);
    while ($Row = $DbResult->fetch_assoc())
    {
      $Output .= '<tr>';
      foreach ($FormClass['Items'] as $ItemIndex => $FormItem)
      if (!array_key_exists('Hidden', $FormItem) or ($FormItem['Hidden'] == false))
      if (!array_key_exists('NotInList', $FormItem) or ($FormItem['NotInList'] == false))
      if ((!array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) or
      (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes) and
      ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] != 'ManyToOne'))) and
      ($ExcludeColumn != $ItemIndex))
      {
        //$Output .= '<td>'.$Row[$ItemIndex].'</td>';
        $UseType = $UseType = $FormItem['Type'];
        if (array_key_exists($FormItem['Type'], $this->System->FormManager->FormTypes))
        {
          if (!array_key_exists($FormItem['Type'], $this->System->FormManager->Type->TypeDefinitionList))
            $this->System->FormManager->Type->RegisterType($FormItem['Type'], '',
              $this->System->FormManager->FormTypes[$FormItem['Type']]);
          if ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] == 'Reference')
          $UseType = 'OneToMany';
          else
          if ($this->System->FormManager->FormTypes[$FormItem['Type']]['Type'] == 'Enumeration')
          $UseType = 'Enumeration';
        }
        $Row[$ItemIndex] = $this->System->FormManager->Type->ExecuteTypeEvent($UseType, 'OnLoadDb',
          array('Value' => $Row[$ItemIndex], 'Name' => $ItemIndex,
          'Type' => $FormItem['Type']));
        $Value = $this->System->FormManager->Type->ExecuteTypeEvent($UseType, 'OnView',
          array('Value' => $Row[$ItemIndex], 'Name' => $ItemIndex,
          'Type' => $FormItem['Type'], 'Filter' => $Row[$ItemIndex.'_Filter']));
        if ($Value == '') $Value = '&nbsp;';
        $Output .= '<td>'.$Value.'</td>';
      }
      $Output .= '<td>'.str_replace('#RowId', $Row['Id'], $RowActions).'</td></tr>';
      $VisibleItemCount = $VisibleItemCount + 1;
    }
    $Output .= '<tr><td colspan="'.count($TableColumns).'" style="text-align: right;">Zobrazeno <strong>'.$VisibleItemCount.'</strong>';
    if ($UserFilter != '') $Output .= ' z filtrovaných <strong>'.$TotalFilteredCount.'</strong>';
    $Output .= ' z celkem <strong>'.$TotalCount.'</strong></td></tr>';
    $Output .= '</table>';
    $Output .= $PageList['Output'];
    return $Output;
  }

  function ShowSelect(string $Table, string $Filter = '', string $Title = ''): string
  {
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Read'))
      return 'Nemáte oprávnění';
    $this->BasicHTML = true;
    $this->HideMenu = true;
    $RowActions = '<a href="javascript:window.close();" onclick="set_return (#RowId,&quot;'.
      $_GET['r'].'&quot;);"><img alt="Vybrat" title="Vybrat" src="'.
      $this->System->Link('/images/select.png').'"/></a>';
    $Output = $this->ShowTable($Table, $Filter, $Title, $RowActions);
    return $Output;
  }

  function ShowMapSelect(string $Table, string $Filter = '', string $Title = ''): string
  {
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write'))
      return 'Nemáte oprávnění';
    $Map = new MapOpenStreetMaps($this->System);
    $Map->Position = array('Lat' => $this->System->Config['Map']['DefaultLatitude'],
      'Lng' => $this->System->Config['Map']['DefaultLongitude']);
    $Map->Zoom = $this->System->Config['Map']['DefaultZoom'];
    $Map->Key = $this->System->Config['Map']['GoogleMapsApiKey'];
    $Map->OnClickObject = $_GET['r'];
    //$MapApi->ShowMarker = true;
    $Output = $Map->ShowPage($this);
    return $Output;
  }

  function ShowList(string $Table, string $Filter = '', string $Title = '', string $ExcludeColumn = '', string $ExcludeValue = ''): string
  {
    $Output = '';
    if (defined('NEW_PERMISSION') and !ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Read'))
      return 'Nemáte oprávnění';
    if (!array_key_exists($Table, $this->System->FormManager->Classes))
      return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    $FormClass = $this->System->FormManager->Classes[$Table];
    if (array_key_exists('BaseTable', $FormClass)) $TableModify = $FormClass['BaseTable'];
      else $TableModify = $Table;

    $RowActions =
      $this->ShowAction('Ukázat', '?a=view&amp;t='.$Table.'&amp;i=#RowId', $this->System->Link('/images/view.png')).
      $this->ShowAction('Upravit', '?a=edit&amp;t='.$TableModify.'&amp;i=#RowId', $this->System->Link('/images/edit.png')).
      $this->ShowAction('Duplikovat', '?a=clone&amp;t='.$TableModify.'&amp;i=#RowId', $this->System->Link('/images/clone.png')).
      $this->ShowAction('Odstranit', '?a=delete&amp;t='.$Table.'&amp;i=#RowId', $this->System->Link('/images/delete.png'), 'Opravdu smazat položku?;');
    if (($Table != '') and (array_key_exists($Table, $this->System->FormManager->Classes)))
      $FormClass = $this->System->FormManager->Classes[$Table];
      else return $this->SystemMessage('Chyba', 'Tabulka '.$Table.' nenalezena');
    if ($ExcludeColumn == '') $this->Title .= ' - '.$FormClass['Title'];
    if (array_key_exists('ItemActions', $FormClass))
    {
      foreach ($FormClass['ItemActions'] as $Action)
      {
        $URL = $this->System->Link($Action['URL']);
        $RowActions .= '<a href="'.$URL.'"><img alt="'.$Action['Caption'].'" title="'.$Action['Caption'].'" src="'.
          $this->System->Link('/images/action.png').'"/></a>';
      }
    }
    $Output .= '<div style="text-align: center;">'.$FormClass['Title'].'</div>';
    $Output .= '<ul class="ActionMenu">';
    $Output .= '<li>'.$this->ShowAction('Přidat', '?a=add&amp;t='.$TableModify.'&amp;preset'.$ExcludeColumn.'='.$ExcludeValue, $this->System->Link('/images/add.png')).'</li>';
    $Output .= '<li>'.$this->ShowAction('Seznam', '?a=list&amp;t='.$Table, $this->System->Link('/images/list.png')).'</li>';
    $MI = 0;
    if (array_key_exists('mi', $_GET))
    {
      $DbResult = $this->Database->select('MenuItemFavorite', 'Id', '(`MenuItem`='.($_GET['mi'] * 1).') AND (`User`='.ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id'].')');
      if ($DbResult->num_rows > 0)
      {
        $DbRow = $DbResult->fetch_assoc();
        $Fav = $DbRow['Id'];
        $Output .= '<li>'.$this->ShowAction('Odebrat z oblíbených', '?a=fav_del&amp;t='.$Table.'&amp;i='.$_GET['mi'].'&amp;mi='.$_GET['mi'],
          $this->System->Link('/images/Favorite-Del.png')).'</li>';
      } else $Output .= '<li>'.$this->ShowAction('Přidat do oblíbených', '?a=fav_add&amp;t='.$Table.'&amp;i='.$_GET['mi'].'&amp;mi='.$_GET['mi'],
          $this->System->Link('/images/Favorite-Add.png')).'</li>';
    }
    if (array_key_exists('Actions', $FormClass))
    {
      foreach ($FormClass['Actions'] as $Action)
      {
        $Output .= '<li>'.$this->ShowAction($Action['Caption'], $this->System->Link($Action['URL']),
          $this->System->Link('/images/action.png')).'</li>';
      }
    }
    $Output .= '</ul>';
    $Output .= $this->ShowTable($Table, $Filter, $Title, $RowActions, $ExcludeColumn);
    return $Output;
  }

  function ShowFavorites(): string
  {
    $this->MenuItems = array();
    $DbResult = $this->Database->query('SELECT `MenuItem`.`Id`, `MenuItem`.`Name`, `MenuItem`.`Parent`, `Action`.`URL` AS `URL`, `ActionIcon`.`Name` AS `IconName`, `Action`.`PermissionOperation` AS `Permission` FROM `MenuItemFavorite` ' .
      'LEFT JOIN `MenuItem` ON `MenuItem`.`Id` = `MenuItemFavorite`.`MenuItem` '.
      'LEFT JOIN `Action` ON `Action`.`Id` = `MenuItem`.`Action` '.
      'LEFT JOIN `ActionIcon` ON `ActionIcon`.`Id` = `Action`.`Icon` '.
      'WHERE `MenuItemFavorite`.`User`='.ModuleUser::Cast($this->System->GetModule('User'))->User->User['Id'].' '.
      'ORDER BY `MenuItem`.`Parent`,`MenuItem`.`Name`');
    while ($DbRow = $DbResult->fetch_assoc())
    {
      //if ($DbRow['Permission'] != '')
      $this->MenuItems[$DbRow['Id']] = $DbRow;
    }
    return $this->ShowMenuItem('', true);
  }

  function ShowMenu(): string
  {
    $this->MenuItems = array();
    $DbResult = $this->Database->query('SELECT `MenuItem`.`Id`, `MenuItem`.`Name`, `MenuItem`.`Parent`, `Action`.`URL` AS `URL`, `ActionIcon`.`Name` AS `IconName`, `Action`.`PermissionOperation` AS `Permission` FROM `MenuItem` '.
      'LEFT JOIN `Action` ON `Action`.`Id` = `MenuItem`.`Action` '.
      'LEFT JOIN `ActionIcon` ON `ActionIcon`.`Id` = `Action`.`Icon` '.
      'WHERE `MenuItem`.`Menu`=1 '.
      'ORDER BY `MenuItem`.`Parent`,`MenuItem`.`Name`');
    while ($DbRow = $DbResult->fetch_assoc())
    {
      //if ($DbRow['Permission'] != '')
      $this->MenuItems[$DbRow['Id']] = $DbRow;
    }
    return $this->ShowMenuItem('');
  }

  function ShowMenuItem(string $Parent, bool $All = false): string
  {
    $Output = '<ul style="list-style: none; margin-left:1em; padding-left:0em;">';
    foreach ($this->MenuItems as $MenuItem)
    {
      if (($MenuItem['Parent'] == $Parent) or $All)
      {
        $LinkTitle = $MenuItem['Name'];
        if ($MenuItem['URL'] != '')
        {
          $Icon = 'Device.png';
          if (substr($MenuItem['URL'], 0, 4) != 'http') $MenuItem['URL'] = $this->System->Link($MenuItem['URL']);
          $LinkTitle = MakeLink($MenuItem['URL'].'&amp;mi='.$MenuItem['Id'], $LinkTitle);
        } else $Icon = 'Folder.png';
        if ($MenuItem['IconName'] != '') $Image = '<img src="'.$this->System->Link('/images/favicons/'.$MenuItem['IconName']).'"/>&nbsp;';
          else $Image = '<img src="'.$this->System->Link('/images/favicons/'.$Icon).'"/>&nbsp;';
        //if (ModuleUser::Cast($this->System->GetModule('User'))->User->CheckPermission($this->TableToModule($Table), 'Write') or !defined('NEW_PERMISSION'))
          $Output .= '<li>'.$Image.$LinkTitle.'</li>';
        if ($All == false) $Output .= $this->ShowMenuItem($MenuItem['Id']);
      }
    }
    $Output .= '</ul>';
    return $Output;
  }

  function TableToModule(string $Table): string
  {
    $DbResult = $this->Database->query('SELECT (SELECT `Name` FROM `Module` '.
      'WHERE `Module`.`Id`=`Model`.`Module`) AS `Name` FROM `Model` WHERE `Name`="'.$Table.'"');
    if ($DbResult->num_rows == 1)
    {
      $DbRow = $DbResult->fetch_assoc();
      return $DbRow['Name'];
    } else return '';
  }

  function ShowAction(string $Name, string $Target, string $Icon, string $Confirm = ''): string
  {
    $Output = '<img alt="'.$Name.'" title="'.$Name.'" src="'.
      $Icon.'"/>';
    if ($this->ShowActionName) $Output .= $Name;
    if ($Confirm != '')
      $Confirm = ' onclick="return confirmAction(\''.$Confirm.'\');"';
    $Output = '<a href="'.$Target.'"'.$Confirm.'>'.$Output.'</a>';
    return $Output;
  }
}

class Menu extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddString('Name');
    return $Desc;
  }
}

class MenuItem extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddString('Name');
    $Desc->AddReference('Parent', MenuItem::GetClassName());
    $Desc->AddReference('Action', Action::GetClassName());
    $Desc->AddReference('Menu', Menu::GetClassName());
    return $Desc;
  }
}

class MenuItemFavorite extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddReference('User', User::GetClassName());
    $Desc->AddReference('MenuItem', MenuItem::GetClassName());
    return $Desc;
  }
}

class ModuleIS extends Module
{
  public array $DashboardItems;

  function __construct(System $System)
  {
    parent::__construct($System);
    $this->Name = 'IS';
    $this->Title = 'Information system';
    $this->Version = '1.0';
    $this->Creator = 'Chronos';
    $this->License = 'GNU/GPLv3';
    $this->Description = 'User interface for generic information system';
    $this->Dependencies = array(ModuleUser::GetName());
    $this->Models = array(Menu::GetClassName(), MenuItem::GetClassName(), MenuItemFavorite::GetClassName());

    $this->DashboardItems = array();
  }

  function DoStart(): void
  {
    $this->System->RegisterPage(['is'], 'PageIS');
    $this->System->FormManager->RegisterClass('MenuItem', array(
      'Title' => 'Položky nabídky',
      'Table' => 'MenuItem',
      'Items' => array(
        'Name' => array('Type' => 'String', 'Caption' => 'Název', 'Default' => ''),
        'Parent' => array('Type' => 'TMenuItem', 'Caption' => 'Rodič', 'Default' => '', 'Null' => true),
        'Action' => array('Type' => 'TAction', 'Caption' => 'Akce', 'Default' => ''),
        'Menu' => array('Type' => 'TMenu', 'Caption' => 'Nabídka', 'Default' => ''),
        'Items' => array('Type' => 'TMenuItemListParent', 'Caption' => 'Položky'),
      ),
    ));
    $this->System->FormManager->RegisterClass('MenuItemFavorite', array(
      'Title' => 'Oblíbené položky nabídky',
      'Table' => 'MenuItemFavorite',
      'Items' => array(
        'User' => array('Type' => 'TUser', 'Caption' => 'Uživatele', 'Default' => '0'),
        'MenuItem' => array('Type' => 'TMenuItem', 'Caption' => 'Položka nabídky', 'Default' => '0'),
      ),
    ));
    $this->System->FormManager->RegisterClass('Menu', array(
      'Title' => 'Nabídky',
      'Table' => 'Menu',
      'Items' => array(
        'Name' => array('Type' => 'String', 'Caption' => 'Název', 'Default' => ''),
        'Items' => array('Type' => 'TMenuItemListMenu', 'Caption' => 'Položky'),
      ),
    ));
    $this->System->FormManager->RegisterFormType('TMenuItem', array(
      'Type' => 'Reference',
      'Table' => 'MenuItem',
      'Id' => 'Id',
      'Name' => 'Name',
      'Filter' => '1',
    ));
    $this->System->FormManager->RegisterFormType('TMenu', array(
      'Type' => 'Reference',
      'Table' => 'Menu',
      'Id' => 'Id',
      'Name' => 'Name',
      'Filter' => '1',
    ));
  }

  function RegisterDashboardItem(string $Name, callable $Callback): void
  {
    $this->DashboardItems[$Name] = array('Callback' => $Callback);
  }

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

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