<?php

class ModuleLog extends Module
{
  var $Excludes;

  function __construct(System $System)
  {
    parent::__construct($System);
    $this->Name = 'Log';
    $this->Version = '1.0';
    $this->Creator = 'Chronos';
    $this->License = 'GNU/GPL';
    $this->Description = 'Log various application events';
    $this->Dependencies = array('Error', 'News', 'Translation');

    $this->Excludes = array();
  }

  function DoStart(): void
  {
    $this->System->RegisterPage(['log'], 'PageLog');
    $this->System->ModuleManager->Modules['Error']->OnError[] = array($this, 'DoAddItem');
    $this->System->ModuleManager->Modules['News']->RegisterRSS(array('Title' => T('Logs'),
      'Channel' => 'log', 'Callback' => array('PageLog', 'ShowRSS'), 'Permission' => LICENCE_ADMIN));
  }

  function DoAddItem($Message)
  {
    $this->WriteLog($Message, LOG_TYPE_ERROR);
  }

  function WriteLog($Text, $Type)
  {
    $User = ModuleUser::Cast($this->System->GetModule('User'))->User;
    if (isset($User) and !is_null($User->Id))
      $UserId = $User->Id;
      else $UserId = 'NULL';
    $Query = 'INSERT INTO `Log` ( `User` , `Type` , `Text` , `Date` , `IP`, `URL` ) '.
      'VALUES ('.$UserId.', '.$Type.', "'.addslashes($Text).'", NOW(), "'.
      GetRemoteAddress().'", "'.GetRequestURI().'")';
    $this->System->Database->query($Query);
  }

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

// Log types
define('LOG_TYPE_TRANSLATION', 1);
define('LOG_TYPE_DOWNLOAD', 2);
define('LOG_TYPE_USER', 3);
define('LOG_TYPE_MODERATOR', 4);
define('LOG_TYPE_ERROR', 10);
define('LOG_TYPE_IMPORT', 11);
define('LOG_TYPE_EXPORT', 12);
define('LOG_TYPE_CZWOW', 13);
define('LOG_TYPE_ADMINISTRATION', 14);
define('LOG_TYPE_PAGE_NOT_FOUND', 15);

// TODO: Change global function to module class local method
function WriteLog($Text, $Type)
{
  global $System, $User;

  if (isset($User) and !is_null($User->Id)) $UserId = $User->Id;
    else $UserId = 'NULL';
  $Query = 'INSERT INTO `Log` ( `User` , `Type` , `Text` , `Date` , `IP`, `URL` ) '.
    'VALUES ('.$UserId.', '.$Type.', "'.addslashes($Text).'", NOW(), "'.
      GetRemoteAddress().'", "'.GetRequestURI().'")';
  $System->Database->query($Query);
}

class PageLog extends Page
{
  function ShowRSS()
  {
    $this->RawPage = true;
    $Output = '';
    $Items = array();
    if (array_key_exists('type', $_GET)) $Where = ' WHERE `Type` = "'.($_GET['type'] * 1).'"';
      else $Where = '';
    $sql = 'SELECT *, UNIX_TIMESTAMP(`Date`) AS `TimeCreate`, (SELECT `User`.`Name` FROM `User` WHERE `User`.`ID` = `Log`.`User`) AS `UserName`, `Date` FROM `Log`'.
      $Where.' ORDER BY `Date` DESC LIMIT 100';
    $DbResult = $this->System->Database->query($sql);
    while ($Line = $DbResult->fetch_assoc())
    {
      $DbResult2 = $this->System->Database->query('SELECT * FROM `LogType` WHERE `Id`='.$Line['Type']);
      $LogType = $DbResult2->fetch_assoc();

      if ($Line['Type'] == LOG_TYPE_ERROR) $Line['Text'] = htmlspecialchars($Line['Text']);
      $Line['Text'] = str_replace("\n", '<br>', $Line['Text']);

      $Items[] = array
      (
        'Title' => $LogType['Name'].' ('.$Line['UserName'].', '.$Line['IP'].')',
        'Link' => 'https://'.Core::Cast($this->System)->Config['Web']['Host'].$this->System->Link('/log/'),
        'Description' => $LogType['Name'].': '.$Line['Text'].' ('.$Line['UserName'].
          ', '.$Line['IP'].', '.HumanDate($Line['Date']).')',
        'Time' => $Line['TimeCreate'],
      );
    }

    $Output .= GenerateRSS(array
    (
      'Title' => Core::Cast($this->System)->Config['Web']['Title'].' - '.T('Logs'),
      'Link' => 'https://'.Core::Cast($this->System)->Config['Web']['Host'].$this->System->Link('/'),
      'Description' => Core::Cast($this->System)->Config['Web']['Description'],
      'WebmasterEmail' => Core::Cast($this->System)->Config['Web']['AdminEmail'],
      'Items' => $Items,
    ));
    return $Output;
  }

  function Show(): string
  {
    if (array_key_exists('a', $_POST)) $Action = $_POST['a'];
      else if (array_key_exists('a', $_GET)) $Action = $_GET['a'];
      else $Action = '';
    if ($Action == 'delerrlog') $Output = $this->DeleteErrorLog();
    else $Output = $this->ShowList();
    return $Output;
  }

  function ShowList()
  {
    $User = ModuleUser::Cast($this->System->GetModule('User'))->User;
    $TranslationTree = $this->System->ModuleManager->Modules['Translation']->GetTranslationTree();

    $this->Title = T('System log');
    $Output = '';
    if (array_key_exists('type', $_GET))
    {
      if (is_numeric($_GET['type'])) $_SESSION['type'] = $_GET['type'] * 1;
        else $_SESSION['type'] = '';
    } else if (!array_key_exists('type', $_SESSION)) $_SESSION['type'] = '';

    if (array_key_exists('group', $_GET)) $_SESSION['group'] = $_GET['group'];

    if ($_SESSION['type'] != '') $WhereType = ' (`Type`='.$_SESSION['type'].')';
      else $WhereType = '1=1';

    $RSSChannels = array(
      array('Title' => 'Záznamy změn', 'Channel' => 'log&amp;type='.$_SESSION['type'])
    );

    // Show category filter
    if ($User->Licence(LICENCE_MODERATOR))
    {
      $Output = '<strong>'.T('Filter').':</strong>';
        $Item = '<a href="'.$this->System->Link('/log/?type=').'" title="Bez filtrování">'.T('All').'</a>';
      if ($_SESSION['type'] == '') $Item = '<strong>'.$Item.'</strong>';
      $Output .= ' '.$Item;
      $DbResult = $this->System->Database->query('SELECT * FROM `LogType`');
      while ($LogType = $DbResult->fetch_assoc())
      {
        $Item = '<a href="'.$this->System->Link('/log/?type='.$LogType['Id']).'" style="color:'.
          $LogType['Color'].'" title="'.$LogType['Name'].'">'.T($LogType['Name']).'</a>';
        if ($_SESSION['type'] == $LogType['Id']) $Item = '<strong>'.$Item.'</strong>';
        $Output .= ' '.$Item;
      }
      // echo ' Formát: datum: text zprávy (uživatel, IP)<br /><br />';
     $Output .= '<br /><br />';

    if (array_key_exists('type', $_SESSION)) $Where = ' WHERE '.$WhereType;
    else
    {
      if (array_key_exists('group', $_SESSION)) $Where = ' WHERE `Text` LIKE "%'.$TranslationTree[$_SESSION['group']]['Name'].'%"';
        else $Where = '';
    }
    //if (($Where != '') and (array_key_exists('group', $_SESSION))) $Where .= ' AND text LIKE "%'.$TranslationTree[$_SESSION['group']]['Name'].'%"';

    $DbResult = $this->System->Database->query('SELECT COUNT(*) FROM `Log` '.$Where);
    $DbRow = $DbResult->fetch_row();
    $PageList = GetPageList($DbRow[0]);

    $Output .= $PageList['Output'];

    $TableColumns = array(
      array('Name' => 'Date', 'Title' => T('Time')),
    );
    if ($_SESSION['type'] == '') $TableColumns[] =
      array('Name' => 'LogName', 'Title' => T('Type'));
    $TableColumns = array_merge($TableColumns, array(
      array('Name' => 'Text', 'Title' => T('Content')),
      array('Name' => 'UserName', 'Title' => T('User')),
      array('Name' => 'IP', 'Title' => T('Address')),
      array('Name' => 'URL', 'Title' => T('URL')),
    ));
    $Order = GetOrderTableHeader($TableColumns, 'date', 1);
    $Output .= '<table width="98%" class="BaseTable">'.
      $Order['Output'];

    $sql = 'SELECT *, `LogType`.`Color` AS `LogColor`, `LogType`.`Name` AS `LogName`, '.
      '(SELECT `User`.`Name` FROM `User` WHERE `User`.`ID` = `Log`.`User`) AS `UserName` FROM `Log` LEFT JOIN `LogType` ON `LogType`.`Id`=`Log`.`Type` '.$Where.$Order['SQL'].$PageList['SQLLimit'];
    $DbResult = $this->System->Database->query($sql);
    while ($Line = $DbResult->fetch_assoc())
    {
      if ($Line['Type'] == LOG_TYPE_ERROR) $Line['Text'] = htmlspecialchars($Line['Text']);
      $Line['Text'] = str_replace("\n", '<br/>', $Line['Text']);
      $Output .= '<tr><td>'.$Line['Date'].'</td>';
      if ($_SESSION['type'] == '') $Output .= '<td>'.T($Line['LogName']).'</td>';
      $Output .= '<td><span style="color: '.$Line['LogColor'].'">'.$Line['Text'].'</span></td>'.
      '<td><a href="'.$this->System->Link('/user/?user='.$Line['User']).'">'.$Line['UserName'].'</a></td>'.
      '<td>'.$Line['IP'].'</td>'.
      '<td>'.$Line['URL'].'</td></tr>';
    }
    $Output .= '</table>'.
      $PageList['Output'];
      if ($User->Licence(LICENCE_ADMIN))
      {
        $Output .= '<div>'.T('Remove').': <a href="'.$this->System->Link('/log/?a=delerrlog&amp;type='.LOG_TYPE_ERROR).'">'.T('Error logs').'</a> '.
          '<a href="'.$this->System->Link('/log/?a=delerrlog&amp;type='.LOG_TYPE_PAGE_NOT_FOUND).'">'.T('Missing').'</a></div>';
      }
    } else $Output .= ShowMessage(T('Access denied'), MESSAGE_CRITICAL);

    return $Output;
  }

  function DeleteErrorLog()
  {
    $User = ModuleUser::Cast($this->System->GetModule('User'))->User;
    if ($User->Licence(LICENCE_ADMIN) and
    (($_GET['type'] == LOG_TYPE_ERROR) or ($_GET['type'] == LOG_TYPE_PAGE_NOT_FOUND)))
    {
      $DbResult = $this->System->Database->select('LogType', '*', 'Id='.$_GET['type']);
      $LogType = $DbResult->fetch_assoc();
      $DbResult = $this->System->Database->query('SELECT COUNT(*) FROM `Log` WHERE `Type`='.$_GET['type']);
      $DbRow = $DbResult->fetch_row();
      $this->System->Database->query('DELETE FROM `Log` WHERE `Type`='.$_GET['type']);
      $this->System->ModuleManager->Modules['Log']->WriteLog('Vymazáno záznamů z '.$LogType['Description'].'.', LOG_TYPE_ADMINISTRATION);
      $Output = ShowMessage('Smazáno všech '.$DbRow[0].' záznamů z '.$LogType['Description'].'.');
      $Output .= $this->ShowList();
      return $Output;
    } else $Output = ShowMessage(T('Access denied'), MESSAGE_CRITICAL);
  }
}
