#ifndef TextFeld_H
#define TextFeld_H

#include "Zeichnung.h"
#include "Array.h"

namespace Framework
{
    class Schrift; //! Schrift.h
    class Text; //! Text.h
    class AlphaFeld; //! AlphaFeld.h
    class Rahmen; //! Rahmen.h
    class TextFeld; //! aus dieser Datei
    class VScrollBar; //! Scroll.h
    class HScrollBar; //! Scroll.h
    class TextRenderer;

    //! Verwaltet ein Textfeld
    class TextFeld : public ZeichnungHintergrund
    {
    public:
        struct TextStyle
        {
            int beginIndex;
            unsigned char fontSize;
            int fontColor;
            int selectedColor;
            int selectedBackcroundColor;
            bool underlined;
            bool selected;
            int interactParam;
            unsigned char rendererIndex;
            DLLEXPORT bool operator==( const TextStyle& rhs );
        };

        class TextStyleManager : public virtual ReferenceCounter
        {
        protected:
            RCArray< TextRenderer > *renderer;
            Array< TextStyle > textStyle;
            int index;
            int styleIndex;
            TextStyle current;
            Text *text;

        public:
            DLLEXPORT TextStyleManager();
            DLLEXPORT virtual ~TextStyleManager();
            //! Setzt den Style eines Textabschnittes
            //! \param begin die startposition des Abschnittes
            //! \param end die endposition des Abschnittes (nicht enthalten)
            DLLEXPORT void setTextStyle( int begin, int end, TextStyle style );
            //! Entfernt einen Textabschnitt
            //! \param begin der index des ersten betroffenen zeichens
            //! \param end der index des ersten zeichens nach dem abschnitt
            DLLEXPORT void removeText( int begin, int end );
            //! Fügt ein Text an einer bestimmten Position ein
            //! \param pos die position des neuen Textausschnitts
            //! \param text der neue Text
            DLLEXPORT void insertText( int pos, const char *text );
            //! Entfernt nicht benötiegte gleiche styles
            DLLEXPORT void cleanupStyles();
            //! gibt eine referenz auf das style objekt zurück
            DLLEXPORT TextStyle &currentStyle();
            //! gibt den aktuellen text renderer zurück
            DLLEXPORT TextRenderer *zCurrentRenderer();
            //! ändert den inhalt des style objektes auf den style des nächsten zeichens
            //!  gibt 0 zurück falls es kein weiteres zeichen gibt
            DLLEXPORT bool nextStyle();
            //! ändert den inhalt des style objektes auf den style des angegebenen zeichens
            //! \param index der Index des Zeichens zu dem gesprungen werden soll
            //!  gibt 0 zurück falls es das zeichen nicht gibt
            DLLEXPORT bool stepTo( int index );
            //! ändert den inhalt des style objektes auf den style des ersten zeichens
            DLLEXPORT void resetIteration();
            //! Gibt den Style eines bestimmten zeichens zurück
            //! \param index Der index des Zeichens
            DLLEXPORT TextStyle getTextStyle( int index ) const;
            friend TextFeld;
        };

        class Style : public ZeichnungHintergrund::Style
        {
        public:
            const static __int64 Mehrzeilig = 0x001000; //! Wenn dieser Flag nicht gesetzt wird, werden alle Zeilenumbrüche automatisch aus dem Text entfernt
            const static __int64 HCenter = 0x002000; //! Wenn dieser Flag gesetzt wird, wird der Text genau in der horizontaen Mitte des Feldes plaziert
            const static __int64 VCenter = 0x004000; //! Wenn dieser Flag gesetzt wird, wird der Text genau in der vertikalen Mitte des Feldes plaziert
            const static __int64 Editierbar = 0x2000000; //! Wenn dieser Flag gesetzt wird, kann der Text durch den Nutzer bearbeitet werden
            
            const static __int64 Center = HCenter | VCenter; //! Vereint die Flags HCenter und VCenter
            const static __int64 TextFeld = Sichtbar | Erlaubt | Rahmen | Buffered | VCenter | Editierbar; //! Vereint die Flags Sichtbar, Erlaubt, Rahmen, Buffered, VCenter
            const static __int64 Text = Sichtbar | Mehrzeilig | Erlaubt; //! Vereint die Flags Sichtbar, Mehrfarbig, Mehrzeilig
            const static __int64 TextGebiet = Sichtbar | Erlaubt | Rahmen | Hintergrund | Editierbar | Mehrzeilig | VScroll; //! Vereint die Flags Sichtbar, Erlaubt, Rahmen, Hintergrund, Mehrzeilig, Mehrfarbig, VScroll
            const static __int64 Scroll = VScroll | HScroll; //! Vereint die Flags VScroll und HScroll
        };
    private:
        TextStyleManager *tm;
        unsigned char showChar;
        int cpos;
        double tickVal;
        bool mausKlick;
        std::function< void( int, int, MausEreignis me ) > charEvent;

        int getTextHeight() const;
        int getTextWidth() const;
        //! Verarbeitet Maus Nachrichten
        //! \param me Das Ereignis, was durch die Mauseingabe ausgelößt wurde
        DLLEXPORT virtual void doMausEreignis( MausEreignis &me, bool userRet ) override;

    public:
        //! Konstruktor 
        DLLEXPORT TextFeld();
        //! Destruktor 
        DLLEXPORT virtual ~TextFeld();
        //! charEvent: eine funktion die aufgerufen wird, wenn sich die maus auf einem bestimmten zeichen befindet und der interactParam im style != 0 ist
        //! \param aufruf charEvent( charIndex, interactParam, mausEreignis );
        DLLEXPORT void setCharEvent( std::function< void( int, int, MausEreignis me ) > charEvent );
        //! setzt einen Zeiger auf den Text im Textfeld
        //! \param txt Der Zeiger auf den Text
        DLLEXPORT void setTextZ( Text *txt );
        //! setzt den Text des Textfeldes
        //! \param txt der Text
        DLLEXPORT void setText( Text *txt );
        //! setzt den Text des Textfeldes
        //! \param txt der Text
        DLLEXPORT void setText( const char *txt );
        //! setzt den Text mit styles
        //! \param txt der Text
        //! \param format 
        //!               - \\x1: aktiviert unterschtrich
        //!               - \\x2\\xY: setzt die schriftgröße auf y für den folgenden text
        //!               - \\x3\\xA\\xR\\xG\\xB: setzt die schriftfarbe auf ARGB
        //!               - \\x4\\xA\\xR\\xG\\xB: setzt die farbe des ausgewählten textes
        //!               - \\x5\\xA\\xR\\xG\\xB: setzt die hintergrundfarbe des ausgewählten textes
        //!               - \\x6\\xY: setzt text renderer index auf y
        //!               - \\x7: deaktiviert unterschtrich
        //!               - \\x8\\xA\\xB\\xC\\xD: set interact param to ABCD
        DLLEXPORT void setFormattedText( const char *txt );
        //! fügt zeilenumbrüche so ein, dass der text nicht die breite des textfeldes überschreitet
        //! \param spacing ein text, der direkt nach jedem eingefügten Zeilenumbruch eingefügt wird
        DLLEXPORT void addLineBreaks( const char *spacing = "" );
        //! Setzt den Style eines Textabschnittes
        //! \param begin die startposition des Abschnittes
        //! \param end die endposition des Abschnittes (nicht enthalten)
        DLLEXPORT void setTextStyle( int begin, int end, TextStyle style );
        //! Fügt eine Zeile an den Text an
        //! \param zeile Die neue Zeile
        DLLEXPORT void addZeile( const char *zeile );
        //! Fügt eine Zeile an den Text an
        //! \param zeile Die neue Zeile
        //! \param color Die Farbe der Zeile
        DLLEXPORT void addZeile( const char *zeile, int color );
        //! Deselectiert alle textabschnitte
        DLLEXPORT void deselectAuswahl();
        //! Setzt den ausgewählten textabschnitt fest
        //!  pos1: Die Cursorposition im Text
        //!  pos2: Die Position im Text, bis zu der der Text eingefärbt werden soll
        DLLEXPORT void setAuswahl( int pos1, int pos2 );
        //! Setzt den ausgewählten textabschnitt fest
        //! \param auswahl Ein punkt mit x als Cursorposition und y als der Position, bis zu der der Text eingefärbt werden soll
        DLLEXPORT void setAuswahl( Punkt &auswahl );
        //! Setzt den ausgewählten textabschnitt fest
        //!  pos1: Die Cursorposition im Text
        //!  pos2: Die Position im Text, bis zu der der Text eingefärbt werden soll
        DLLEXPORT void addAuswahl( int pos1, int pos2 );
        //! Setzt den ausgewählten textabschnitt fest
        //! \param auswahl Ein punkt mit x als Cursorposition und y als der Position, bis zu der der Text eingefärbt werden soll
        DLLEXPORT void addAuswahl( Punkt &auswahl );
        //! Setzt den ausgewählten textabschnitt fest
        //! \param begin Die Cursorposition im Text
        //! \param end Die Position im Text, bis zu der der Text eingefärbt werden soll
        DLLEXPORT void invertAuswahl( int begin, int end );
        //! ersetzt alle ausgewählten Textabschnitte mit einem text
        //! \param text der neue Text
        DLLEXPORT void replaceAuswahl( const char *text );
        //! Setzt den verwendeten TextRenderer
        //! \param textRd Der Textrenderer
        DLLEXPORT void setTextRendererZ( TextRenderer *textRd );
        //! Fügt einen TextRenderer hinzu
        //! \param textRd Der Textrenderer
        DLLEXPORT void addTextRendererZ( TextRenderer *textRd );
        //! Setzt die verwendeten TextRenderer
        //! \param textRd Die Textrenderer
        DLLEXPORT void setTextRendererZ( RCArray< TextRenderer > *textRd );
        //! Setzt einen Zeiger zur Schrift
        //! \param schrift Die Schrift, die zum Textzeichnen verwendet werden soll.
        DLLEXPORT void setSchriftZ( Schrift *schrift );
        //! Setzt einen Zeiger zur Schrift
        //! \param rendererIndex Der Index des Renderers dessen Schrift gesetzt werden soll
        //! \param schrift Die Schrift, die zum Textzeichnen verwendet werden soll.
        DLLEXPORT void setSchriftZ( int rendererIndex, Schrift *schrift );
        //! Setzt die Schriftgröße (Standart: 12)
        //! \param gr Die Schriftgröße, die zum Textzeichnen verwendet werden soll
        DLLEXPORT void setSchriftSize( unsigned char gr );
        //! Setzt die Schriftgröße (Standart: 12)
        //! \param begin Der Index des ersten betroffenen Zeichens
        //! \param end Der Index des ersten nicht betroffenen Zeichens
        //! \param gr Die Schriftgröße, die zum Textzeichnen verwendet werden soll
        DLLEXPORT void setSchriftSize( int begin, int end, unsigned char gr );
        //! Setzt die Schrift Farbe
        //! \param fc Die Farbe, die zum Textzeichnen verwendet werden soll
        DLLEXPORT void setSchriftFarbe( int fc );
        //! Setzt die Schrift Farbe
        //! \param begin Der Index des ersten betroffenen Zeichens
        //! \param end Der Index des ersten nicht betroffenen Zeichens
        //! \param fc Die Farbe, die zum Textzeichnen verwendet werden soll
        DLLEXPORT void setSchriftFarbe( int begin, int end, int fc );
        //! Legt einen Buchstaben fest, der zum zeichnen verwendet werden soll, unabhängig vom Text des Textfeldes (benötigt Flag zum Zeichnen: Rahmen)
        //! \param c Der Buchstabe, der gezeichnet werden soll
        //! Beispiel: setShowChar( '*' ); Bei Passwort Textfeldern
        DLLEXPORT void setSchowChar( unsigned char c );
        //! Scrollt zu einer bestimmten Zeile (benötigt Flag zum Zeichnen: VScroll)
        //! \param zeile Der Index der Zeile, die als oberste Zeile zu sehen sein soll
        DLLEXPORT void setVScrollZuZeile( int zeile );
        //! Scrollt zu einer bestimmten Position im Text. Ohne den Flag Erlaubt wrd immer ganz nach unten gescrollt. (benötigt Flag zum Zeichnen: VScroll)
        //! \param pos Der Index des Zeichens, zu dem gescrollt werden soll. Standartmäßig wird zur Cursorposition gescrollt
        DLLEXPORT void updateVScroll( int pos = -1 );
        //! Scrollt zu einer bestimmten Position im Text. Benötigt den Flag Erlaubt. (benötigt Flag zum Zeichnen: HScroll)
        //! \param pos Der Index des Zeichens, zu dem gescrollt werden soll. Standartmäßig wird zur Cursorposition gescrollt
        DLLEXPORT void updateHScroll( int pos = -1 );
        //! Gibt die breite in pixeln zurück, die benötigt wird um den aktuellen text mit den aktuellen styles voll anzuzeigen
        DLLEXPORT int getNeededWidth();
        //! Gibt die höhe in pixeln zurück, die benötigt wird um den aktuellen text mit den aktuellen styles voll anzuzeigen
        DLLEXPORT int getNeededHeight();
        //! Aktualisiert das Objekt. Wird vom Framework aufgerufen
        //! \param tickVal Die Zeit in sekunden, die seit dem lezten Aufruf dieser Funktion vergangen ist
        //! \return 1, wenn sich etwas verändert hat und das Bild neu gezeichnet werden muss. 0 sonst
        DLLEXPORT virtual bool tick( double tickval ) override;
        //! Verarbeitet Tastatur Nachrichten
        //! \param me Das Ereignis, was durch die Tastatureingabe ausgelößt wurde
        DLLEXPORT void doTastaturEreignis( TastaturEreignis &te ) override;
        //! Zeichnet das Objekt nach zRObj, falls es sichtbar ist
        //! \param zRObj Das Bild, in welches gezeichnet werden soll
        DLLEXPORT virtual void render( Bild &zRObj ) override;
        //! Gibt den Text aus dem Textfeld zurück
        DLLEXPORT Text *getText() const;
        //! Gibt den Text aus dem Textfeld ohne erhöhten Reference Counter zurück
        DLLEXPORT Text *zText() const;
        //! Gibt die Schrift zurück.
        //! \return 0, falls die Schrift nicht gesetzt wurde
        DLLEXPORT Schrift *getSchrift() const;
        //! Gibt die Schrift ohne erhöhten Reference Counter zurük
        //! \return 0, falls die Schrift nicht gesetzt wurde
        DLLEXPORT Schrift *zSchrift() const;
        //! Gibt die Schrift zurück.
        //! \param rendererIndex Der Index des Renderers dessen Schrift zurückgegeben werden soll
        //! \return 0, falls die Schrift nicht gesetzt wurde
        DLLEXPORT Schrift *getSchrift( int rendererIndex ) const;
        //! Gibt die Schrift ohne erhöhten Reference Counter zurük
        //! \param rendererIndex Der Index des Renderers dessen Schrift zurückgegeben werden soll
        //! \return 0, falls die Schrift nicht gesetzt wurde
        DLLEXPORT Schrift *zSchrift( int rendererIndex ) const;
        //! Gibt den TextRenderer zurück.
        //! \return 0, falls der TextRenderer nicht gesetzt wurde
        DLLEXPORT TextRenderer *getTextRenderer() const;
        //! Gibt dien TextRenderer ohne erhöhten Reference Counter zurük
        //! \return 0, falls der TextRenderer nicht gesetzt wurde
        DLLEXPORT TextRenderer *zTextRenderer() const;
        //! Gibt den TextRenderer zurück.
        //! \param index Der Index des Renderers der zurückgegeben werden soll
        //! \return 0, falls der TextRenderer nicht gesetzt wurde
        DLLEXPORT TextRenderer *getTextRenderer( int index ) const;
        //! Gibt dien TextRenderer ohne erhöhten Reference Counter zurük
        //! \param index Der Index des Renderers der zurückgegeben werden soll
        //! \return 0, falls der TextRenderer nicht gesetzt wurde
        DLLEXPORT TextRenderer *zTextRenderer( int index ) const;
        //! Gibt die Schriftgröße zurück
        DLLEXPORT unsigned char getSchriftSize() const;
        //! Gibt die Schriftgröße zurück
        //! \param index Der Index des Zeichens
        DLLEXPORT unsigned char getSchriftSize( int index ) const;
        //! Gibt die Schriftfarbe im A8R8G8B8 Format zurück
        DLLEXPORT int getSchriftFarbe() const;
        //! Gibt die Schriftfarbe im A8R8G8B8 Format zurück
        //! \param index Der Index des Zeichens
        DLLEXPORT int getSchriftFarbe( int index ) const;
        //! Gibt den Anzeigebuchstabe zurück
        DLLEXPORT unsigned char getShowChar() const;
        //! Gibt die Cursorposition zurück
        DLLEXPORT int getCursorPos() const;
        //! Gibt 1 zurück wenn das Zeichen ausgewählt ist
        //! \param index Der Index des Zeichens
        DLLEXPORT bool isCharSelected( int index ) const;
        //! Gibt den Index des Zeichens zurück, das sich unter der Maus befindet
        //! \param mx die x position der maus relativ zur position des textfeldes
        //! \param my die y position der maus relativ zut position des textfeldes
        //! \return -1, falls sich an der Position kein zeichen befindet
        DLLEXPORT int getTextIndexAt( int mx, int my ) const;
        //! Gibt den Index des Zeichens zurück, vor dem der curser gesetzt wird, wenn mit der maus geklickt wird
        //! \param mx die x position der maus relativ zur position des textfeldes
        //! \param my die y position der maus relativ zut position des textfeldes
        DLLEXPORT int getCurserPosAt( int mx, int my ) const;
        //! Gibt den Style eines bestimmten zeichens zurück
        //! \param index Der index des Zeichensf
        DLLEXPORT TextStyle getTextStyle( int index ) const;
        //! Erzeugt eine Komplette Kopie des Textfeldes, welches ohne auswirkungen verändert werden kann
        DLLEXPORT Zeichnung *dublizieren() const override;
    };
}
#endif