//********************************************************************************
//* File       : AcEditFile.hpp                                                  *
//* Author     : Mahlon R. Smith                                                 *
//*              Copyright (c) 2022-2026 Mahlon R. Smith, The Software Samurai   *
//*                 GNU GPL copyright notice in AcEdit.cpp.                      *
//* Date       : 17-Oct-2025                                                     *
//* Version    : (see AppVersion string)                                         *
//*                                                                              *
//* Description: Definitions for file management.                                *
//********************************************************************************

#include <iostream>
#include <filesystem>            // filesystem (C++17)
#include <dirent.h>              // manage directory entries
#include <grp.h>                 // user information
#include <pwd.h>                 // user information

//* Convert the C-style structure syntax to C++ format.  *
//* Used for smooth structure management.                *
typedef struct statx  FileStats ;
typedef struct dirent64 deStats ;
typedef struct tm Tm ;
typedef struct passwd PwdInfo ;
typedef struct group GrpInfo ;
typedef struct utimbuf uTime ;

//* Maximum bytes to hold GNU/Linux path and filename strings *
//* Note that these values correspond to the PATH_MAX and     *
//* NAME_MAX definitions in <linux/limits.h>.                 *
const int32_t MAX_PATH = 4096 ;     //* Size of buffer to hold a filespec
const int32_t MAX_FNAME = 256 ;     //* Size of buffer to hold a filename

//* Local definitions for file type encoded in the *
//* "st_mode" element of the stat{} structure.     *
enum fmFType : short { fmDIR_TYPE,   fmREG_TYPE,  fmLINK_TYPE, fmCHDEV_TYPE, 
                       fmBKDEV_TYPE, fmFIFO_TYPE, fmSOCK_TYPE, fmUNKNOWN_TYPE, fmTYPES } ;

//* Specifies the character or group of characters to be "escaped" *
//* by a call to the EscapeSpecialChars() method.                  *
enum escGroup : short
{
   escDQ,      // escape only double-quote character ( " )
   escMIN,     // escape the four most critical characters: ( $ \ ` " )
   escLINUX,   // escMIN plus the Linux shell special characters ( \ ' " ? : ; & > < | * )
   escMAX,     // escLINUX plus all remaining special characters
               // # + = % ! ~ { } @ ( ) [ ] and space(' ' 20h)
   escWCHAR    // escape only the specified character
} ;

//* When displaying names of files on disc, visual indicators for filetype.*
const wchar_t PCHAR = DOT ;               // parent directory designator
const wchar_t DCHAR = L'>' ;              // subdirectory designator
const wchar_t FCHAR = wcsBULLET ;         // filename designator
//enum PrefixChar : wchar_t THIS WON'T WORK BECAUSE "lvalue" needed.
//{
//   PCHAR = DOT,
//   DCHAR = L'>',
//   FCHAR = wcsBULLET
//} ;

//* Super-user (root) user ID *
const uid_t superUID  = (0x0000) ;

//* Class for reporting the system local date/time.                            *
//* ---------------------------------------------------------------------------*
#define DECODE_TZ (1)   // if non-zero, decode time-zone fields of localTime
const int64_t maxETIME32 = 0x07FFFFFFF,      // largest 32-bit time_t
              minETIME32 = -maxETIME32 - 1 ; // smallest 32-bit time_t
const short ltFMT_LEN = 16 ;                 // length of time string buffers
//* Important note about the year 2038 bug:                                    *
//* Because 'time_t' is defined as a signed, 32-bit value on 32-bit systems,   *
//* time reporting will break down for date/time values                        *
//*                     >= 19 Jan 2038 at 11:14:08                             *
//* For this reason and for others, we have defined our own local-time class.  *
//* This class uses a signed, 64-bit value for storing the epoch time.         *
//* It is hoped that all Linux systems will have been updated long before this *
//* becomes an issue; however, even now (2013), some applications are using    *
//* date/time manipulations that exceed the 32-bit limit. BEWARE!!             *
//* NOTE: time arithmetic should always be performed on signed 64-bit values.  *
//* NOTE: 'struct tm' uses int or long int for all integer values.             *
class localTime
{
   public:
   localTime ( void ) { this->reset() ; }
   void reset ( void )
   {  //* Set to epoch date: Thursday, 01 Jan. 1970 @ 08:00:00
      this->sysepoch = ZERO ;
      this->epoch = ZERO ;
      this->day = 4 ;
      this->year = 1970 ;
      this->month = this->date = 1 ;
      this->hours = 8 ;
      this->minutes = this->seconds = ZERO ;
      this->julian = ZERO ;
      #if DECODE_TZ != 0   // time-zone data
      *this->timezone = NULLCHAR ;
      *this->utc_zone  = NULLCHAR ;
      this->gmtoffset = ZERO ;
      this->dst       = false ;
      #endif   // DECODE_TZ
   }
   int64_t  epoch ;        //* Seconds since the epoch (01-Jan-1970)
   time_t   sysepoch ;     //* system epoch time (see note)
   // Note that the struct tm equivalents are SIGNED int values.
   uint16_t day ;          //* Day of the week (0 == Sun, ..., 6 == Sat)
   uint16_t date ;         //* Day of the month (1-[28|29|30|31])
   uint16_t month ;        //* Month of the year (1 == Jan, ... 12 == Dec)
   uint16_t year ;         //* Year (four digit year)
   uint16_t hours ;        //* Time of day, hour (0-23)
   uint16_t minutes ;      //* Time of day, minutes (0-59)
   uint16_t seconds ;      //* Time of day, seconds (0-59)
   uint16_t julian ;       //* Completed days since beginning of year

   #if DECODE_TZ != 0   // time-zone data
   // See DecodeEpochTime method for more information.
   char     timezone[ltFMT_LEN] ; //* string representing the local time zone (useless)
   char     utc_zone[ltFMT_LEN] ; //* string representing the UTC offset for local time zone
   int32_t  gmtoffset ;    //* Expressed as (signed) number of seconds offset from UTC+0:00
                           //* Range: -43200 dec.(0xFFFF5740) to 43200 dec.(0x0000ABC0)
   bool     dst ;          //* 'true' if daylight savings time in effect,
                           //* 'false if not DST or info not available
   #endif   // DECODE_TZ
} ;

//* Class definition for target file stats.                      *
//* (adapted from TreeNode structure in FileMangler application) *
class tnFName
{
   public:
   ~tnFName ( void )          //* Destructor
   { /* nothing to do */ }
   tnFName ( void )           //* Constructor
   { this->reset () ; }

   void reset(void)           //* Set all members to default values
   {
      this->fSpec[0] = NULLCHAR ;
      this->fName[0] = NULLCHAR ;
      this->fType    = fmTYPES ;
      this->fBytes   = ZERO ;
      this->modTime.day  = this->modTime.date  = this->modTime.month = 
      this->modTime.year = this->modTime.hours = this->modTime.minutes = 
      this->modTime.seconds = ZERO ;
      this->readAcc  = false ;
      this->writeAcc = false ;
      // NOTE: data member, rawStats is left unitialized
   }

   //* Data Members *
   char        fSpec[MAX_PATH] ;  //* Filespec (path) string
   char        fName[MAX_FNAME] ; //* Filename string
   fmFType     fType ;     //* File type (enum fmFType)
   uint64_t    fBytes ;    //* File size (in bytes)
   localTime   modTime ;   //* Date/Time file last modified (human readable)
   FileStats   rawStats ;  //* Copy of system's "stat" structure (all file info)
   bool        readAcc ;   //* 'true' if user has read access to file
   bool        writeAcc ;  //* 'true' if user has write access to file
} ;

//* Information on the user account under which the application is running. *
const short uiMAX_sGID = 32 ;
const short uiMAX_STRING = MAX_PATH ;
class UserInfo
{
   public:
   UserInfo ()
   {
      *stringAlloc = NULLCHAR ;
      userName = realName = shellProg = homeDir = 
      passWord = grpName = grpPWord = stringAlloc ;
      userID = grpID = ggrpID = (-1) ;
      suppGroups = ZERO ;
      goodData = false ;
   }
   char*   userName ;         //* User name
   char*   realName ;         //* User's real name
   char*   grpName ;          //* Group name
   char*   shellProg ;        //* User's shell program
   char*   homeDir ;          //* Path to user's home directory
   char*   passWord ;         //* User's password (encrypted)
   char*   grpPWord ;         //* Group password (encrypted)
   gid_t   suppGID[uiMAX_sGID];//* List of supplimentary groups belonged to 
                              //* (first uiMAX_sGID only, probably far more)
                              //* than enough except for 'root' user       )
   uid_t    userID ;          //* User ID
   gid_t    grpID ;           //* User's group ID
   gid_t    ggrpID ;          //* Group ID from Group file
   short    suppGroups ;      //* Number of supplimentary groups that user belongs to
   bool     goodData ;        //* true if data are valid, else false

   private:
   char  stringAlloc[uiMAX_STRING];//* Memory for storing string data
friend class AcEdit ;   // AcEdit class has full access to class members
} ;   // UserInfo
