#ifndef Schrift_H
#define Schrift_H

#include <functional>

#include "Critical.h"
#include "Punkt.h"
#include "ReferenceCounter.h"

namespace Framework
{
    class Bild;      //! Bild.h
    class Text;      //! Text.h
    class Buchstabe; //! aus dieser Datei
    class Alphabet;  //! aus dieser Datei
    class Schrift;   //! aus dieser Datei

    //! Speichert die Alphawerte eines Zeichens einer bestimmten Schrift
    //! Die anderen Farbwerte werden durch die Schriftfarbe bestimmt. Daher nur
    //! die Alpha werte.
    class Buchstabe : public virtual ReferenceCounter
    {
    private:
        Punkt size;
        unsigned char* alpha;
        int schriftSize;

    public:
        //! Erstellt ein neues leeres Zeichnung
        DLLEXPORT Buchstabe();
        //! L�scht das Zeichnung
        DLLEXPORT ~Buchstabe();
        //! Erstellt einen neuen Buchstaben mit bestimmter Gr��e
        //! \param size Die Gr��e des Buchstabens in Pixel
        DLLEXPORT void NeuBuchstabe(Punkt& size);
        //! Setzt den Alphawert eines bestimmten Pixels
        //! \param pos Die position des Pixels
        //! \param alpha Der Wert des Pixels
        DLLEXPORT void setPixel(Punkt& pos, unsigned char alpha);
        //! Setzt den Alphawert eines bestimmten Pixels
        //! \param x die x Position des Pixels
        //! \param y die y Position des Pixels
        //! \param alpha Der Wert des Pixels
        DLLEXPORT void setPixel(int x, int y, unsigned char alpha);
        //! Setzt den Alphawert eines bestimmten Pixels
        //! \param i der Index des Pixels. Er berechnet sich durch x + y *
        //! breite und geht von 0 bis breite * h�he - 1 \param alpha Der Wert
        //! des Pixels
        DLLEXPORT void setPixel(int i, unsigned char alpha);
        //! Setzt die Schriftgr��e, zu der der Buchstabe geh�rt
        //! \param sg Die Schriftgr��e des Buchstabens.
        DLLEXPORT void setSchriftSize(int sg);
        //! Gibt die Schriftgr��e zur�ck, zu der der Buchstabe geh�rt
        DLLEXPORT int getSchriftSize() const;
        //! Gibt die alpha Werte des Buchstabens als array zur�ck wobei die
        //! werte Zeilenweise hintereinander stehen
        DLLEXPORT unsigned char* getBuff() const;
        //! Gibt die Gr��e des Buchstabens in Pixeln nicht skalliert zur�ck.
        DLLEXPORT const Punkt& getSize() const;
        //! Gibt die Breite des Buchstabens in Pixeln zur�ck
        DLLEXPORT int getBreite() const;
        //! Gibt die H�he des Buchstabens in Pixeln zur�ck
        DLLEXPORT int getHeight() const;
    };

    //! Speichert alle Buchstaben der selben Schriftgr��e.
    //! Wird von der Schrift klasse verwendet
    class Alphabet : public virtual ReferenceCounter
    {
    private:
        Buchstabe** zeichen;
        int schriftSize;

    public:
        //! Erzeugt ein leeres Zeichnung
        DLLEXPORT Alphabet();
        //! L�scht ein Zeichnung
        DLLEXPORT ~Alphabet();
        //! L�scht alle gespeicherten Zeichen
        DLLEXPORT void NeuAlphabet();
        //! F�gt dem Alphabet einen Buchstaben hinzu
        //! Wenn der hinzugef�gte Buchstabe bereits existiert wird er
        //! �berschrieben \param i Der ASCII code des Buchstaben, der
        //! hinzugef�gt werden soll \param buchstabe Der Buchstabe, der
        //! hinzugef�gt wird
        DLLEXPORT void setBuchstabe(unsigned char i, Buchstabe* buchstabe);
        //! Setzt die Schriftgr��e des Alphabets und die der gespeicherten
        //! buchstaben \param gr Die Schriftgr��e des Alphabets
        DLLEXPORT void setSchriftSize(int gr);
        //! Gibt den gespeicherten Buchstaben zu einem bestimmten ASCII Zeichen
        //! zur�ck \param i Der ASCII code des Zeichens \return Ein Zeiger zu
        //! dem Buchstaben mit erh�htem Reference Counter
        DLLEXPORT Buchstabe* getBuchstabe(unsigned char i) const;
        //! Gibt den gespeicherten Buchstaben zu einem bestimmten ASCII Zeichen
        //! zur�ck \param i Der ASCII code des Zeichens \return Ein Zeiger zu
        //! dem Buchstaben ohne erh�htem Reference Counter
        DLLEXPORT Buchstabe* zBuchstabe(unsigned char i) const;
        //! Pr�ft, ob zu einem bestimmten ASCII code ein Zeichen vorhanden ist
        //! \param b Der zu pr�fende ASCII code
        //! \return (true), wenn ein Zeichen zu dem Code gefunden wurde. (false)
        //! sonnst
        DLLEXPORT bool hatBuchstabe(unsigned char b) const;
        //! Gibt die Schriftgr��e zur�ck, deren Zeichen in diesem Alphabet
        //! gespeichert werden
        DLLEXPORT int getSchriftSize() const;
    };

    //! Specihert eine Liste von Alphabeten mit verschiedener Schriftgr��e.
    //! Wird von der Schrift Klasse verwendet, um alle Zeichen der Schriftgr��e
    //! nach sortiert zu speichern.
    class AlphabetArray
    {
    private:
        Alphabet* alphabets[256];

    public:
        //! Erzeugt eine neue Liste
        DLLEXPORT AlphabetArray();

        //! F�gt der Liste ein Alphabet hinzu
        //! Wenn bereits ein Alphabet mit der selben Schriftgr��e existiert,
        //! wird das Alphabet nicht hinzugef�gt \param alphabet Das Alphabet,
        //! welches hinzugef�gt werden soll \return (true), wenn das Alphabet
        //! hinzugef�gt wurde. (false) sonnst.
        DLLEXPORT bool addAlphabet(Alphabet* alphabet);
        //! L�scht ein Alphabet bestimmter Schriftgr��e aus der Liste
        //! \param sg Die Schriftgr��e des Alphabets, welches entfernt werden
        //! soll \return (true), wenn ein Alphabet entfernt wurde. (false)
        //! sonnst
        DLLEXPORT bool removeAlphabet(unsigned char sg);

        //! Gibt ein bestimmtes Alphabet mit erh�htem Reference Counter zur�ck
        //! \param sg Die Schriftgr��e, dessen Alphabet gesucht werden soll
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet* getAlphabet(unsigned char sg) const;
        //! Gibt ein bestimmtes Alphabet ohne erh�htem Reference Counter zur�ck
        //! \param sg Die Schriftgr��e, dessen Alphabet gesucht werden soll
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet* zAlphabet(unsigned char sg) const;
    };

    //! Speichert alle Buchstaben einer Schrift in verschiedenen Schriftgr��en
    class Schrift : public virtual ReferenceCounter
    {
    private:
        unsigned char alphabetAnzahl;
        AlphabetArray* alphabet;

    public:
        //! Erzeugt eine leere Schrift
        DLLEXPORT Schrift();
        //! L�scht ein Zeichnung
        DLLEXPORT ~Schrift();
        //! F�gt der Schrift ein Alphabet hinzu. Sollte bereits ein Alphabet der
        //! selben Schriftgr��e existieren, wird das Alphabet nicht hinzugef�gt
        //! \param alphabet Das Alphabet, welches hinzugef�gt werden soll
        //! \return (true), wenn das Alphabet hinzugef�gt wurde. (false) sonnst
        DLLEXPORT bool addAlphabet(Alphabet* alphabet);
        //! L�scht ein bestimmtes Alphabet aus der Schrift
        //! \param sg Die Schriftgr��e, deren Alphabet entfernt werden soll
        DLLEXPORT void removeAlphabet(unsigned char sg);
        //! Gibt ein bestimmtes Alphabet mit erh�htem Reference Counter zur�ck
        //! \param sg Die Schriftgr��e, dessen Alphabet gesucht werden soll
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet* getAlphabet(unsigned char sg) const;
        //! Gibt ein bestimmtes Alphabet ohne erh�htem Reference Counter zur�ck
        //! \param sg Die Schriftgr��e, dessen Alphabet gesucht werden soll
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet* zAlphabet(unsigned char sg) const;
        //! Gibt zur�ck, wie viele Alphabete (und damit Schriftgr��en) in der
        //! Schrift enthalten sind
        DLLEXPORT unsigned char getAlphabetAnzahl() const;
    };

    class TextRenderer : public virtual ReferenceCounter
    {
    protected:
        Schrift* s;
        int schriftSize;
        int zeilenAbstand;
        int zeichenAbstand;
        int charWidths[256];
        int charHeights[256];

    public:
        DLLEXPORT TextRenderer();
        DLLEXPORT TextRenderer(Schrift* schrift);
        DLLEXPORT virtual ~TextRenderer();
        DLLEXPORT void setSchriftZ(Schrift* schrift);
        DLLEXPORT Schrift* getSchrift();
        DLLEXPORT Schrift* zSchrift();
        //! Setzt die Schriftgr��e, in der gezeichnet werden soll. Die Schrift
        //! w�hlt automatisch das passende Alphabet zum Zeichnen \param sg Die
        //! Schriftgr��e
        DLLEXPORT void setSchriftSize(int sg);
        //! Setzt den Zeilenabstand, der zum zeichnen verwendet werden soll
        //! \param za Der Zeilenabstand zum unteren Ende der dar�ber liegenden
        //! zeile in Pixeln
        DLLEXPORT void setZeilenAbstand(int za);
        //! Setzt den Zeichenabstand, der zum zeichnen verwendet werden soll
        //! \param za Der Zeichenabstand zum unteren Ende der dar�ber liegenden
        //! zeile in Pixeln
        DLLEXPORT void setZeichenAbstand(int za);
        //! F�gt Zeilenumbr�che in den Text ein, so dass er bei einer
        //! vorgegebenen Breite follst�ndig angezeigt wird \param zText Der
        //! text, in den die Zeilenumbr�che eingef�gt werden sollen \param
        //! maxBreite Die Breite in Pixeln auf der der Text follst�ndig
        //! angezeigt werden soll
        DLLEXPORT virtual void textFormatieren(Text* zText, int maxBreite);
        //! Zeichnet einen Bestimmten Text mit Cursor und einf�rbung auf ein
        //! Bild Nutze (setPosition) und (setDrawSchriftGr��e) um die Position
        //! und die Gr��e zu ver�ndern \param x x position des ersten zeichens
        //! \param y y position des ersten zeichens
        //! \param txt Der Text, der gezeichnet werden soll
        //! \param zRObj Das Bild, auf das gezeichnet werden soll
        //! \param cpos Die position des Cursors im Text
        //! \param cf Die Farbe des Cursors
        //! \param fbeg Die Position des Zeichens im Text, wo die Einf�rbung
        //! beginnen soll. Der Text wird von dort bis zur Cursorposition
        //! eingef�rbt \param ff Die Hintergrund Farbe des eingef�rbten Textes
        //! \param f Eine Funktion die f�r jeden Buchstaben aufgerufen wird und
        //! seine Farbe zur�ckgibt
        DLLEXPORT virtual void renderText(int x,
            int y,
            const char* txt,
            Bild& zRObj,
            std::function<int(int, int, int)> f,
            int cpos = -1,
            int cf = 0,
            int fbeg = -1,
            int ff = 0);
        //! Zeichnet einen Bestimmten Text mit Cursor und einf�rbung auf ein
        //! Bild Nutze (setPosition) und (setDrawSchriftGr��e) um die Position
        //! und die Gr��e zu ver�ndern \param x x position des ersten zeichens
        //! \param y y position des ersten zeichens
        //! \param txt Der Text, der gezeichnet werden soll
        //! \param zRObj Das Bild, auf das gezeichnet werden soll
        //! \param cpos Die position des Cursors im Text
        //! \param cf Die Farbe des Cursors
        //! \param fbeg Die Position des Zeichens im Text, wo die Einf�rbung
        //! beginnen soll. Der Text wird von dort bis zur Cursorposition
        //! eingef�rbt \param ff Die Hintergrund Farbe des eingef�rbten Textes
        //! \param f Die Farbe, in der der Text gezeichnet werden soll
        DLLEXPORT virtual void renderText(int x,
            int y,
            const char* txt,
            Bild& zRObj,
            int f,
            int cpos = -1,
            int cf = 0,
            int fbeg = -1,
            int ff = 0);
        //! Zeichnet einen Bestimmten Buchstaben mit einf�rbung auf ein Bild
        //! Nutze (setPosition) und (setDrawSchriftGr��e) um die Position und
        //! die Gr��e zu ver�ndern \param x x position des ersten zeichens
        //! \param y y position des ersten zeichens
        //! \param txt Der Text, der gezeichnet werden soll
        //! \param zRObj Das Bild, auf das gezeichnet werden soll
        //! \param color Die Farbe, in der der Text gezeichnet werden soll
        //! \param underlined 1, falls der Text unterstrichen sein soll
        //! \param selected 1, falls das zeichen eingef�rbt sein soll
        //! \param selectedBackgroundColor Die Hintergrund Farbe des
        //! eingef�rbten Textes
        DLLEXPORT virtual void renderChar(int& x,
            int y,
            char c,
            Bild& zRObj,
            int color,
            bool underlined = 0,
            bool selected = 0,
            int selectedBackgroundColor = 0);
        //! Gibt die Schriftgr��e zur�ck, die zum Zeichnen verwendet wird
        DLLEXPORT int getSchriftSize() const;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten Text
        //! vollst�ndig darzustellen \param txt Der Text, von dem die Breite in
        //! Pixeln ermitelt werden soll
        DLLEXPORT virtual int getTextBreite(const char* txt) const;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten Text
        //! vollst�ndig darzustellen \param txt Der Text, von dem die H�he in
        //! Pixeln ermitelt werden soll
        DLLEXPORT virtual int getTextHeight(const char* txt) const;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten
        //! Buchstaben vollst�ndig darzustellen \param c Der Buchstabe, von dem
        //! die Breite in Pixeln ermitelt werden soll
        DLLEXPORT virtual int getCharWidth(const char c) const;
        //! Ermittelt, wie viele Pixel maximal ben�tigt werden, um einen
        //! Buchstaben vollst�ndig darzustellen
        DLLEXPORT virtual int getMaxCharWidth() const;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten Text
        //! vollst�ndig darzustellen \param c Der Buchstabe, von dem die H�he in
        //! Pixeln ermitelt werden soll
        DLLEXPORT virtual int getCharHeight(const char c) const;
        //! Gibt den Abstand in Pixeln zum unteren Ende der dar�ber ligenden
        //! Zeile zur�ck
        DLLEXPORT int getZeilenAbstand() const;
        //! Gibt den Abstand in Pixeln zum zwischen zwei zeichen auf der x Achse
        //! zur�ck
        DLLEXPORT int getZeichenAbstand() const;
        //! Gibt die skallierte H�he zur�ck, die eine gezeichnete Zeile in
        //! Pixeln ben�tigt
        DLLEXPORT int getZeilenHeight() const;
        //! Ermittelt das Zeichen im Text, auf das die Maus zeigt
        //! \param zTxt Der Text, auf den die Maus Zeigt
        //! \param mausX Die X Position der Maus in Pixeln Relativ zur Position
        //! des ersten Zeichens \param mausY Die Y Position der Maus in Pixeln
        //! Relativ zur Position des ersten Zeichens
        DLLEXPORT virtual int textPos(
            const char* txt, int mausX, int mausY) const;
    };

    class GravurTextRenderer : public TextRenderer
    {
    public:
        DLLEXPORT GravurTextRenderer();
        DLLEXPORT GravurTextRenderer(Schrift* schrift);
        DLLEXPORT virtual ~GravurTextRenderer();
        //! Zeichnet einen Bestimmten Buchstaben mit einf�rbung auf ein Bild
        //! Nutze (setPosition) und (setDrawSchriftGr��e) um die Position und
        //! die Gr��e zu ver�ndern \param x x position des ersten zeichens
        //! \param y y position des ersten zeichens
        //! \param txt Der Text, der gezeichnet werden soll
        //! \param zRObj Das Bild, auf das gezeichnet werden soll
        //! \param color Die Farbe, in der der Text gezeichnet werden soll
        //! \param underlined 1, falls der Text unterstrichen sein soll
        //! \param selected 1, falls das zeichen eingef�rbt sein soll
        //! \param selectedBackgroundColor Die Hintergrund Farbe des
        //! eingef�rbten Textes
        DLLEXPORT virtual void renderChar(int& x,
            int y,
            char c,
            Bild& zRObj,
            int color,
            bool underlined = 0,
            bool selected = 0,
            int selectedBackgroundColor = 0) override;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten
        //! Buchstaben vollst�ndig darzustellen \param c Der Buchstabe, von dem
        //! die Breite in Pixeln ermitelt werden soll
        DLLEXPORT virtual int getCharWidth(const char c) const override;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten Text
        //! vollst�ndig darzustellen \param c Der Buchstabe, von dem die H�he in
        //! Pixeln ermitelt werden soll
        DLLEXPORT virtual int getCharHeight(const char c) const override;
    };

    class KursivTextRenderer : public TextRenderer
    {
    public:
        DLLEXPORT KursivTextRenderer();
        DLLEXPORT KursivTextRenderer(Schrift* schrift);
        DLLEXPORT virtual ~KursivTextRenderer();
        //! Zeichnet einen Bestimmten Buchstaben mit einf�rbung auf ein Bild
        //! Nutze (setPosition) und (setDrawSchriftGr��e) um die Position und
        //! die Gr��e zu ver�ndern \param x x position des ersten zeichens
        //! \param y y position des ersten zeichens
        //! \param txt Der Text, der gezeichnet werden soll
        //! \param zRObj Das Bild, auf das gezeichnet werden soll
        //! \param color Die Farbe, in der der Text gezeichnet werden soll
        //! \param underlined 1, falls der Text unterstrichen sein soll
        //! \param selected 1, falls das zeichen eingef�rbt sein soll
        //! \param selectedBackgroundColor Die Hintergrund Farbe des
        //! eingef�rbten Textes
        DLLEXPORT virtual void renderChar(int& x,
            int y,
            char c,
            Bild& zRObj,
            int color,
            bool underlined = 0,
            bool selected = 0,
            int selectedBackgroundColor = 0) override;
        //! Ermittelt, wie viele Pixel ben�tigt werden, um einen Bestimmten
        //! Buchstaben vollst�ndig darzustellen \param c Der Buchstabe, von dem
        //! die Breite in Pixeln ermitelt werden soll
        DLLEXPORT virtual int getCharWidth(const char c) const override;
    };
} // namespace Framework

#endif