/*==================================================================================================
  
Copyright (c) 2013 Siemens PLM
Unpublished - All rights reserved

 ====================================================================================================*/
/**
    @file

    Contains the definition of the file class.
    This class is useful to complete all sort of operation on OS-related files.
    Files are only a specialization of directories
*/

/**  */

#ifndef FCLASSES_OSFILE_INCLUDE_HXX
#define FCLASSES_OSFILE_INCLUDE_HXX

/**
   @file

   Provides various methods to manipulate files.
*/

#include <ss/ss_const.h>
#include <ss/ss_types.h>

#include <fclasses/libfclasses_exports.h>
namespace Teamcenter
{
    /**
       @brief Manipulates a file.

       It provides a wide range of methods to create, delete, rename, parse, etc. a file.
    */
    class FCLASSES_API OSFile
    {
    public:
        /**
           Constructs the object based on the provided file path and type.
           @param[in] iFilePath Path to the file
           @param[in] iFileType Type of file. Valid values are SS_TEXT or SS_BINARY
        */
        OSFile(const char *iFilePath, int iFileType = SS_TEXT);

        /**
           Constructs the object based solely on the provided type.
           @param[in] iFileType Type of file. Valid values are SS_TEXT or SS_BINARY
        */
        OSFile(int iFileType = SS_TEXT);

        /**
           Copy constructor.
           @note The original file ought to be closed prior to calling the copy constructor.
        */
        OSFile(const OSFile& iOSFile);

        /** 
            Operator equal
        */
        OSFile& operator = (const OSFile&);

        /**
           Destructor
        */
        virtual ~OSFile();


        /**
           Generates a suitable file name from an input string, by replacing all single-byte non alphanumeric characters with the '_' character.
           <br/>The file extension is also considered in the validation. Only the last '.' character will not be replaced, because it is considered as the extension marker.
         
           @param[in] iFileNameToValidate The file name to validate
           @param[in] iKeepCase Flag to indicate if the case of the file name shall not be altered (true) or set to lower case (false).
          
           @returns A validated file name (extension included).
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        static char *getValidatedFileName(const char *iFileNameToValidate, bool iKeepCase); 

        /**
           Generates a suitable file name from an input string, by replacing all single-byte non alphanumeric characters
           (excluding the '+', '-' and '|' characters) with the '_' character.
           <br/>The file extension is also considered in the validation. Only the last '.' character will not be replaced, because it is considered as the extension marker.
           <br/>The output file name will be in lower case.
         
           @param[in] iFileNameToClean The file name to clean
         
           @returns A validated file name (extension included).
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        static char *getCleanedName(const char *iFileNameToClean);
          

        /**
           Retrieves the full path as it was passed in the constructor.
         
           @returns The full path name.
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        char* getFilePath() const;

        /**
           Returns the name of the file (with its potential extension).
          
           @returns The file name.
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        char* getFileName() const;
       
        /**
           Retrieves the file extension.
         
           @returns The file extension.
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        char *getFileExtension() const;

        /**
           Returns the directory part of the path name
           <br/>The name will contain either the / or the \ folder separator, depending on the Operating System.
          
           @returns The directory path name.
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        char* getDirectoryPath() const;

        /**
           Changes the file name of the OSFile instance.
           <br/>The file needs to:
           <ul>
           <li>to exist on disk prior to changing its name.
           <li>to be closed prior to the call.
           </ul>
         
           @param[in] iFileName The new file name. 
         
           @returns
           <ul>
           <li>ITK_ok if the name has correctly been changed, and the new file created.
           <li>SS_FILEBUSY if the file is not closed prior to the call.
           <li>SS_NOSUCHFILE if the original file does not exist on the disk.
           <li>Possibly other errors.
           </ul>
        */
        int rename( const char* iFileName );
    
        /**
           Changes the full path to the OSFile instance.
           <br/>The file needs to:
           <ul>
           <li>to exist on disk prior to changing the path.
           <li>to be closed prior to the call.
           </ul>
         
           @param[in] iFilePath The new file path. 
         
           @returns
           <ul>
           <li>ITK_ok if the name has correctly been changed, and the new file created.
           <li>SS_FILEBUSY if the file is not closed prior to the call.
           <li>SS_NOSUCHFILE if the original file does not exist on the disk.
           <li>Possibly other errors.
           </ul>
        */
        int changeFilePath( const char* iFilePath );

        /**
           Checks the existence of a file.
         
           @param[in,out] oFileExists Flag determining if the file exists
         
           @returns
           <ul>
           <li>ITK_ok on success
           <li>SS_NOSUCHFILE if the file existence cannot be verified
           <li>Possibly other errors
           </ul>
        */
        int exists (bool& oFileExists) const;
    
        /** 
            Creates the file with the permission as specified in the @p iMode arguments
            <br/><br/>The value for the mode is a numeric mode is from one to four octal
            digits (0-7), derived by adding up the bits with values 4, 2 and  1.
            Any  omitted digits are assumed to be leading zeros:
            <ul>
            <li>The first digit selects the set user ID (4) and set group ID (2) and sticky (1) attributes. Leave it as 0 if unsure.
            <li>The second digit selects permissions for the user who owns  the  file:  read(4),  write(2) and execute (1).
            <li>The third selects permissions for other users in the file's group, with the same values.
            <li>The fourth for other users not in the file's group, with the same values.
            </ul>
            The following modes can be used as defined in the ITK documentation group SS_CONST: SS_ALL_PERMISSIONS_DMODE, SS_DEF_FMODE, SS_DEF_DMODE, 
            SS_NO_WORLD_ACCESS_FMODE, SS_NO_WORLD_ACCESS_DMODE
         
            @note Once created, the file is considered to be opened.
         
            @param[in] iMode The needed mode as explained above. By default, the files are created 
            with the mode SS_DEF_DMODE (user can read/write, all others can only read).
         
            @returns
            <ul>
            <li>ITK_ok if the file is created with the specified permission.
            <li>SS_ALREADYOPEN if the file is opened (and therefore exists).
            <li>SS_FILEEXISTS if the file already exists
            <li>Possibly other errors.
            </ul>
        */
        int create (int iMode = SS_DEF_FMODE);

        /** 
            Opens the file with the requested permission.
            <br/><br/>If the file does not exist and the mode is not read-only, then the file will be created.
         
            @param[in] iRWMode The needed mode to open the file. The default mode is read only.
            <br/>Valid values are SS_RDONLY (read only), SS_WRONLY (write only), SS_RDWRITE (read/write), SS_APPEND (appending)
         
            @returns
            <ul>
            <li>ITK_ok if the file is opened with the specified permission.
            <li>SS_ALREADYOPEN if the file is already opened (it could have been opened with a different mode though).
            <li>SS_NOOPEN if the file could not be opened.
            <li>SS_INVMODE if the mode is invalid.
            <li>Possibly other errors.
            </ul>
        */
        int open( int iRWMode = SS_RDONLY );

        /** 
            Closes the file.
            <br/><br/>If the file does not exist and the mode is not read-only, then the file will be created.
         
            @returns
            <ul>
            <li>ITK_ok on success.
            <li>SS_FILENOTOPEN if the file is not opened.
            <li>SS_NOCLOSE if the file could not be closed.
            <li>Possibly other errors.
            </ul>
        */
        int close();

        /**
           Changes the access permission of a file.
           <br/><br/>Refer to the create() method for explanation on the values for the @p iMode parameter.
         
           @param[in] iMode The requested mode as explained in the create() method. 
         
           @returns
           <ul>
           <li>ITK_ok if the permission has correctly been modified.
           <li>Possibly other errors.
           </ul>
        */
        int chmod  (int iMode);

        /**
           Retrieves the file status, as captured in the structure SS_file_status.
         
           @param[out] oFileStatus The file status.
         
           @returns
           <ul>
           <li>ITK_ok on success.
           <li>SS_NOSTAT if the file status cannot be retrieved.
           <li>Possibly other errors.
           </ul>
        */
        int getFileStatus( SS_file_status *oFileStatus );

        /**
           Retrieves the file type.
         
           @param[out] oFileType The file type. Values are SS_TEXT (text file) and SS_BINARY (binary file). 
         
           @returns
           <ul>
           <li>ITK_ok on success.
           <li>SS_NOREAD if the file type cannot be retrieved.
           </ul>
        */
        int getFileType(int *oFileType);

        /**
           Returns the size of the file in bytes.
        */
        int getFileSize();

        /**
           Copies the content of the OSFile instance to another file.
           <br/>The file must be closed.
         
           @param[in] iCopyPath Path to the location where the file will be copied. 
         
           @returns
           <ul>
           <li>ITK_ok if the file has been copied correctly.
           <li>SS_FILEBUSY if the file is not closed.
           <li>SS_NOCOPY if the file has not been copied.
           <li>Possibly other errors.
           </ul>
        */
        int copy( const char *iCopyPath );
            
        /**
           Deletes the file.
           <br/>The file must be closed.
         
           @returns
           <ul>
           <li>ITK_ok if the file has been deleted correctly.
           <li>SS_FILEBUSY if the file is not closed.
           <li>SS_NODELETE if the file could not be deleted.
           <li>Possibly other errors.
           </ul>
        */
        int deleteFile ();

        /**
           Prints the file content to the specified printer.
         
           @param[in] iPrinter The printer to use for the job. 
           <br/>If a 0 pointer is specified, the printer stored 
           in the preference "TC_PRINTER" will be used.
         
           @returns
           <ul>
           <li>ITK_ok on success.
           <li>SS_NOPRINT if the file could not be printed.
           <li>Possibly other errors.
           </ul>
        */
        int print  (const char *iPrinter = 0) const;

        /**
           Reads a line from the file, and stores the output in already-allocated memory.
           <br/>The file needs to be opened.
         
           @param[out] oReadLine The line being read. The pointer will need to be allocated 
           prior to calling this method. It should be dimensioned to SS_MAXLLEN.
         
           @returns
           <ul>
           <li>ITK_ok on success
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_NOREAD if the file cannot be read.
           <li>Possibly other errors.
           </ul>
        */
        int readLine( char* oReadLine );

        /**
           Reads a line from the file, and allocates the memory in the returned pointer.
           <br/>The file needs to be opened.
         
           @param[out] oReadLine The line being read. The pointer will need to be freed 
           through a call to MEM_free or Teamcenter::scoped_smptr.
         
           @returns
           <ul>
           <li>ITK_ok on success
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_NOREAD if the file cannot be read.
           <li>Possibly other errors.
           </ul>
         
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */        
        int readLineWithAllocation (char** oReadLine);

        /**
           Reads a line from the file, and stores the output in the @p oFormattedLine parameter.
           <br/>The file needs to be opened.
           <br/>The method detects the presence of up to 10 arguments in the formatted line. 
           Arguments are signalled by the '%' character, which can also be escaped ("\%").
         
           @param[out] oFormattedLine The line being read. 
           @param[out] ...            The variable argument list. Each non-zero pointer corresponds 
           to an existing parameter in the formatted line.
         
           @returns
           <ul>
           <li>ITK_ok on success
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_NOREAD if the file cannot be read.
           <li>SS_TOOMANYARGS if too many parameters are found with the provided format.
           <li>Possibly other errors.
           </ul>
        */
        int fscanf  (const char * oFormattedLine, ...);

        /**
           Writes a line to the file.
           <br/>The file needs to be opened.
         
           @param[in] iLine  The line to be written.
         
           @returns
           <ul>
           <li>ITK_ok on success
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_NOWRITE if the file cannot be written.
           <li>Possibly other errors.
           </ul>
         
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        int writeLine( const char* iLine );

        /**
           Writes a formatted line to the file.
           <br/>The file needs to be opened.
         
           @param[in] iFormattedLine The formatted line to print to the file.
           @param[in] ...            The formatted arguments to be fed into the formatted line.
         
           @returns
           <ul>
           <li>ITK_ok on success
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_NOWRITE if the file cannot be written.
           <li>Possibly other errors.
           </ul>
         
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        int fprintf (const char *iFormattedLine, ...);

        /** 
            Initializes the instance prior to parsing (through getToken()).
            <br/>The file needs to be closed prior to the call. The method will open the file.
            <br/>Each time parsing from the beginning is needed, the method needs to be called.
            <br/>Once parsing is done, remember to close the file.
         
            @returns
            <ul>
            <li>ITK_ok on success.
            <li>SS_ALREADYOPEN if the file is already opened.
            <li>SS_NOOPEN if the file could not be opened.
            <li>Possibly other errors.
            </ul>
        */
        int initializeParsing();

        
        /** 
            Parses the file content and returns the string found between the current cursor position 
            and the next separator (any of the characters in the parameter @p iSeparators).
            <br/>The method initializeParsing() must have been called at least once. 
            <br/>Each time parsing from the beginning is needed, the method initializeParsing() 
            needs to be called.
            <br/>Once parsing is done, remember to close the file.
          
            <br/>Note the following behavior:
            <ul>
            <li>When the file has been fully parsed, the parameter @p oFoundSeparator will contain the character '\0'.
            <li>If the file contains no characters between 2 separators, the method will move to the next section.
            <li>If the token string starts with '"', any separator character before the closing '"' will not be considered as a separator.
            </ul>
          
            Here is an example of output with successive calls, using ";\n" as separators
            <table>
            <tr><th>String</th>
            <th>Result call#1</th>
            <th>Result call#2</th>
            <th>Result call#3</th>
            <th>Result call#4</th></tr>
            <tr><td>token1;\n"token;2"\n;token3</td>
            <td>oFoundSeparator=';'<br/>return=token1</td>
            <td>oFoundSeparator='\n'<br/>return="token;2"</td>
            <td>oFoundSeparator=''<br/>return=token3</td>
            <td>oFoundSeparator=''<br/>return=</td></tr>
            </table>
         
            @param[out] oFoundSeparator The separator found for the returned token
            @param[in]  iSeparators String containing separators (one per character) to be considered
            for parsing.
         
            @returns
            <ul>
            <li>ITK_ok on success.
            <li>SS_ALREADYOPEN if the file is already opened.
            <li>SS_NOOPEN if the file could not be opened.
            <li>Possibly other errors.
            </ul>
        */
        char* getToken(char *oFoundSeparator, const char* iSeparators=" \n\t\r\f");

    
        /**
           Retrieves or sets the cursor position in the file. 
           <br/>The file needs to be opened prior to this call. 
         
           <br/>If the parameter value is -1, the method will retrieve the current cursor position.
           Otherwise, the method will set the cursor position to the desired location.
         
           @param[in,out] iOffset Either the position to retrieve or the position to set
         
           @returns
           <ul>
           <li>ITK_ok on success.
           <li>SS_FILENOTOPEN if the file is not opened. In this case, the value of @p iOffset will be set to -1.
           <li>SS_NOSEEK if the position either cannot be retrieved or cannot be set.
           <li>Possibly other errors.
           </ul>
        */
        int seek( int* iOffset);
    
        /**
           Read @p iNumberOfBytes bytes from the file and puts it in the @p ioBuffer pointer.
          
           @param[in,out] ioBuffer        The pointer containing the output. The memory needs to be allocated prior to the call.
           @param[in]     iNumberOfBytes  The number of bytes to read
           @param[in]     iType           The type of the data. 
           <br/>Valid values are SS_VOID, SS_CHAR, SS_WCHAR, SS_BYTE, SS_SHORT, SS_LONG, SS_FLOAT, SS_DOUBLE.
          
           @returns
           <ul>
           <li>ITK_ok on success.
           <li>SS_EOF if the end of the file is reached.
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_INV_DTYPE if the provided type is invalid.
           <li>SS_NOREAD if the file cannot be read.
           </ul>
        */
        int read (void *ioBuffer, int iNumberOfBytes, int iType = SS_VOID);
    
        /**
           @defgroup OSFILE_READ_WRAPPERS Wrapper to read() method for the specified pointer type.
          
           @param[in,out] ioBuffer        The pointer containing the output. The memory needs to be allocated prior to the call.
           @param[in]     iNumberOfBytes  The number of bytes to read
          
           @{
        */
        int readVoid  (void           *ioBuffer, int iNumberOfBytes);
        int readChar  (unsigned char  *ioBuffer, int iNumberOfBytes);
        int readByte  (unsigned char  *ioBuffer, int iNumberOfBytes);
        int readShort (unsigned short *ioBuffer, int iNumberOfBytes);
        int readShort (short          *ioBuffer, int iNumberOfBytes);
        int readInt   (unsigned int   *ioBuffer, int iNumberOfBytes);
        int readInt   (int            *ioBuffer, int iNumberOfBytes);
        int readLong  (unsigned long  *ioBuffer, int iNumberOfBytes);
        int readLong  (long           *ioBuffer, int iNumberOfBytes);
        int readFloat (float          *ioBuffer, int iNumberOfBytes);
        int readDouble(double         *ioBuffer, int iNumberOfBytes);
        /**
           @}
        */

        /**
           Writes @p iNumberOfBytes bytes from the @p ioBuffer pointer into the file.
          
           @param[in] ioBuffer        The pointer containing the information to print to the file.
           @param[in] iNumberOfBytes  The number of bytes to write.
           @param[in] iType           The type of the data. 
           <br/>Valid values are SS_VOID, SS_CHAR, SS_WCHAR, SS_BYTE, SS_SHORT, SS_LONG, SS_FLOAT, SS_DOUBLE.
          
           @returns
           <ul>
           <li>ITK_ok on success.
           <li>SS_FILENOTOPEN if the file is not opened.
           <li>SS_INV_DTYPE if the provided type is invalid.
           <li>SS_NOWRITE if the data cannot be written to the file.
           <li>Possibly other errors
           </ul>
        */
        int write      (const void    *ioBuffer, int iNumberOfBytes, int iType = SS_VOID);
    
        /**
           @defgroup OSFILE_READ_WRAPPERS Wrapper to read() method for the specified pointer type.
          
           @param[in,out] ioBuffer        The pointer containing the output. The memory needs to be allocated prior to the call.
           @param[in]     iNumberOfBytes  The number of bytes to read
          
           @{
        */
        int writeVoid   (const void           *ioBuffer, int iNumberOfBytes);
        int writeChar   (const unsigned char  *ioBuffer, int iNumberOfBytes);
        int writeByte   (const unsigned char  *ioBuffer, int iNumberOfBytes);
        int writeShort  (const unsigned short *ioBuffer, int iNumberOfBytes);
        int writeShort  (const short          *ioBuffer, int iNumberOfBytes);
        int writeInt    (const unsigned int   *ioBuffer, int iNumberOfBytes);
        int writeInt    (const int            *ioBuffer, int iNumberOfBytes);
        int writeLong   (const unsigned long  *ioBuffer, int iNumberOfBytes);
        int writeLong   (const long           *ioBuffer, int iNumberOfBytes);
        int writeFloat  (const float          *ioBuffer, int iNumberOfBytes);
        int writeDouble (const double         *ioBuffer, int iNumberOfBytes);
        /**
           @}
        */

        /**
           @defgroup OSFILE_READ_OPERATORS Read operators for OSFile instances.
           @{
        */
        OSFile& operator >> (unsigned char&);
        OSFile& operator >> (short&);
        OSFile& operator >> (unsigned short&);
        OSFile& operator >> (int&);
        OSFile& operator >> (unsigned int&);
        OSFile& operator >> (long&);
        OSFile& operator >> (unsigned long&);
        OSFile& operator >> (float&);
        OSFile& operator >> (double&);
        /**
           @}
        */

        /**
           @defgroup OSFILE_WRITE_OPERATORS Write operators for OSFile instances.
           @{
        */
        OSFile& operator << (unsigned char);   
        OSFile& operator << (short);
        OSFile& operator << (unsigned short);
        OSFile& operator << (int);
        OSFile& operator << (unsigned int);
        OSFile& operator << (long);
        OSFile& operator << (unsigned long);
        OSFile& operator << (float);
        OSFile& operator << (double);
        /**
           @}
        */
        
        /**
           Dumps the content of a OSFile object, printing all of its attributes.
           <br/>All references to other objects will only be dumped as hexadecimal
           addresses.
         
           @note The returned pointer needs to be free through a call to MEM_free or Teamcenter::scoped_smptr.
        */
        virtual char *asString() const;


    protected:
        /**
           Checks if the provided character is one of the characters in the @p iSeparators parameter. 
        */
        bool isSeparator(char iCharacter, const char *iSeparators) const;


    private:
        /** Retrieves the file stats information */
        void getFileInformation();

        /** ID of the file owner */
        int m_owner;

        /** File creation date */
        int m_creationDate;

        /** File protection mode */
        int m_fileProtection;

        /** File descriptor */
        SS_fd m_fileDescriptor;

        /** Mode flag to determine if the file is text or binary */
        int m_flagTextBinary;

        /** The file size */
        int m_fileSize;

        /** The file format */
        int m_fileFormat;
        
        /** Flag to determine if the file stats shall be retrieved */
        bool m_statDataRetrieved;

        /** File parsing: line content */
        char* m_parsedLine;

        /** File parsing: cursor position */
        int m_parsedLinePosition;

        /** File parsing: line length */
        int m_parsedLineLength;

        /** File parsing: reports if a parsing error has occurred */
        bool m_parsingError;

        /** File path */
        char* m_filePath;

        /** The file status */
        struct
        {
            int error_status;       /**< Any error that has occurred on a file operation */
            const char* operation;  /**< The name of the operation where the error has occurred */
        }  m_fileStatus;

        /** Constants defining the different types of operations done on the OSFile instance */ 
        static const char* OPERATION_CONSTRUCTOR;
        static const char* OPERATION_COPYCONST;  
        static const char* OPERATION_OPERATOREQUALS;  
        static const char* OPERATION_RENAME;
        static const char* OPERATION_CHANGEFP;
        static const char* OPERATION_CREATE;
        static const char* OPERATION_OPEN;
        static const char* OPERATION_CLOSE;
        static const char* OPERATION_DELETE;
        static const char* OPERATION_EXISTS;
        static const char* OPERATION_CHMOD;
        static const char* OPERATION_STAT;
        static const char* OPERATION_COPY;
        static const char* OPERATION_READ;
        static const char* OPERATION_WRITE;
        static const char* OPERATION_FPRINTF;
        static const char* OPERATION_FSCANF;
        static const char* OPERATION_READLINEWA;
        static const char* OPERATION_READLINE;
        static const char* OPERATION_WRITELINE;
        static const char* OPERATION_SEEK;
        static const char* OPERATION_GETFILEINFO;
    };
}

#include <fclasses/libfclasses_undef.h>
#endif
