<?php

include_once(dirname(__FILE__).'/ModuleUser.php');
include_once(dirname(__FILE__).'/UserList.php');
include_once(dirname(__FILE__).'/Options.php');
include_once(dirname(__FILE__).'/Registration.php');
include_once(dirname(__FILE__).'/Profile.php');

class PageUserLogin extends Page
{
  function Show(): string
  {
    $Output = '<form action="'.$this->System->Link('/?action=login').'" method="post" class="Form">'.
      '<fieldset><legend>'.T('Login').'</legend>
      <table>
      <tr>
      <th class="Left">'.T('Name').':</th><td><input type="text" name="LoginUser" size="13" /></td>
      </tr>
      <tr>
      <th class="Left">'.T('Password').':</th><td><input type="password" name="LoginPass" size="13" /></td>
      </tr>
      <tr>
      <th class="Left">'.T('Stay logged').':</th><td><input type="checkbox" name="StayLogged" /></td>
      </tr>
      <tr>
      <th class="Center"colspan="2"><input type="submit" value="'.T('Do login').'" /></th>
      </tr>
      </table>
      </fieldset></form>';
      return $Output;
  }
}

// User licence levels
define('LICENCE_ANONYMOUS', -1);
define('LICENCE_USER', 0);
define('LICENCE_MODERATOR', 1);
define('LICENCE_ADMIN', 2);

class User
{
  var $Id;
  public string $Name;
  var $Team;
  var $Role;
  var $Redirecting;
  var $Language;
  var $System;
  var $Database;
  var $OnlineStateTimeout;
  var $PreferredVersion = 0;
  public string $PreferredVersionGame;
  public string $Email;
  public string $Info;

  function __construct(System $System)
  {
    $this->System = &$System;
    $this->Database = &$System->Database;
    $this->OnlineStateTimeout = 600; // in seconds
    if (isset($_SESSION)) $this->Check();
  }

  function __destroy()
  {
  }

  function Login($Name, $Password, $StayLogged = false)
  {
    $SID = session_id();
    $DbResult = $this->Database->query('SELECT `ID` FROM `User` WHERE '.
      'LOWER(`Name`) = LOWER("'.$Name.'") AND `Pass` = '.$this->CryptPasswordSQL('"'.$Password.'"', '`Salt`'));
    if ($DbResult->num_rows > 0)
    {
      $User = $DbResult->fetch_assoc();
      $this->Id = $User['ID'];

      // Prepare cookies for permanent login
      $StayLoggedSalt = $this->GetPasswordSalt();
      if ($StayLogged == true) $StayLoggedValue = 1; else $StayLoggedValue = 0;
      $this->Database->update('UserOnline', '`SessionId`="'.$SID.'"', array(
        'User' => $User['ID'], 'StayLogged' => $StayLoggedValue, 'StayLoggedHash' => $StayLoggedSalt));
      if ($StayLogged)
      {
        setcookie('LoginUserId', $User['ID'], time() + 365 * 24 * 60 * 60);
        setcookie('LoginHash', sha1($User['ID'].$StayLoggedSalt), time() + 365 * 24 * 60 * 60);
      } else {
        setcookie('LoginUserId', '', time() - 3600);
        setcookie('LoginHash', '', time() - 3600);
      }

      $this->Database->query('UPDATE `UserTrace` SET '.
        '`LastLogin` = NOW(), '.
        '`LastIP` = "'.GetRemoteAddress().'", '.
        '`UserAgent` = "'.$this->System->Database->real_escape_string($_SERVER['HTTP_USER_AGENT']).'" '.
        ' WHERE `User` = '.$this->Id);
      $this->System->ModuleManager->Modules['Log']->WriteLog('Login', LOG_TYPE_USER);
      $this->Check();
    };
  }

  function Logout()
  {
    $SID = session_id();
    if ($this->Role != LICENCE_ANONYMOUS)
    {
      $this->Database->update('UserOnline', '`SessionId`="'.$SID.'"', array('User' => null));
      $this->Database->query('UPDATE `UserTrace` SET '.
        '`LastLogout` = NOW() WHERE `User` = '.$this->Id);
      $this->System->ModuleManager->Modules['Log']->WriteLog('Logout: '.$this->Name, LOG_TYPE_USER);
      $this->Check();
    }
  }

  function Load()
  {
    $DbResult = $this->Database->query('SELECT `User`.`PreferredVersion`,`User`.`ID`,`User`.`Team`,`User`.`Redirecting`,`User`.`Email`,`User`.`Info`,'.
    '`User`.`Language`,`User`.`Name`,`User`.`GM`,`ClientVersion`.`Version` AS `PreferredVersionGame` FROM `User` '.
    'LEFT JOIN `ClientVersion` ON `ClientVersion`.`Id` = `User`.`PreferredVersion` '.
    'WHERE `User`.`ID` = '.$this->Id);
    if ($DbResult->num_rows > 0)
    {
      $User = $DbResult->fetch_assoc();
      // Security: Password and Salt hash should not be loaded to variables
      $this->Id = $User['ID'];
      $this->Team = $User['Team'];
      $this->Redirecting = $User['Redirecting'];
      $this->Language = $User['Language'];
      $this->Name = $User['Name'];
      $this->Role = $User['GM'];
      $this->Email = $User['Email'];      
      if ($User['Info'] != null) $this->Info = $User['Info'];
        else $this->Info = '';
      if ($User['PreferredVersionGame'] != null) $this->PreferredVersionGame = $User['PreferredVersionGame'];
        else $this->PreferredVersionGame = '';
    } else $this->SetAnonymous();
  }

  function SetAnonymous()
  {
    $this->Id = NULL;
    $this->Name = 'anonymous';
    $this->Role = LICENCE_ANONYMOUS;
    $this->Language = NULL;
    $this->Redirecting = 1;
    $this->Team = '';
    $this->Email = '';
  }

  function Licence($Licence)
  {
    if (GetRemoteAddress() == '') return true; // Execution from command line
      else return $this->Role >= $Licence;
  }

  function CheckToken($Licence, $Token)
  {
    $DbResult = $this->Database->select('APIToken', 'User', '`Token`="'.$Token.'"');
    if ($DbResult->num_rows > 0)
    {
      $DbRow = $DbResult->fetch_assoc();
      $DbResult2 = $this->Database->select('User', 'GM', '`ID`="'.$DbRow['User'].'"');
      $DbRow2 = $DbResult2->fetch_assoc();
      return $DbRow2['GM'] >= $Licence;
    } else return false;
  }

  function GetPasswordSalt()
  {
    return substr(sha1(mt_rand()), 0, 8);
  }

  function CryptPasswordSQL($Password, $Salt)
  {
    return 'SHA1(CONCAT(SHA1('.$Password.'), '.$Salt.'))';
  }

  function Check()
  {
    $SID = session_id();
    // Lookup user record
    $Query = $this->Database->select('UserOnline', '*', 'SessionId="'.$SID.'"');
    if ($Query->num_rows > 0)
    {
      // Refresh time of last access
      $this->Database->update('UserOnline', 'SessionId="'.$SID.'"', array('ActivityTime' => 'NOW()'));
    } else
    {
      if (GetRemoteAddress() != '') $HostName = gethostbyaddr(GetRemoteAddress());
        else $HostName = '';
      $this->Database->insert('UserOnline', array('SessionId' => $SID,
      'User' => null, 'LoginTime' => 'NOW()', 'ActivityTime' => 'NOW()',
      'IpAddress' => GetRemoteAddress(), 'HostName' => $HostName,
      'ScriptName' => GetRequestURI(), 'StayLogged' => 0, 'StayLoggedHash' => ''));
    }

    // Logged permanently?
    if (array_key_exists('LoginHash', $_COOKIE))
    {
      $DbResult = $this->Database->query('SELECT * FROM `UserOnline` WHERE `User`='.$_COOKIE['LoginUserId'].
        ' AND `StayLogged`=1 AND SessionId!="'.$SID.'"');
      if ($DbResult->num_rows > 0)
      {
        $DbRow = $DbResult->fetch_assoc();
        if (sha1($_COOKIE['LoginUserId'].$DbRow['StayLoggedHash']) == $_COOKIE['LoginHash'])
        {
          $this->Database->query('DELETE FROM `UserOnline` WHERE `SessionId`="'.$SID.'"');
          $this->Database->query('UPDATE `UserOnline` SET `SessionId`="'.$SID.'" WHERE `Id`='.$DbRow['Id']);
        }
      }
    }

    // Check login
    $Query = $this->Database->select('UserOnline', '*', '`SessionId`="'.$SID.'"');
    $Row = $Query->fetch_assoc();
    if ($Row['User'] != '')
    {
      $this->Id = $Row['User'];
      $this->Load();
    } else
    {
      $this->SetAnonymous();
    }

    // Remove nonactive users
    $DbResult = $this->Database->select('UserOnline', '`Id`, `User`', '(`ActivityTime` < DATE_SUB(NOW(), INTERVAL '.$this->OnlineStateTimeout.' SECOND)) AND (`StayLogged` = 0)');
    while ($DbRow = $DbResult->fetch_array())
    {
      $this->Database->delete('UserOnline', 'Id='.$DbRow['Id']);
    }
  }

  function Register($UserName, $Password, $Email, $Language, $Team, $PreferredVersion)
  {
    $Salt = $this->GetPasswordSalt();
    if ($Team == null) $Team = 'NULL';
    if ($PreferredVersion == null) $PreferredVersion = 'NULL';
    $this->Database->query('INSERT INTO `User` '.
      '(`Name` , `Pass` , `Salt`, `Email` , `Language` , `Team` , `NeedUpdate`, `RegistrationTime`, `PreferredVersion` ) '.
      'VALUES ("'.$UserName.'", '.$this->CryptPasswordSQL('"'.$Password.'"', '"'.$Salt.'"').
      ', "'.$Salt.'", "'.$Email.'", '.$Language.', '.$Team.', 1, NOW(), '.$PreferredVersion.')');
    $UserId = $this->Database->insert_id;
    $this->Database->query('INSERT INTO `UserTrace` (`User`, `LastIP`, `UserAgent`) '.
      'VALUES ('.$UserId.', "'.GetRemoteAddress().'", '.
      '"'.$this->Database->real_escape_string($_SERVER['HTTP_USER_AGENT']).'")');
  }
}
