<?php

function ReadSessionVar(string $Name, bool $Persistent = true): string
{
  $Result = '';
  if ($Persistent)
    if (array_key_exists($Name, $_SESSION)) $Result = $_SESSION[$Name];
  if (array_key_exists($Name, $_GET))
  {
    $Result = $_GET[$Name];
    if ($Persistent) $_SESSION[$Name] = $Result;
  }
  return $Result;
}

class Element
{
  public string $Id;
  public bool $Enabled;
  public bool $Visible;

  function __construct()
  {
    $this->Visible = true;
    $this->Enabled = true;
  }

  function Show(): string
  {
    $Output = '';
    //$Output .= '#'.$this->Id;
    return $Output;
  }

  function Prepare(): void
  {
  }
}

class Layout extends Element
{
  public array $Items;

  function Show(): string
  {
    if ($this->Visible)
    {
      $Output = parent::Show();
      foreach ($this->Items as $Item)
        $Output .= $Item->Show();
      return $Output;
    }
  }

  function Prepare(): void
  {
    foreach ($this->Items as $Item)
      $Item->Prepare();
  }
}

class Button extends Element
{
  public string $Caption;

  function Show(): string
  {
    if ($this->Visible)
    {
      return parent::Show().'<button>'.$this->Caption.'</button>';
    }
  }
}

class Edit extends Element
{
  public string $Text;

  function Show(): string
  {
    return parent::Show().'<input type="text" name="'.$this->Id.'" value="'.$this->Text.'"/>';
  }

  function Prepare(): void
  {
    $this->Text = ReadSessionVar($this->Id.'_Text');
  }
}

class PageSelect extends Element
{
  public int $Count;
  public int $Position;
  public int $PageSize;

  function __construct()
  {
    parent::__construct();
    $this->PageSize = 10;
    $this->Position = 0;
    $this->Count = 0;
  }

  function Show(): string
  {
    if (array_key_exists($this->Id.'_Page', $_GET))
      $this->Position = $_GET[$this->Id.'_Page'];
    if ($this->Position >= $this->Count) $this->Position = $this->Count / $this->PageSize - 1;
    $Output = '';
    for ($I = 0; $I < $this->Count / $this->PageSize; $I++)
    {
      $Text = '<a href="?'.$this->Id.'_Page='.$I.'">'.$I.'</a> ';
      if ($I == $this->Position) $Text = '<strong>'.$Text.'</strong>';
      $Output .= $Text;
    }
    $Output .= '<br/>';
    return $Output;
  }

  function Prepare(): void
  {
    $this->Position = ReadSessionVar($this->Id.'_Page');
  }
}

class ListViewColumn extends Element
{
  public string $Name;

  function Show(): string
  {
    return $this->Name;
  }
}

class ListView extends Element
{
  public array $Columns;
  public array $Rows;
  public $OnColumnClick;
  public $OnColumnDraw;

  function __construct()
  {
    parent::__construct();
    $this->Rows = array();
    $this->Columns = array();
  }

  function Show(): string
  {
    $Output = '<table class="WideTable" style="font-size: small;><tr>';
    foreach ($this->Columns as $Column)
    {
      if ($this->OnColumnDraw != '') $Text = call_user_func($this->OnColumnDraw, $Column);
        else $Text = $Column->Show();
      $Output .= '<th>'.$Text.'</th>';
    }
    $Output .= '</tr>';
    foreach ($this->Rows as $Row)
    {
      $Output .= '<tr>';
      foreach ($Row as $Value)
        $Output .= '<td>'.$Value.'</td>';
      $Output .= '</tr>';
    }
    $Output .= '</table>';
    return $Output;
  }
}

class PageListView extends ListView
{
  public PageSelect $PageSelect;
  public int $SortOrder;
  public string $SortColumn;
  public array $OrderArrowImage;

  function __construct()
  {
    parent::__construct();
    $this->PageSelect = new PageSelect();
    $this->OrderArrowImage = array('sort_asc.png', 'sort_desc.png');
    $this->SortOrder = 0;
    $this->SortColumn = '';
  }

  function ColumnClick(ListViewColumn $Column): string
  {
    return '?'.$this->Id.'_SortColumn='.$Column->Id.'&amp;'.$this->Id.'_SortOrder='.(1 - $this->SortOrder);
  }

  function ColumnDraw(ListViewColumn $Column): string
  {
    global $System;

    $Output = $Column->Show();

    if ($Column->Name == $this->SortColumn)
    {
      $Output .= '<img style="vertical-align: middle; border: 0px;" src="'.
        $System->Link('/images/'.$this->OrderArrowImage[$this->SortOrder]).'" alt="order arrow">';
    }
    if ($this->OnColumnClick != '')
      $Output = '<a href="'.call_user_func($this->OnColumnClick, $Column).'">'.$Output.'</a>';
    return $Output;
  }

  function Show(): string
  {
    $this->PageSelect->Count = count($this->Rows);
    $this->OnColumnClick = array($this, 'ColumnClick');
    $this->OnColumnDraw = array($this, 'ColumnDraw');
    $Output = $this->PageSelect->Show();
    $Output .= parent::Show();
    $Output .= $this->PageSelect->Show();
    return $Output;
  }

  function Prepare(): void
  {
    $this->PageSelect->Id = $this->Id.'PageSelect';
    $this->PageSelect->Prepare();
    $this->SortColumn = ReadSessionVar($this->Id.'_SortColumn');
    $this->SortOrder = ReadSessionVar($this->Id.'_SortOrder');
  }
}

class TableLayout extends Element
{
  public array $Rows;
  public string $Span;

  function Show(): string
  {
    $Output = '<table>';
    foreach ($this->Rows as $RowNum => $Row)
    {
      $Output .= '<tr>';
      foreach ($Row as $ColNum => $Value)
      {
        if ($this->Span[$RowNum][$ColNum] != 1) $Span = ' colspan="'.$this->Span[$RowNum][$ColNum].'"';
          else $Span = '';
        $Output .= '<td'.$Span.'>'.$Value->Show().'</td>';
      }
      $Output .= '</tr>';
    }
    $Output .= '</table>';
    return $Output;
  }

  function Prepare(): void
  {
    foreach ($this->Rows as $RowNum => $Row)
    {
      foreach ($Row as $ColNum => $Value)
      {
        $Value->Prepare();
      }
    }
  }
}

class Label extends Element
{
  public string $Caption;
  public $OnExecute;

  function Show(): string
  {
    $Output = $this->Caption;
    if (method_exists($this->OnExecute[0], $this->OnExecute[1]))
    {
      $Link = 'O='.$this->Id.'&amp;M=Execute';
      $Output = '<a href="?'.$Link.'">'.$Output.'</a>';
    };
    return $Output;
  }

  function Prepare(): void
  {
    $Object = ReadSessionVar('O', false);
    $Method = ReadSessionVar('M', false);
    if (($Object == $this->Id) and ($Method == 'Execute'))
      call_user_func($this->OnExecute, $this);
  }
}

class Page2
{
  public array $Items;

  function Show(): string
  {
    $Output = '<!DOCTYPE html><html><head></head><body>';
    foreach ($this->Items as $Item)
      $Output .= $Item->Show();
    $Output .= '</body></html>';
    return $Output;
  }

  function Prepare(): void
  {
    foreach ($this->Items as $Item)
      $Item->Prepare();
  }
}
