<?php

class ModuleDocument extends Module
{
  function __construct(System $System)
  {
    parent::__construct($System);
    $this->Name = 'Document';
    $this->Version = '1.0';
    $this->Creator = 'Chronos';
    $this->License = 'GNU/GPLv3';
    $this->Description = 'Documents support';
    $this->Models = array(FinanceYear::GetClassName(), DocumentLineCode::GetClassName(), DocumentLine::GetClassName(),
      DocumentLineSequence::GetClassName());
  }

  function DoStart(): void
  {
    $this->System->FormManager->RegisterClass('DocumentLine', array(
      'Title' => 'Dokladové řady',
      'Table' => 'DocumentLine',
      'DefaultSortColumn' => 'Name',
      'Items' => array(
        'Name' => array('Type' => 'String', 'Caption' => 'Jméno', 'Default' => ''),
        'Shortcut' => array('Type' => 'String', 'Caption' => 'Kód', 'Default' => ''),
        'Yearly' => array('Type' => 'Boolean', 'Caption' => 'Ročně', 'Default' => 0),
        'Sequence' => array('Type' => 'TDocumentLineSequenceListLine', 'Caption' => 'Čísleníky', 'Default' => ''),
        'Codes' => array('Type' => 'TDocumentLineCodeList', 'Caption' => 'Kódy', 'Default' => ''),
        'Operations' => array('Type' => 'TFinanceOperationGroupListDocumentLine', 'Caption' => 'Skupiny finančních operací', 'Default' => ''),
        'Invoices' => array('Type' => 'TFinanceInvoiceGroupListDocumentLine', 'Caption' => 'Skupiny faktur', 'Default' => ''),
      ),
    ));
    $this->System->FormManager->RegisterClass('DocumentLineSequence', array(
      'Title' => 'Čísleníky dokladových řad',
      'Table' => 'DocumentLineSequence',
      'DefaultSortColumn' => 'Id',
      'Items' => array(
        'DocumentLine' => array('Type' => 'TDocumentLine', 'Caption' => 'Dokladová řada', 'Default' => ''),
        'FinanceYear' => array('Type' => 'TFinanceYear', 'Caption' => 'Účetní rok', 'Default' => ''),
        'NextNumber' => array('Type' => 'Integer', 'Caption' => 'Další číslo', 'Default' => '1'),
        'YearPrefix' => array('Type' => 'Boolean', 'Caption' => 'Rok jako přípona', 'Default' => '1'),
      ),
    ));
    $this->System->FormManager->RegisterClass('DocumentLineCode', array(
      'Title' => 'Kód dokladových řad',
      'Table' => 'DocumentLineCode',
      'DefaultSortColumn' => 'Name',
      'Items' => array(
        'DocumentLine' => array('Type' => 'TDocumentLine', 'Caption' => 'Dokladová řada', 'Default' => ''),
        'Name' => array('Type' => 'String', 'Caption' => 'Název', 'Default' => ''),
      ),
    ));
    $this->System->FormManager->RegisterClass('FinanceYear', array(
      'Title' => 'Účetní roky',
      'Table' => 'FinanceYear',
      'DefaultSortColumn' => 'Year',
      'DefaultSortOrder' => 1,
      'Items' => array(
        'Year' => array('Type' => 'Integer', 'Caption' => 'Rok', 'Default' => ''),
        'DateStart' => array('Type' => 'Date', 'Caption' => 'První den', 'Default' => ''),
        'DateEnd' => array('Type' => 'Date', 'Caption' => 'Poslední den', 'Default' => ''),
        'Closed' => array('Type' => 'Boolean', 'Caption' => 'Uzavřen', 'Default' => 0),
        'Sequence' => array('Type' => 'TDocumentLineSequenceListYear', 'Caption' => 'Čísleníky', 'Default' => ''),
      ),
      //'AfterInsert' => array($this, 'AfterInsertFinanceYear'),
    ));
    $this->System->FormManager->RegisterFormType('TDocumentLine', array(
      'Type' => 'Reference',
      'Table' => 'DocumentLine',
      'Id' => 'Id',
      'Name' => 'Name',
      'Filter' => '1',
    ));
    $this->System->FormManager->RegisterFormType('TDocumentLineCode', array(
      'Type' => 'Reference',
      'Table' => 'DocumentLineCode',
      'Id' => 'Id',
      'Name' => 'Name',
      'Filter' => '1',
    ));
  }

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

  function GetFinanceYear(int $Year): array
  {
    if ($Year == 0)
    {
      // Get latest year
      $DbResult = $this->Database->select('FinanceYear', '*', '1 ORDER BY `Year` DESC LIMIT 1');
    } else $DbResult = $this->Database->select('FinanceYear', '*', '`Year`='.$Year);
    if ($DbResult->num_rows == 0)
    {
	    if ($Year == date('Y'))
	    {
		    $this->CreateFinanceYear($Year);
        $DbResult = $this->Database->select('FinanceYear', '*', '`Year`='.$Year);
	    } else throw new Exception('Rok '.$Year.' nenalezen');
	  }
    $FinanceYear = $DbResult->fetch_assoc();
    if ($FinanceYear['Closed'] == 1)
      throw new Exception('Rok '.$FinanceYear['Year'].' je již uzavřen. Nelze do něj přidávat položky.');
    return $FinanceYear;
  }

  function GetNextDocumentLineNumber(string $Id, int $FinanceYear = 0): string
  {
	  $FinanceYear = $this->GetFinanceYear($FinanceYear);

    $DbResult = $this->Database->query('SELECT `Shortcut`, `Id` FROM `DocumentLine` WHERE `Id`='.$Id);
    $DocumentLine = $DbResult->fetch_assoc();

    $DbResult = $this->Database->query('SELECT * FROM `DocumentLineSequence` WHERE '.
      '`DocumentLine`='.$Id.' AND `FinanceYear`='.$FinanceYear['Id']);
    if ($DbResult->num_rows > 0)
    {
      $Sequence = $DbResult->fetch_assoc();
    } else 
    {
      $Sequence = array('DocumentLine' => $Id, 'FinanceYear' => $FinanceYear['Id'], 
        'NextNumber' => 1, 'YearPrefix' => 1);
      $Sequence['Id'] = $this->Database->insert('DocumentLineSequence', $Sequence);
    }

    if ($Sequence['YearPrefix'] == 1)
    {
      $Result = $DocumentLine['Shortcut'].$Sequence['NextNumber'].'/'.$FinanceYear['Year'];
    } else
    {
      $Result = $DocumentLine['Shortcut'].$Sequence['NextNumber'];
    }

    $this->Database->query('UPDATE `DocumentLineSequence` SET `NextNumber` = `NextNumber` + 1 '.
      'WHERE (`DocumentLine`='.$Id.') AND (`FinanceYear`='.$FinanceYear['Id'].')');
    return $Result;
  }

  function GetNextDocumentLineNumberId(string $Id, int $FinanceYear = 0): int
  {
    $Code = $this->GetNextDocumentLineNumber($Id, $FinanceYear);
    $this->Database->insert('DocumentLineCode', array('DocumentLine' => $Id, 'Name' => $Code));
    return $this->Database->insert_id;
  }

  function CreateFinanceYear(int $Year)
  {
    $StartTime = mktime(0, 0, 0, 1, 1, $Year);
    $EndTime = mktime(0, 0, 0, 12, 31, $Year);
    $this->Database->insert('FinanceYear', array('Year' => $Year,
	    'DateStart' => TimeToMysqlDate($StartTime), 'DateEnd' => TimeToMysqlDate($EndTime), 'Closed' => 0));
	  $YearId = $this->Database->insert_id;

    // Create DocumentLineSequence from previous
    $DbResult = $this->Database->select('DocumentLine', 'Id', '`Yearly` = 1');
    while ($DbRow = $DbResult->fetch_assoc())
    {
	    $this->Database->insert('DocumentLineSequence', array('FinanceYear' => $YearId,
	      'NextNumber' => 1, 'YearPrefix' => 1, 'DocumentLine' => $DbRow['Id']));
	  }
  }
}

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

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

class DocumentLineSequence extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddReference('DocumentLine', DocumentLine::GetClassName());
    $Desc->AddReference('FinanceYear', FinanceYear::GetClassName());
    $Desc->AddInteger('NextNumber');
    $Desc->AddString('YearPrefix');
    return $Desc;
  }
}

class FinanceYear extends Model
{
  static function GetModelDesc(): ModelDesc
  {
    $Desc = new ModelDesc(self::GetClassName());
    $Desc->AddInteger('Year');
    $Desc->AddDate('DateStart');
    $Desc->AddDate('DateEnd');
    $Desc->AddBoolean('Closed');
    return $Desc;
  }
}
