#ifndef File_H
#define File_H

#include <fstream>

#include "Array.h"
#include "Reader.h"
#include "Writer.h"

namespace Framework
{
    class Text; //! Text.h
    class Time; //! Time.h

    namespace Encryption
    {
        class Key; //! Key.h
    }
    class File; //! from this file

    //! Reads and writes to a file
    class File : public Reader,
                  public Writer,
                  public virtual ReferenceCounter
    {
    public:
        class Style
        {
        public:
            static const int read = 0x01; //! file is opened for reading
            static const int write
                = 0x02; //! file is opened for writing
            static const int end
                = 0x04; //! sets file pointer to the end of the file
        };

    private:
        std::fstream* stream;
        Text* pfad;
        __int64 gr;
        char tmpReadByte;
        char tmpReadBPos;
        char tmpWriteByte;
        char tmpWriteBPos;
        Encryption::Key* key;

    public:
        //! Constructor
        DLLEXPORT File();
        //! Constructor
        DLLEXPORT File(const char* pfad);
        //! Constructor
        DLLEXPORT File(Text* pfad);
        //! Destructor
        DLLEXPORT virtual ~File();
        //! Sets the path to the file
        //! \param pfad The path
        DLLEXPORT void setFile(const char* pfad);
        //! Sets the path to the file
        //! \param pfad The path
        DLLEXPORT void setFile(Text* pfad);
        //! Renames or moves the file
        //! \param pfad The new path to the file. If only the name changes,
        //! it is only renamed
        //! \return 1 if the renaming was successful. 0 otherwise
        DLLEXPORT bool rename(const char* pfad);
        //! Renames or moves the file
        //! \param pfad The new path to the file. If only the name changes,
        //! it is only renamed
        //! \return 1 if the renaming was successful. 0 otherwise
        DLLEXPORT bool rename(Text* pfad);
        //! Deletes the file
        //! \return 1 if the deletion was successful. 0 otherwise
        DLLEXPORT bool remove();
        //! Creates the file anew. If the path contains folders that don't
        //! exist, they will be created
        //!  return 1 if the creation was successful. 0 otherwise
        DLLEXPORT bool create();
        //! Opens the file
        //! \param style Specifies whether the file is opened for reading and/or
        //! writing. All elements from File::Style:: are possible
        //!  return 1 if the file was opened successfully. 0 otherwise
        DLLEXPORT bool open(int style);
        //! Sets the position of the byte to be read next
        //! \param pos The index of the byte
        //! \param ende 1 if the index counts from the end of the file. 0 if the
        //! index counts from the beginning of the file
        DLLEXPORT void setReadPosition(__int64 pos, bool ende) override;
        //! Sets the position of the byte to be overwritten next
        //! \param pos The index of the byte
        //! \param ende 1 if the index counts from the end of the file. 0 if the
        //! index counts from the beginning of the file
        DLLEXPORT void setWritePosition(__int64 pos, bool ende) override;
        //! Writes to the file
        //! \param bytes An array of bytes to be written
        //! \param len How many bytes should be written to the file
        DLLEXPORT void write(const char* bytes, int len) override;
        //! Writes all temporary bytes to the file
        DLLEXPORT void flush();
        //! Reads from the file
        //! \param bytes An array to be filled with bytes from the file
        //! \param len How many bytes should be read from the file
        DLLEXPORT void read(char* bytes, int len) override;
        //! Reads the next line of the file
        //! \return The read line as Text with line break
        DLLEXPORT Text* readLine() override;
        //! Closes the file
        DLLEXPORT void close();
        //! Sets the encryption key for the file
        DLLEXPORT void setKey(char* s, int l);
#ifdef WIN32
        //! Sets the timestamp of the last modification of the file (Windows only)
        //! \param zeit The timestamp of the last modification
        //! \return 1 if the timestamp was set. 0 otherwise
        DLLEXPORT bool setLetzteAEnderung(Time* zeit);
#endif
        //! Reads the next bit from the file
        //! \param bit A reference to a bool where the bit will be stored
        //!  return 1 if the read was successful. 0 otherwise
        DLLEXPORT bool getNextBit(bool& bit);
        //! Stores a single bit in the file
        //! \param bit The bit to be stored
        //!  return 1 if the storage was successful
        DLLEXPORT bool setNextBit(bool bit);
        //! Checks whether the file is a directory
        //!  return 1 if the file is a directory. 0 otherwise
        DLLEXPORT bool isDirectory() const;
        //! Checks whether the file has been opened
        //! \return 1 if the file is open. 0 otherwise
        DLLEXPORT bool isOpen() const;
        //! Returns the number of sub-files in the directory
        //! \return 0 if the file is not a directory. Otherwise the number
        //! of sub-files
        DLLEXPORT int getSubFileCount() const;
        //! Returns a list of sub-files
        //!  return 0 if the file is not a directory. A list with the
        //!  names of the sub-files
        DLLEXPORT RCArray<Text>* getFileList() const;
        //! Returns the size of the file
        //! return -1 if the file is a directory or an error occurred.
        //! Otherwise the size of the file
        DLLEXPORT __int64 getSize() const;
        //! Returns the timestamp of the last modification
        //! \return 0 if an error occurred. The timestamp of the
        //! last modification otherwise
        DLLEXPORT Time* getLastChange() const;
        //! Checks whether the file exists
        //! \return 1 if the file exists. 0 otherwise
        DLLEXPORT bool exists() const;
        //! Returns the index of the byte from the file that would be read next
        //! return -1 if an error occurred.
        //! Otherwise the position of the read pointer
        DLLEXPORT __int64 getReadPosition() const override;
        //! Returns the index of the byte from the file that would be overwritten next
        //! return -1 if an error occurred.
        //! Otherwise the position of the write pointer
        DLLEXPORT __int64 getWritePosition() const override;
        //! Checks whether the file has been fully read
        //!  return 1 if the file has been fully read. 0 otherwise
        DLLEXPORT bool isEnd() const override;
        //! Returns the path to the file
        DLLEXPORT Text* getPfad() const;
        //! Returns the path to the file without increasing the reference counter
        DLLEXPORT Text* zPfad() const;
    };

    //! File Functions

    //! Searches for an unused filename
    //! \param zPfad A pointer to the path in which an unused filename
    //! should be found. Without increased reference counter.
    //!          Also used as return value
    DLLEXPORT void GetFreePfad(Text* zPfad);
    //! Creates the complete path including file
    //! \param pfad The path to the file
    //! \return 1 if the creation was successful.
    DLLEXPORT bool FilePathCreate(Text* pfad);
    //! Deletes the specified file
    //! \param pfad The path to the file
    //! \return 1 if the file was deleted
    DLLEXPORT bool FileRemove(Text* pfad);
    //! Renames or moves a file
    //!  pfad_alt: The path to the file to be renamed.
    //!  pfad_neu: The new path to the file. If only the name changes,
    //!  it is only renamed
    //! \return 1 if the renaming was successful. 0 otherwise
    DLLEXPORT bool FileRename(Text* pfad_alt, Text* pfad_neu);
    //! Checks whether a file exists
    //! \param pfad The path to the file
    //! \return 1 if the file exists. 0 if the file was not found
    DLLEXPORT bool FileExists(Text* pfad);
    //! Checks whether a path is a directory
    //! \param pfad The path to the file
    //! \return 1 if the file is a directory. 0 otherwise
    DLLEXPORT bool FileIsDirectory(Text* pfad);
    //! Creates the complete path including file
    //! \param pfad The path to the file
    //! \return 1 if the creation was successful.
    DLLEXPORT bool FilePathCreate(const char* pfad);
    //! Deletes the specified file
    //! \param pfad The path to the file
    //! \return 1 if the file was deleted
    DLLEXPORT bool FileRemove(const char* pfad);
    //! Renames or moves a file
    //!  pfad_alt: The path to the file to be renamed.
    //!  pfad_neu: The new path to the file. If only the name changes,
    //!  it is only renamed
    //! \return 1 if the renaming was successful. 0 otherwise
    DLLEXPORT bool FileRename(const char* pfad_alt, const char* pfad_neu);
    //! Checks whether a file exists
    //! \param pfad The path to the file
    //! \return 1 if the file exists. 0 if the file was not found
    DLLEXPORT bool FileExists(const char* pfad);
    //! Checks whether a path is a directory
    //! \param pfad The path to the file
    //! \return 1 if the file is a directory. 0 otherwise
    DLLEXPORT bool FileIsDirectory(const char* pfad);
} // namespace Framework

#endif