<?php

class ModelDesc
{
  public string $Name;
  public array $Columns;
  public array $Indices;
  public string $PrimaryKey;
  public bool $Memory;

  function __construct(string $Name)
  {
    $this->Name = $Name;
    $this->Columns = array();
    $this->Indices = array();
    $this->PrimaryKey = 'Id';
    $this->Memory = false;
  }

  function AddString(string $Name): ModelColumnString
  {
    $Result = new ModelColumnString($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddFloat(string $Name): ModelColumnFloat
  {
    $Result = new ModelColumnFloat($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddText(string $Name): ModelColumnText
  {
    $Result = new ModelColumnText($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddInteger(string $Name): ModelColumnInteger
  {
    $Result = new ModelColumnInteger($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddBigInt(string $Name): ModelColumnBigInt
  {
    $Result = new ModelColumnBigInt($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddDateTime(string $Name): ModelColumnDateTime
  {
    $Result = new ModelColumnDateTime($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddDate(string $Name): ModelColumnDate
  {
    $Result = new ModelColumnDate($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddBoolean(string $Name): ModelColumnBoolean
  {
    $Result = new ModelColumnBoolean($Name);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddReference(string $Name, string $RefTable, bool $Nullable = true): ModelColumnReference
  {
    $Result = new ModelColumnReference($Name, $RefTable);
    $this->Columns[] = $Result;
    $Result->Nullable = $Nullable;
    return $Result;
  }

  function AddEnum(string $Name, array $States): ModelColumnEnum
  {
    $Result = new ModelColumnEnum($Name, $States);
    $this->Columns[] = $Result;
    return $Result;
  }

  function AddChangeAction(): void
  {
    $Column = $this->AddEnum('ChangeAction', array('add', 'modify', 'remove'));
    $Column->Nullable = true;
    $Column = $this->AddDateTime('ChangeTime');
    $Column->Nullable = true;
    $this->AddInteger('ChangeReplaceId');
  }
}

class ModelColumnType
{
  const Integer = 0;
  const String = 1;
  const Float = 2;
  const Text = 3;
  const DateTime = 4;
  const Reference = 5;
  const Boolean = 6;
  const Date = 7;
  const Enum = 8;
  const BigInt = 9;

  static function GetName(int $Index)
  {
    $Text = array('Integer', 'String', 'Float', 'Text', 'DateTime', 'Reference', 'Boolean', 'Date', 'Enum', 'BigInt');
    return $Text[$Index];
  }
}

class ModelColumn
{
  public string $Name;
  public int $Type; // ModelColumnType
  public bool $Nullable;
  public bool $Unique;
  public bool $HasDefault;

  function __construct(string $Name, int $Type, bool $Nullable = false, bool $Unique = false)
  {
    $this->Name = $Name;
    $this->Type = $Type;
    $this->Nullable = $Nullable;
    $this->Unique = $Unique;
    $this->HasDefault = false;
  }

  function GetDefault(): ?string
  {
    return null;
  }
}

class ModelColumnString extends ModelColumn
{
  public ?string $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::String);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return '"'.$this->Default.'"';
  }
}

class ModelColumnFloat extends ModelColumn
{
  public ?float $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::Float);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return '"'.$this->Default.'"';
  }
}

class ModelColumnText extends ModelColumn
{
  public ?string $Default;
  public int $MaxLength;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::Text);
    $this->HasDefault = false;
    $this->Default = null;
    $this->MaxLength = 255;
  }

  function GetDefault(): ?string
  {
    return '"'.$this->Default.'"';
  }
}

class ModelColumnInteger extends ModelColumn
{
  public ?int $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::Integer);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return $this->Default;
  }
}

class ModelColumnBigInt extends ModelColumn
{
  public ?int $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::BigInt);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return $this->Default;
  }
}

class ModelColumnDateTime extends ModelColumn
{
  public ?DateTime $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::DateTime);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return '"'.$this->Default.'"';
  }
}

class ModelColumnDate extends ModelColumn
{
  public ?DateTime $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::Date);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return '"'.$this->Default.'"';
  }
}

class ModelColumnReference extends ModelColumn
{
  public string $RefTable;

  function __construct(string $Name, string $RefTable)
  {
    parent::__construct($Name, ModelColumnType::Reference);
    $this->RefTable = $RefTable;
  }
}

class ModelColumnBoolean extends ModelColumn
{
  public ?bool $Default;

  function __construct(string $Name)
  {
    parent::__construct($Name, ModelColumnType::Boolean);
    $this->HasDefault = false;
    $this->Default = null;
  }

  function GetDefault(): ?string
  {
    return $this->Default;
  }
}

class ModelColumnEnum extends ModelColumn
{
  public ?bool $Default;
  public array $States;

  function __construct(string $Name, array $States)
  {
    parent::__construct($Name, ModelColumnType::Enum);
    $this->HasDefault = false;
    $this->Default = null;
    $this->States = $States;
  }

  function GetDefault(): ?string
  {
    return $this->Default;
  }
}
