#ifndef FileSystem_H
#define FileSystem_H

#include <fstream>

#include "Array.h"
#include "Point.h"

namespace Framework
{
    class Image;    //! Image.h
    class Text;    //! Text.h
    class ProgressBar; //! Progress.h
#ifdef WIN32
    class Character; //! Font.h
    class Alphabet;  //! Font.h
    class Font;   //! Font.h
#endif
    class LTDBPixel; //! from this file
    class LTDBHeader;  //! from this file
    class LTDBBody;  //! from this file
    class LTDBFile; //! from this file
    class LTDSPixel; //! from this file
#ifdef WIN32
    class LTDSFileHeader;        //! from this file
    class LTDSFontHeader;      //! from this file
    class LTDSCharacterHeader;   //! from this file
    class LTDSCharacterBody; //! from this file
    class LTDSFile;            //! from this file
#endif

    //! LTDB File format --- Used for storing multiple images in one file.

    //! Used for storing and loading a single pixel from an image in the
    //! LTDB file format
    class LTDBPixel : public virtual ReferenceCounter //! Pixel of an LTDB file
    {
    private:
        LTDBPixel* davor; //! Previous pixel
        char index;       //! Bit length of the pixel
        char iR, iG, iB, iA;
        char miR, miG, miB, miA;
        char maxIndex;    //! Length of the pixel
        bool change  : 1; //! Whether something changes in the following 5 variables
        bool changeR : 1; //! Whether Red changes
        bool changeG : 1; //! Whether Green changes
        bool changeB : 1; //! Whether Blue changes
        bool changeA : 1; //! Whether Alpha changes
        unsigned char komp : 3; //! Compression of color values
        unsigned char R;        //! Red
        unsigned char G;        //! Green
        unsigned char B;        //! Blue
        unsigned char A;        //! Alpha
        bool addBitZuColor(
            unsigned char bit); //! Adds a bit to the color values
        bool getNextColorBit(
            char& byte, int i); //! Stores the next color bit in byte

    public:
        //! Constructor
        //! \param davor The pixel that was loaded before. 0 if this is the
        //! first pixel
        DLLEXPORT LTDBPixel(LTDBPixel* davor);
        //! Destructor
        DLLEXPORT ~LTDBPixel();
        //! For loading. Adds some bits to the pixel
        //! \param byte The last byte read from the file
        //! \param begin The index of the first bit in byte where the pixel begins
        //! \return The index of the bit in byte where the pixel ended. -1 if
        //! the pixel is not finished at the end of the byte
        DLLEXPORT char addByte(char byte, char begin);
        //! For saving. Sets the color to be stored in the pixel
        //! \param f The color to store
        DLLEXPORT void setColor(int f);
        //! Compresses the pixel. Must be called before saving.
        DLLEXPORT void compress();
        //! Returns a part of the bits that represent the pixel
        //! \param byte A reference to the byte to be saved next
        //! \param begin The index of the first bit in the byte where the pixel
        //! should be stored \return The index of the bit where the pixel ends.
        //! -1 if the pixel must continue in the next byte
        DLLEXPORT char getNextByte(char& byte, int begin);
        //! Returns the color value of the pixel
        DLLEXPORT int toColor() const;
        //! Returns whether the red component changed compared to the previous pixel
        DLLEXPORT bool getChangeR() const;
        //! Returns whether the green component changed compared to the previous pixel
        DLLEXPORT bool getChangeG() const;
        //! Returns whether the blue component changed compared to the previous pixel
        DLLEXPORT bool getChangeB() const;
        //! Returns whether the alpha component changed compared to the previous pixel
        DLLEXPORT bool getChangeA() const;
        //! Returns the compression of the pixel
        DLLEXPORT unsigned char getKomp() const;
        //! Returns the red component of the pixel's color
        DLLEXPORT unsigned char getR() const;
        //! Returns the green component of the pixel's color
        DLLEXPORT unsigned char getG() const;
        //! Returns the blue component of the pixel's color
        DLLEXPORT unsigned char getB() const;
        //! Returns the alpha component of the pixel's color
        DLLEXPORT unsigned char getA() const;
    };

    //! The header of the LTDB file format. Stores information about all
    //! saved images
    class LTDBFileHeader : public virtual ReferenceCounter
    {
    private:
        RCArray<Text>* bilder;
        Array<__int64>* pos;
        int bCount;

    public:
        //! Constructor
        DLLEXPORT LTDBFileHeader();
        //! Destructor
        DLLEXPORT ~LTDBFileHeader();
        //! Removes an image from the file header
        //! \param i The index of the image to remove
        DLLEXPORT void removeImage(int i);
        //! Removes an image from the file header
        //! \param txt The name of the image to remove
        DLLEXPORT void removeImage(Text* txt);
        //! Adds an image to the file header
        //! \param txt The name of the image
        DLLEXPORT void addImage(Text* txt);
        //! Sets the byte index in the file where the image begins
        //! \param i The index of the image
        //! \param pos The position of the image in the file
        DLLEXPORT void setImagePos(int i, __int64 pos);
        //! Sets the byte index in the file where the image begins
        //! \param txt The name of the image
        //! \param pos The position of the image in the file
        DLLEXPORT void setImagePos(Text* txt, __int64 pos);
        //! Loads the file header of an LTDB file
        //! \param f A pointer to a progress bar to use for loading. Can be 0.
        //! \param inF The opened ifstream of the LTDB file with the read
        //! position already pointing to the first byte of the file header.
        DLLEXPORT void load(ProgressBar* f, std::ifstream* inF);
        //! Saves the file header to an LTDB file
        //! \param outF The opened ofstream of the LTDB file with the write
        //! position already pointing to the first byte of the file header.
        DLLEXPORT void save(std::ofstream* outF) const;
        //! Returns the name of a specific image
        //! \param i The index of the image whose name should be returned
        //! \return The name of the image
        DLLEXPORT Text* getImage(int i) const;
        //! Returns the name of a specific image
        //! \param i The index of the image whose name should be returned
        //! \return The name of the image without increased reference counter
        DLLEXPORT Text* zImage(int i) const;
        //! Returns the index of the first byte of an image in the file
        //! \param txt The name of the image whose start should be found
        //! \return -1 if the image was not found.
        DLLEXPORT __int64 getImagePosition(Text* txt) const;
        //! Returns the index of the first byte of an image in the file.
        //! If the index does not exist, std::out_of_range is thrown.
        //! \param index The index of the image whose start should be found
        DLLEXPORT __int64 getImagePosition(int index) const;
        //! Returns the index of a specific image
        //! \param txt The name of the image
        //! \return -1 if the image was not found
        DLLEXPORT int getImageIndex(Text* txt) const;
        //! Returns the number of images in the file
        DLLEXPORT int getBCount() const;
        //! Returns a list of images in the file without increased reference
        //! counter. The list should not be modified
        DLLEXPORT RCArray<Text>* zImageListe() const;
    };

    //! Information stored in the LTDB file header for a single image
    class LTDBHeader : public virtual ReferenceCounter
    {
    private:
        __int64 a; //! The LTDB file header is at most 104 bits long
        __int32 b; //! - up to 75 bits for the title
        __int8 c;  //! - 12 bits for width

    public:
        //! Constructor
        DLLEXPORT LTDBHeader();
        //! Loads information about an image
        //! \param f The opened ifstream of the LTDB file pointing to the
        //! correct position
        DLLEXPORT void load(std::ifstream* f);
        //! Sets the information to be stored
        //! \param title The title of the image
        //! \param size The size of the image
        //! \return The number of characters from the title that cannot be
        //! stored in the LTDB file format. Only a-z, A-Z, ae ue oe ss,
        //! AE UE OE and . are allowed. All uppercase letters in the title
        //! are converted to lowercase
        DLLEXPORT int Init(Text* title, const Point& size);
        //! Loads information from loaded bits. Used by the load(
        //! std::ifstream) function. \param BeginBit The index of the first
        //! bit to evaluate \param EndBit The index of the last bit that
        //! should not be evaluated anymore \param bits The bits from which
        //! all between BeginBit and EndBit should be evaluated.
        //! A total of 104 bits must be set. BeginBit and EndBit refer to this
        //! bezihen sich BeginBit und EndBit
        DLLEXPORT void setBits(int BeginBit, int EndBit, __int16 bits);
        //! Saves the information to a file
        //! \param f The opened ofstream of the LTDB file pointing to the
        //! correct position
        DLLEXPORT void save(std::ofstream* f) const;
        //! Returns the length of the title
        DLLEXPORT int getTitelLength() const;
        //! Returns the title of the image
        DLLEXPORT Text* getTitel() const;
        //! Returns the size of the image
        DLLEXPORT Point getSize() const;
        //! Returns the next bits to be saved
        //! \param begin The index of the first bit to save into
        //! \param end The index of the last bit to save into
        //! \return 16 bits containing the information between begin and end.
        //! A total of 104 bits must be read. BeginBit and EndBit refer to this
        DLLEXPORT __int16 getBits(int begin, int end) const;
    };

    //! Manages the pixel data of a single image in an LTDB file
    class LTDBBody : public virtual ReferenceCounter
    {
    private:
        Point gr;
        Image* b;
        int dateiSize;

    public:
        //! Constructor
        DLLEXPORT LTDBBody();
        //! Constructor
        //! \param k The LTDB header of the image containing information about
        //! the size of the image
        DLLEXPORT LTDBBody(LTDBHeader* k);
        //! Destructor
        DLLEXPORT ~LTDBBody();
        //! Sets information about the size of the image. Required for loading.
        //! \param k The LTDB header of the image
        DLLEXPORT void init(LTDBHeader k);
        //! Sets information about the size of the image. Required for loading.
        //! \param k The LTDB header of the image
        DLLEXPORT void init(LTDBHeader* k);
        //! Loads the pixel data from the file
        //! \param zF A progress bar that can be 0
        //! \param inF The opened ifstream of the LTDB file pointing to the
        //! correct position
        DLLEXPORT void load(ProgressBar* zF, std::ifstream* inF);
        //! Sets the image to be saved
        //! \param b The image to save
        DLLEXPORT void setImage(Image* b);
        //! Saves the pixel data of the image in an LTDB file
        //! \param zF A progress bar that can be 0
        //! \param outF The opened ofstream of the LTDB file pointing to the
        //! correct position
        DLLEXPORT void save(ProgressBar* zF, std::ofstream* outF) const;
        //! Returns the loaded image
        DLLEXPORT Image* getImage() const;
        //! Returns the size of the image
        DLLEXPORT const Point& getSize() const;
    };

    //! Manages an LTDB file
    class LTDBFile : public virtual ReferenceCounter
    {
    private:
        Text* pfad;
        LTDBFileHeader* datKpf;

    public:
        //! Constructor
        DLLEXPORT LTDBFile();
        //! Destructor
        DLLEXPORT ~LTDBFile();
        //! Sets the path to the file
        //! \param pfad The path
        DLLEXPORT void setFile(Text* pfad);
        //! Creates a new LTDB file
        DLLEXPORT void create();
        //! Reads basic information from the file.
        //! Must be called before working with the file
        //! \param zF A progress bar that can be 0
        DLLEXPORT void readData(ProgressBar* zF);
        //! Deletes the LTDB file
        DLLEXPORT void remove();
        //! Deletes an image from the LTDB file
        //! \param zF A progress bar that can be 0
        //! \param name The name of the image to delete
        DLLEXPORT void remove(ProgressBar* zF, Text* name);
        //! Loads an image from the LTDB file
        //! \param zF A progress bar that can be 0
        //! \param name The name of the image to load
        //! \return The loaded image. 0 if the image was not found
        DLLEXPORT Image* load(ProgressBar* zF, Text* name);
        //! Saves a new image in the LTDB file
        //! \param zF A progress bar that can be 0
        //! \param bild The image to save
        //! \param name The name under which the image should be saved
        //! \return Number of warnings that occurred while converting the name
        //! to a valid name. -1 if an image with the same name already exists
        DLLEXPORT int save(ProgressBar* zF, Image* bild, Text* name);
        //! Returns a list of stored images.
        //! The list should not be modified
        DLLEXPORT RCArray<Text>* zImageListe();
        //! Returns the path to the LTDB file
        DLLEXPORT Text* getPfad() const;
        //! Returns the number of images in the LTDB file
        DLLEXPORT int getImageCount() const;
        //! Checks whether the LTDB file exists
        DLLEXPORT bool isOpen() const;
    };

#ifdef WIN32
    //! LTDS file format --- Used for storing fonts

    //! Manages a single pixel of a character
    class LTDSPixel : public virtual ReferenceCounter
    {
    private:
        char index;
        char iA;
        char miA;
        char maxIndex; //! Length of the pixel
        bool aender;
        bool aenderA;
        unsigned char komp : 3; //! Compression of the color values
        unsigned char alpha;
        LTDSPixel* davor;
        bool addBitZuColor(
            unsigned char bit); //! Adds a bit to the color values
        bool getNextColorBit(
            char& byte, int i); //! Stores the next color bit in byte

    public:
        //! Constructor
        //! \param davor The pixel that was loaded before this one. 0 if this
        //! is the first pixel
        DLLEXPORT LTDSPixel(LTDSPixel* davor);
        //! Destructor
        DLLEXPORT ~LTDSPixel();
        //! Adds some loaded bits to the pixel. For loading.
        //! \param byte The last byte loaded from the file.
        //! \param begin The index of the first bit in the byte where the pixel begins
        //! \return The index of the last bit in the byte where the pixel ends.
        //! -1 if the pixel continues in the next byte
        DLLEXPORT char addByte(char byte, char begin);
        //! Sets the alpha value of the pixel. For saving.
        //! \param alpha The alpha value of the pixel.
        DLLEXPORT void setAlpha(unsigned char alpha);
        //! Compresses the pixel. Must be called before saving.
        DLLEXPORT void Komp();
        //! Returns a part of the bits that represent the pixel
        //! \param byte A reference to the byte to be saved next
        //! \param begin The index of the first bit in the byte where the pixel
        //! should be stored \return The index of the bit in the byte where the
        //! pixel ends. -1 if the pixel must continue in the next byte
        DLLEXPORT char getNextByte(char& byte, int bbegin);
        //! Returns the compression of the pixel
        DLLEXPORT unsigned char getKomp() const;
        //! Returns whether the alpha value changed compared to the previous pixel
        DLLEXPORT bool getAEnderA() const;
        //! Returns the alpha value of the pixel
        DLLEXPORT unsigned char getA() const;
    };

    //! Manages the header of an LTDS file. Contains information about the
    //! font sizes stored in the file
    class LTDSFileHeader : public virtual ReferenceCounter
    {
    private:
        unsigned char sganzahl;
        unsigned char* gr;
        int* pos;

    public:
        //! Constructor
        DLLEXPORT LTDSFileHeader();
        //! Destructor
        DLLEXPORT ~LTDSFileHeader();
        //! Loads the header from the LTDS file
        //! \param inF The opened ifstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void load(std::ifstream* inF);
        //! Adds a font size
        //! \param sg The font size to add
        DLLEXPORT void addSG(char sg);
        //! Deletes a font size
        //! \param sg The font size to delete
        DLLEXPORT void removeSG(char sg);
        //! Saves the LTDS header to the file
        //! \param outF The opened ofstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void save(std::ofstream* outF) const;
        //! Returns an array of stored font sizes.
        //! The array should not be modified
        DLLEXPORT unsigned char* getFontSizeList() const;
        //! Returns an array with positions of the first bytes for each
        //! font size in the file
        DLLEXPORT int* getPositionList() const;
        //! Returns the number of stored font sizes
        DLLEXPORT int getFontSizeCount() const;
    };

    //! The header of a font size. Contains information about the
    //! stored characters
    class LTDSFontHeader : public virtual ReferenceCounter
    {
    private:
        unsigned char fontSize;
        unsigned char* zeichen;
        int* pos;
        unsigned char zeichenAnzahl;

    public:
        //! Constructor
        DLLEXPORT LTDSFontHeader();
        //! Destructor
        DLLEXPORT ~LTDSFontHeader();
        //! Loads the header of a font size from the file
        //! \param inF The opened ifstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void load(std::ifstream* inF);
        //! Sets the font size. For saving
        //! \param gr The font size
        DLLEXPORT void setFontSize(unsigned char gr);
        //! Sets the alphabet to be stored in the font size
        //! \param alphabet The alphabet containing all characters to store
        //! in the font size
        DLLEXPORT void setCharAlphabet(Alphabet* alphabet);
        //! Adds a character to the font size to be stored
        //! \param zeichen The ASCII code of the character to add
        DLLEXPORT void addChar(unsigned char zeichen);
        //! Deletes a character from the font size
        //! \param zeich The ASCII code of the character to delete
        DLLEXPORT void removeChar(unsigned char zeich);
        //! Saves the font size header to the LTDS file
        //! \param outF The opened ofstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void save(std::ofstream* outF) const;
        //! Returns the font size this header belongs to
        DLLEXPORT unsigned char getFontSize() const;
        //! Returns the number of characters stored in the font size
        DLLEXPORT unsigned char getCharCount() const;
        //! Returns an array with the positions of the first bytes of the
        //! stored characters in the LTDS file
        DLLEXPORT int* getPositionen() const;
        //! Returns an array with the ASCII codes of the stored characters
        DLLEXPORT unsigned char* getChar() const;
    };

    //! The header of a single character from the LTDS file. Contains
    //! information about the pixel size of the character
    class LTDSCharacterHeader : public virtual ReferenceCounter
    {
    private:
        unsigned char zeichen;
        Point size;

    public:
        //! Constructor
        DLLEXPORT LTDSCharacterHeader();
        //! Loads the data from the LTDS file
        //! \param inF The opened ifstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void load(std::ifstream* inF);
        //! Sets the data to be saved.
        //! \param zeichen The ASCII code of the character
        //! \param groesse The size of the character in pixels
        DLLEXPORT void init(unsigned char zeichen, const Point& groesse);
        //! Sets the data to be saved.
        //! \param zeichen The ASCII code of the character
        //! \param br The width of the character in pixels
        //! \param hoe The height of the character in pixels
        DLLEXPORT void init(unsigned char zeichen, int br, int hoe );
        //! Saves the data to the LTDS file
        //! \param outF The opened ofstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void save(std::ofstream* outF) const;
        //! Returns the ASCII code of the character
        DLLEXPORT unsigned char getChar() const;
        //! Returns the width of the character in pixels
        DLLEXPORT int getWidth() const;
        //! Returns the height of the character in pixels
        DLLEXPORT int getHeight() const;
        //! Returns the size of the character in pixels
        DLLEXPORT const Point& getSize() const;
    };

    //! Manages the pixel data of a character
    class LTDSCharacterBody : public virtual ReferenceCounter
    {
    private:
        Point size;
        unsigned char zeichen;
        Character* buchstabe;

    public:
        //! Constructor
        //! \param kopf The header of the character
        DLLEXPORT LTDSCharacterBody(LTDSCharacterHeader * kopf);
        //! Destructor
        DLLEXPORT ~LTDSCharacterBody();
        //! Sets the character to be saved
        //! \param zeichen The character to save
        DLLEXPORT void setCharacter(Character * zeichen);
        //! Loads the pixels from the LTDS file
        //! \param inF The opened ifstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void load(std::ifstream * inF);
        //! Saves the pixels to the LTDS file
        //! \param outF The opened ofstream of the LTDS file pointing to the
        //! correct position
        DLLEXPORT void save(std::ofstream * outF) const;
        //! Returns the loaded character
        DLLEXPORT Character* getCharacter() const;
        //! Returns the ASCII code of the character
        DLLEXPORT unsigned char getChar() const;
    };

    //! Manages an LTDS file
    class LTDSFile : public virtual ReferenceCounter
    {
    private:
        Text* pfad;
        LTDSFileHeader* dateiKopf;

    public:
        //! Constructor
        DLLEXPORT LTDSFile();
        //! Destructor
        DLLEXPORT ~LTDSFile();
        //! Sets the path to the file
        //! \param txt The path
        DLLEXPORT void setPfad(Text* txt);
        //! Loads important information from the file. Must be called before
        //! using the file
        DLLEXPORT void readData();
        //! Adds a font size to the file if it does not already exist
        //! \param alphabet The alphabet containing the characters in the
        //! desired font size
        DLLEXPORT void addFontSize(Alphabet* alphabet);
        //! Adds a character to a font size
        //! \param gr The font size of the character
        //! \param zeich The character to save
        //! \param zeichen The ASCII code of the character
        DLLEXPORT void addCharacter(
            int gr, Character* zeich, unsigned char zeichen);
        //! Deletes a specific font size from the file
        //! \param gr The font size to remove
        DLLEXPORT void deleteFontSize(int gr);
        //! Deletes a character from a font size
        //! \param gr The font size from which the character should be removed
        //! \param zeichen The ASCII code of the character to delete
        DLLEXPORT void deleteCharacter(int gr, unsigned char zeichen);
        //! Deletes the LTDS file
        DLLEXPORT void deleteFile();
        //! Creates the LTDS file
        DLLEXPORT void createFile();
        //! Saves an entire font to the file
        //! \param font The font to save
        DLLEXPORT void saveFont(Font* font);
        //! Loads the entire font from the file
        //! \return The loaded font. 0 if an error occurred while loading
        DLLEXPORT Font* loadFont();
        //! Loads a single font size from the file
        //! \param fontgroesse The font size to load
        //! \return An alphabet with the characters in the font size. 0 if
        //! the font size was not found
        DLLEXPORT Alphabet* loadAlphabet(int fontgroesse);
        //! Loads a specific character of a specific font size
        //! \param fontgroesse The font size the character belongs to
        //! \param zeichen The ASCII code of the character to load
        //! \return The loaded character. 0 if the character was not found.
        DLLEXPORT Character* loadCharacter(
            int fontgroesse, unsigned char zeichen);
        //! Returns the path to the LTDS file
        DLLEXPORT Text* getPfad() const;
        //! Returns the number of stored font sizes
        DLLEXPORT int getFontSizeCount() const;
        //! Returns an array with the stored font sizes.
        //! The array should not be modified
        DLLEXPORT unsigned char* getFontSizes() const;
        //! Returns the number of stored characters in a font size
        //! \param sg The font size for which the number of characters
        //! should be determined \return The number of characters.
        DLLEXPORT unsigned char getCharacterCount(int sg);
        //! Returns an array with characters of a specific font size
        //! \param sg The font size
        //! \return The array with the ASCII codes of the characters. 0 if the
        //! font size was not found.
        DLLEXPORT unsigned char* getCharacters(int sg);
    };
#endif
    //! Bit functions

    //! Returns 1-bits in the desired count.
    //! \param a The number of bits that should be 1
    //! \return 32 bits, where the one-bits start from the right
    DLLEXPORT int Bits(int a);
    //! Returns how many bits are needed to represent a number
    //! \param c The number to represent
    //! \return The number of required bits
    DLLEXPORT int getBits(char c);
} // namespace Framework
#endif