#ifndef Schrift_H
#define Schrift_H

#include "Critical.h"
#include "Punkt.h"
#include "ReferenceCounter.h"
#include <functional>

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:
        AlphabetArray *next;
        Alphabet *This;

    public:
        //! Erzeugt eine neue Liste
        DLLEXPORT AlphabetArray();
        //! Löscht eine 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( int sg );
        //! Setzt den Zeiger auf das nächste Element der Liste auf 0
        DLLEXPORT void setNext0();

        //! 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 ein bestimmtes Alphabet mit erhöhtem Reference Counter zurück
        //! \param index Der Index des gesuchten Alphabets in der Reihenfolge wie sie der Liste hinzugefügt wurden
        //! \param count Hier sollte 0 übergeben werden. Gibt an auf dem wievielten Element der Liste die Funktion aufgerufen wird.
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet *getAlphabetI( int index, int count ) const;
        //! Gibt ein bestimmtes Alphabet ohne erhöhtem Reference Counter zurück
        //! \param index Der Index des gesuchten Alphabets in der Reihenfolge wie sie der Liste hinzugefügt wurden
        //! \param count Hier sollte 0 übergeben werden. Gibt an auf dem wievielten Element der Liste die Funktion aufgerufen wird.
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet *zAlphabetI( int index, int count ) const;
        //! Gibt einen Zeiger auf das nächste Element der Liste zurück
        DLLEXPORT AlphabetArray *getNext() 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( int 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( int 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( int sg ) const;
        //! Gibt ein bestimmtes Alphabet mit erhöhtem Reference Counter zurück
        //! \param index Der Index des gesuchten Alphabets in der Reihenfolge wie sie der Liste hinzugefügt wurden
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet *getAlphabetI( int index ) const;
        //! Gibt ein bestimmtes Alphabet ohne erhöhtem Reference Counter zurück
        //! \param index Der Index des gesuchten Alphabets in der Reihenfolge wie sie der Liste hinzugefügt wurden
        //! \return (0), fals kein passendes Alphabet gefunden wurde
        DLLEXPORT Alphabet *zAlphabetI( int index ) 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;

    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;
        //! Gibt den Abstand in Pixeln zum unteren Ende der darüber ligenden Zeile zurück
        DLLEXPORT int getZeilenabstand() 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 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 );
        //! 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 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;
    };

    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 );
        //! 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 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;
    };
}

#endif