//
//  File:   hzDirectory.h
//
//  Legal Notice: This file is part of the HadronZoo C++ Class Library.
//
//  Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
//  The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
//  Software Foundation, either version 3 of the License, or any later version.
//
//  The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
//  A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
#ifndef hzDirectory_h
#define hzDirectory_h
//  System includes
#include <sys/stat.h>
//  Other HadronZoo includes
#include "hzChars.h"
#include "hzDate.h"
#include "hzChain.h"
#include "hzCodec.h"
#include "hzTmplArray.h"
#include "hzTmplList.h"
#include "hzTmplVect.h"
#include "hzTmplMapS.h"
#include "hzTmplMapM.h"
/*
**  Definitions
*/
#define ISDIR   S_ISDIR
typedef struct stat FSTAT ;
/*
**  Control flags for directories & files for a filesystem state compare regime
*/
//  Status flags
#define FSI_INERT   0x0000      //  File or dir exists in both current and previous snapshot and has not changed.
#define FSI_MODIFY  0x0001      //  File or dir exists in both current and previous snapshot but has changed.
#define FSI_CREATE  0x0002      //  File or dir exists only in the current snapshot and is thus new.
#define FSI_DELETE  0x0004      //  File or dir exists only in the previous snapshot and is thus deprecated.
class   hzDirent
{
    //  Category:   Filesystem
    //
    //  Directory entry. Either file or directory
    hzString    m_parent ;      //  The parent directory
    hzString    m_Name ;        //  This will be full path if this is a dir, only the name if a file
    uint64_t    m_Size ;        //  Size in bytes (assuming 64 bit OS)
    uint32_t    m_Ctime ;       //  Date & time when file created
    uint32_t    m_Mtime ;       //  Date & time of last modification
    uint32_t    m_Inode ;       //  Inode value
    uint32_t    m_Mode ;        //  UNIX Permissions
    uint16_t    m_Owner ;       //  User Id of owner (unused under Windows)
    uint16_t    m_Group ;       //  Group Id of owner (unused under Windows)
    uint16_t    m_Links ;       //  Number of hard links
    uint16_t    m_Status ;      //  Appliction assigned value (eg version)
public:
    hzDirent    (void)
    {
        m_Size = 0 ;
        m_Inode = m_Ctime = m_Mtime = m_Mode = 0 ;
        m_Owner = m_Group = m_Links = m_Status = 0 ;
    }
    ~hzDirent   (void)
    {
        //m_Kinder.Clear() ;
    }
    //  Set functions
    void    InitStat    (const hzString& pardir, const hzString& name, FSTAT& fs) ;
    void    InitNorm    (   const hzString& pardir,
                            const hzString& name,
                            uint64_t    size,
                            uint32_t    ino,
                            uint32_t    ctime,
                            uint32_t    mtime,
                            uint32_t    mode,
                            uint32_t    uid,
                            uint32_t    gid,
                            uint32_t    nlink) ;
    //  Set functions
    void    SetName     (const char* name)  { m_Name = name ; }
    void    SetName     (hzString& name)    { m_Name = name ; }
    void    SetCtime    (hzXDate& d)        { m_Ctime = d.AsEpoch() ; }
    void    SetMtime    (hzXDate& d)        { m_Mtime = d.AsEpoch() ; }
    void    SetCtime    (uint32_t ctime)    { m_Ctime = ctime ; }
    void    SetMtime    (uint32_t mtime)    { m_Mtime = mtime ; }
    void    SetSize     (uint32_t nSize)    { m_Size = nSize ; }
    //  Get functions
    const hzString  Path    (void) const ;
    const hzString  strName (void) const    { return m_Name ; }
    const char*     txtName (void) const    { return *m_Name ; }
    uint32_t        Ctime   (void) const    { return m_Ctime ; }
    uint32_t        Mtime   (void) const    { return m_Mtime ; }
    uint32_t        Inode   (void) const    { return m_Inode ; }
    uint32_t        Mode    (void) const    { return m_Mode ; }
    uint32_t        Size    (void) const    { return m_Size ; }
    uint16_t        Owner   (void) const    { return m_Owner ; }
    uint16_t        Group   (void) const    { return m_Group ; }
    uint16_t        Nlink   (void) const    { return m_Links ; }
    bool            IsDir   (void) const    { return ISDIR(m_Mode) ? true : false ; }
    //  Set status functions
    void    MkInert     (void)  { m_Status = 0 ; }
    void    MkModify    (void)  { m_Status = FSI_MODIFY ; }
    void    MkCreate    (void)  { m_Status = FSI_CREATE ; }
    void    MkDelete    (void)  { m_Status = FSI_DELETE ; }
    //  Get status functions
    bool    IsInert     (void)  { return m_Status ? false : true ; }
    bool    IsModify    (void)  { return m_Status & FSI_MODIFY ? true : false ; }
    bool    IsCreate    (void)  { return m_Status & FSI_CREATE ? true : false ; }
    bool    IsDelete    (void)  { return m_Status & FSI_DELETE ? true : false ; }
    bool    IsChanged   (void)  { return m_Status & (FSI_MODIFY | FSI_CREATE) ? true : false ; }
    //  Operators
    hzDirent&   operator=   (const hzDirent& op) ;
    bool    operator<   (const hzDirent& op) const ;
    bool    operator>   (const hzDirent& op) const ;
    bool    operator==  (const hzDirent& op) const ;
    //  Stream operators
    friend  std::istream&   operator>>  (std::istream& is, hzDirent& de) ;
    friend  std::ostream&   operator<<  (std::ostream& os, const hzDirent& de) ;
} ;
class   hzFileset
{
    //  Category:   Filesystem
    //
    //  The hzFileset (file set) class represents a snapshot of a file system subset. The directories and files in the subset can be for any purpose, e.g. webapp configs. hzFileset
    //  is implemented as a 1:1 map of pathnames to directories and a 1:many map of filenames to files. The directories and files are held as hzDirent instances.
    //
    //  hzFileset is populated by importing a directory/file list or by file system scan. The scan is driven by a set of one or more roots, each of which is a starting point for a
    //  hierarchical scan.
    hzChain     m_Error ;       //  Report errors during scan
    uint32_t    m_nBlocs ;      //  No of block devices
    uint32_t    m_nChars ;      //  No of char devices
    uint32_t    m_nLinks ;      //  No of links
    uint32_t    m_nSocks ;      //  No of open sockets
    uint64_t    m_nBytes ;      //  Total bytes in all files on all disks
    hzEcode _scan_r (hzDirent*, hzString& curdir) ;
    void    _clear  (void) ;
public:
    hzMapS<hzString,hzDirent*>  m_dirs ;    //  Index of directories by name
    hzMapM<hzString,hzDirent*>  m_file ;    //  Index of files by name
    hzList<hzString>    m_Roots ;           //  Root directories
    hzFileset   (void)
    {
        _clear() ;
    }
    ~hzFileset  (void)
    {
        _clear() ;
    }
    hzEcode AddRoot (hzString& pathname)
    {
        if (pathname)
            return m_Roots.Add(pathname) ;
        return E_ARGUMENT ;
    }
    hzEcode Scan    (void) ;
    hzEcode Import  (const char* cpFilename) ;
    hzEcode Export  (const char* cpFilename) ;
    hzChain&    Error   (void)  { return m_Error ; }
    uint32_t    TotalDirs   (void) const    { return m_dirs.Count() ; }
    uint32_t    TotalFiles  (void) const    { return m_file.Count() ; }
    uint64_t    TotalBytes  (void) const    { return m_nBytes ; }
} ;
/*
**  Non member prototypes
*/
hzEcode GetCurrDir      (hzString& Dir) ;
hzEcode GetAbsPath      (hzString& abs, const char* rel) ;
hzEcode ReadDir         (hzVect<hzDirent>& Dirs, hzVect<hzDirent>& Files, const char* cpPath = 0, const char* cpCriteria = 0) ;
hzEcode ReadDir         (hzVect<hzDirent>& entries, const char* cpPath = 0, const char* cpCriteria = 0) ;
hzEcode ListDir         (hzVect<hzString>& Dirs, hzVect<hzString>& Files, const char* cpPath = 0, const char* cpCriteria = 0) ;
hzEcode BlattDir        (const char* dirname) ;
hzEcode Filecopy        (const hzString& tgt, const hzString& src) ;
hzEcode Dircopy         (const hzString& tgt, const hzString& src, bool bRecurse) ;
hzEcode Filemove        (const hzString& tgt, const hzString& src) ;
//  FindfilesStd (find files strictly conforming to the supplied criteria)
hzEcode FindfilesStd    (hzArray<hzString>& files, const char* criteria) ;
//  FindfilesTar (find files according to the tar interpretation of the supplied criteria)
hzEcode FindfilesTar    (hzArray<hzString>& files, const char* criteria) ;
hzEcode AssertDir       (const char* cpDir, uint32_t nPerms) ;
hzEcode DirExists       (const char* dirname) ;
hzEcode TestFile        (const char* pathname) ;
hzEcode OpenInputStrm   (std::ifstream& is, const char* pathname) ;
#endif  //  hzDirectory_h