#ifndef Zeichnung_H
#define Zeichnung_H

#include "Punkt.h"
#include "MausEreignis.h"
#include "TastaturEreignis.h"
#include "Critical.h"
#include "ReferenceCounter.h"
#include <queue>
#include <functional>

namespace Framework
{
    struct MausEreignis; //! MausEreignis.h
    struct TastaturEreignis; //! TastaturEreignis.h
    class Bild; //! Bild.h
    class Zeichnung; //! Aus dieser Datei
    class ToolTip; //! ToopTip.h
    class Bildschirm; //! Bildschirm.h
    class Rahmen; //! Rahmen.h
    class AlphaFeld; //! AlphaFeld.h
    class VScrollBar; //! Scroll.h
    class HScrollBar; //! Scroll.h
    class Schrift;

    //! Eine Zeichnung für das 2D GUI Framework
    class Zeichnung : public virtual ReferenceCounter
    {
    public:
        class Style
        {
        public:
            //! Wenn dieser Style gesetzt ist, wird die Zeichnung beim Zeichnen angezeigt
            const static __int64 Sichtbar = 0x00001;
            //! Wenn dieser Style gesetzt ist, kann der Benutzer mit der Zeichnung interagieren
            const static __int64 Erlaubt = 0x00002;
            //! Wenn dieser Style gesetzt ist, wird ein TastaturEreignis von der Zeichnung verarbeitet
            const static __int64 Fokus = 0x00004;
            //! Wenn dieser Style gesetzt ist, wird ein MausEreignis auch verarbeitet, wenn das Objekt nicht sichtbar ist
            const static __int64 MEIgnoreSichtbar = 0x0800000000000000;
            //! Wenn dieser Style gesetzt ist, lockt der Thread das Objekt während das MausEreignis verarbeitet wird
            const static __int64 MELockZeichnung = 0x1000000000000000;
            //! Wenn dieser Style gesetzt ist, wird ein MausEreignis auch verarbeitet, wenn es außerhalb der Zeichnung liegt
            const static __int64 MEIgnoreInside = 0x2000000000000000;
            //! Wenn dieser Style gesetzt ist, wird ein MausEreignis auch verarbeitet, wenn es bereits von einer anderen Zeichnung verarbeitet wurde
            const static __int64 MEIgnoreVerarbeitet = 0x4000000000000000;
            //! Wenn dieser Style gesetzt ist, wird ein MausEreignis auch verarbeitet, wenn es sich außerhalb der Zeichnung befindet, zu der diese Zeichnung gehört
            const static __int64 MEIgnoreParentInside = 0x8000000000000000;
        };
    protected:
        Punkt pos;
        Punkt gr;
        void *makParam;
        void *takParam;
        MausAktion mak;
        TastaturAktion tak;
        void *nmakParam;
        void *ntakParam;
        MausAktion nMak;
        TastaturAktion nTak;
        bool mausIn;
        Critical cs;
        ToolTip *toolTip;
        __int64 style;
        bool rend;
        std::queue< std::function< void() > > actions;
        std::function< void( Zeichnung * ) > onNeedToolTip;

        //! Verarbeitet ein Maus Ereignis. Wird vom Framework automatisch aufgerufen.
        //! \param me Das MausEreignis
        //! \param userRet true wenn MausEreignis::verarbeitet auf true gesetzt werden soll
        DLLEXPORT virtual void doMausEreignis( MausEreignis &me, bool userRet );

    public:
        //! Konstruktor 
        DLLEXPORT Zeichnung();
        //! Destruktor 
        DLLEXPORT virtual ~Zeichnung();
        //! Übergibt einen void Funktionszeiger auf eine Aktion die einmalig vom Hauptthread ausgeführt werden soll. Wird am ende von tick() aufgerufen
        DLLEXPORT void postAction( std::function< void() > action );
        //! Legt fest, ob sich die Zeichnung seit des letzten Bildes verändert hat und neu gezeichnet werden muss
        DLLEXPORT void setRender();
        //! Setzt den Text, der erscheint, wenn der Benutzer für längere Zeit mit der Maus in der Zeichnung verweilt
        //! \param txt Der Text, der angezeigt werden soll
        //! \param zScreen Ein Zeiger auf das Verwendete Bildschirm Objekt ohne erhöhten Reference Counter
        //! \param zSchrift Ein Zeiger auf die Schrift, die verwendet werden soll ohne erhöhten Reference Counter
        DLLEXPORT void setToolTipText( const char *txt, Bildschirm *zScreen, Schrift *zSchrift );
        //! setzt eine Funktion, die aufgerufen wird, falls ein Tooltip benötigt wird und noch keiner gesetzt wurde
        //! \param initToolTip die Funktion
        DLLEXPORT void setNeedToolTipEvent( std::function< void( Zeichnung * ) > onNeedTooltip );
        //! legt den tooltip fest
        //! \param tt der tooltip
        DLLEXPORT void setToolTipZ( ToolTip *tt );
        //! Dies ist notwendig, falls mehrere Threads gleichzeitig die Zeichnung benutzen.
        //! Wenn lockZeichnung() von zwei threads aufgerufen wird, wartet der letzte so lange, bis der erste unlockZeichnung() aufgerufen hat.
        DLLEXPORT void lockZeichnung();
        //! Dies ist notwendig, falls mehrere Threads gleichzeitig die Zeichnung benutzen.
        //! Wenn lockZeichnung() von zwei threads aufgerufen wird, wartet der letzte so lange, bis der erste unlockZeichnung() aufgerufen hat.
        DLLEXPORT void unlockZeichnung();
        //! setzt den Parameter, der bei einem Maus Ereignis an die Rückruffunktion übergeben wird
        //! \param p Der Parameter
        DLLEXPORT void setMausEreignisParameter( void *p );
        //! Setzt den Parameter, der bei einem Tastatur Ereignis an die Rückruffunktion übergeben wird
        //! \param p Der Parameter
        DLLEXPORT void setTastaturEreignisParameter( void *p );
        //! Setzt die Rückruffunktion, die bei einem Maus Ereignis aufgerufen werden soll.
        //! Wenn die Rückruffunktion 0 zurückgiebt, oder nicht gesetzt wurde, wird ein Maus Ereignis von der Zeichnung nicht weiter beachtet
        //! Es kann die Standartfunktion __ret1ME verwendet werden, die in MausEreignis.h definiert ist und immer 1 zurückgibt
        //! \param ak Ein Zeiger auf die Rückruffunktion
        DLLEXPORT void setMausEreignis( MausAktion ak );
        //! Setzt die Rückruffunktion, die bei einem Tastatur Ereignis aufgerufen werdne soll.
        //! Wenn die Rückruffunktion 0 zurückgiebt, oder nicht gesetzt wurde, wird ein Tastatur Ereignis von der Zeichnung nicht weiter beachtet
        //! Es kann die Standartfunktion __ret1TE verwendet werden, die in TastaturEreignis.h definiert ist und immer 1 zurückgibt
        //! Weitere Standartfunktionen sind _nurNummernTE und _nurHexTE ebenfals aus TastaturEreignis.h
        //! \param ak Ein Zeiger auf die Rückruffunktion
        DLLEXPORT void setTastaturEreignis( TastaturAktion ak );
        //! setzt den Parameter, der bei einem Maus Ereignis an die Rückruffunktion übergeben wird, die aufgerufen wird, fals das Ereignis von der Zeichnung verarbeitet wurde
        //! \param p Der Parameter
        DLLEXPORT void setNMausEreignisParameter( void *p );
        //! Setzt den Parameter, der bei einem Tastatur Ereignis an die Rückruffunktion übergeben wird, die aufgerufen wird, fals das Ereignis von der Zeichnung verarbeitet wurde
        //! \param p Der Parameter
        DLLEXPORT void setNTastaturEreignisParameter( void *p );
        //! Setzt die Rückruffunktion, die bei einem Maus Ereignis aufgerufen werden soll, nachdem das Ereignis bereits von der Zeichnung verarbeitet wurde
        //! Wenn die Rückruffunktion 1 zurückgiebt, oder nicht gesetzt wurde, wird das Maus Ereignis von keiner weiteren Zeichnung verarbeitet, die zum Beispiel hinter dieser Zeichnung liegen
        //! Es kann die Standartfunktion __ret1ME verwendet werden, die in MausEreignis.h definiert ist und immer 1 zurückgibt
        //! \param ak Ein Zeiger auf die Rückruffunktion
        DLLEXPORT void setNMausEreignis( MausAktion ak );
        //! Setzt die Rückruffunktion, die bei einem Tastatur Ereignis aufgerufen werdne soll, nachdem das Ereignis bereits von der Zeichnung verarbeitet wurde
        //! Wenn die Rückruffunktion 1 zurückgiebt, oder nicht gesetzt wurde, wird das Tastatur Ereignis von keiner weiteren Zeichnung verarbeitet
        //! Es kann die Standartfunktion __ret1TE verwendet werden, die in TastaturEreignis.h definiert ist und immer 1 zurückgibt
        //! Weitere Standartfunktionen sind _nurNummernTE und _nurHexTE ebenfals aus TastaturEreignis.h
        //! \param ak Ein Zeiger auf die Rückruffunktion
        DLLEXPORT void setNTastaturEreignis( TastaturAktion ak );
        //! Verarbeitet ein Maus Ereignis. Wird vom Framework automatisch aufgerufen.
        //! \param me Das Ereignis
        DLLEXPORT virtual void doPublicMausEreignis( MausEreignis &me );
        //! Verarbeitet ein Tastatur Ereignis. Wird vom Framework automatisch aufgerufen
        //! \param te Das Ereignis
        DLLEXPORT virtual void doTastaturEreignis( TastaturEreignis &te );
        //! Verarbeitet die Zeit, die seit dem letzten aufruf dieser Funktion vergangen ist
        //! \param tickVal Die vergangene Zeit in Sekunden
        DLLEXPORT virtual bool tick( double tickval );
        //! Setzt die Position der Zeichnung
        //! \param pos Die Position in Pixeln
        DLLEXPORT void setPosition( const Punkt &pos );
        //! Setzt die X Position der Zeichnung
        //! \param xPos Die Position in Pixeln
        DLLEXPORT void setX( int xPos );
        //! Setzt die Y Position der Zeichnung
        //! \param yPos Die Position in Pixeln
        DLLEXPORT void setY( int yPos );
        //! Setzt die Größe der Zeichnung
        //! \param gr Ein Punkt mit x als Breite und y als Höhe in Pixeln
        DLLEXPORT void setSize( const Punkt &gr );
        //! Setzt die Position der Zeichnung
        //! \param x Die X Position in Pixeln
        //! \param y Die Y Position in Pixeln
        DLLEXPORT void setPosition( int x, int y );
        //! Setzt die Größe der Zeichnung
        //! \param br Die Breite in Pixeln
        //! \param height Die Höhe in Pixeln
        DLLEXPORT void setSize( int br, int height );
        //! Setzt den Style der Zeichnung
        //! \param style Der neue Style bestehend aus den Flags aus der zugehörigen Style Klasse
        DLLEXPORT void setStyle( __int64 style );
        //! Setzt den Style der Zeichnung
        //! \param style Alle Style Flags, die verändert werden sollen
        //! \param add_remove 1, falls der Style hinzugefügt werden soll. 0, falls der Style entfernt weden soll
        DLLEXPORT void setStyle( __int64 style, bool add_remove );
        //! Fügt Style Flags hinzu
        //! \param style Der Style, der hinzugefügt werden soll
        DLLEXPORT void addStyle( __int64 style );
        //! Entfernt Style Flags
        //! \param style Der Style, der entfernt werden soll
        DLLEXPORT void removeStyle( __int64 style );
        //! Zeichnet die Zeihnung in ein bestimmtes Bild
        //! \param zRObj Das Bild, in das gezeichnet werden soll
        DLLEXPORT virtual void render( Bild &zRObj );
        //! Gibt zurück, ob eine Rückruffunktion für Maus Ereignisse gesetzt wurde
        DLLEXPORT bool hatMausEreignis() const;
        //! Gibt zurück, ob eine Rückruffunktion für Tastatur Ereignisse gesetzt wurde
        DLLEXPORT bool hatTastaturEreignis() const;
        //! Gibt die Position der Zeichnung in Pixeln zurück
        DLLEXPORT const Punkt &getPosition() const;
        //! Gibt die Größe der Zeichnung in Pixeln zurück. x für Breite und y für Höhe
        DLLEXPORT const Punkt &getSize() const;
        //! Gibt die Breite der Zeichnung in Pixeln zurück
        DLLEXPORT int getBreite() const;
        //! Gibt die Höhe der Zeichnung in Pixeln zurück
        DLLEXPORT int getHeight() const;
        //! Gibt die Breite des Innenraumes in der Zeichnung in Pixeln zurück
        DLLEXPORT virtual int getInnenBreite() const;
        //! Gibt die Höhe des Innenraumes in der Zeichnung in Pixeln zurück
        DLLEXPORT virtual int getInnenHeight() const;
        //! Gibt die X Position der Zeichnung in Pixeln zurück
        DLLEXPORT int getX() const;
        //! Gibt die Y Position der Zeichnung in Pixeln zurück
        DLLEXPORT int getY() const;
        //! Prüft, ob ein Punkt in diesem Objekt liegt
        //! \param p der Punkt
        //! \return 1, wenn der punkt innen ist, 0 sonst
        DLLEXPORT virtual bool istPunktInnen( Punkt p ) const;
        //! Prüft, ob ein Punkt in diesem Objekt liegt
        //! \param x die x koordinate des punktes
        //! \param y die y koordinate des punktes
        //! \return 1, wenn der punkt innen ist, 0 sonst
        DLLEXPORT virtual bool istPunktInnen( int x, int y ) const;
        //! Gibt einen Zeiger auf das Tooltip Objekt zurück, walls es verwendet wird
        DLLEXPORT ToolTip *getToolTip() const;
        //! Gibt einen Zeiger auf das Tooltip Objekt ohne erhöhten Reference Counter zurück, walls es verwendet wird
        DLLEXPORT ToolTip *zToolTip() const;
        //! Gibt zurück, ob bestimmte Styles gesetzt wurden
        //! \param style Die Styles, die überprüft werden sollen
        //! \return 1, falls alle Styles in style gesetzt wurden
        DLLEXPORT bool hatStyle( __int64 style ) const;
        //! Gibt zurück, ob bestimmte Styles nicht gesetzt wurden
        //! \param style Die Styles, die geprüft werden sollen
        //! \return 1, falls alle Styles in style nicht gesetzt wurden
        DLLEXPORT bool hatStyleNicht( __int64 style ) const;
        //! Kopiert die Komplette Zeichnung, so dass sie ohne Effekt auf das Original verändert werden kann
        DLLEXPORT virtual Zeichnung *dublizieren() const;
    };

    //! Eine Zeichnung für das 2D GUI Framework mit Hintergrund, Rahmen und Scroll Balken
    class ZeichnungHintergrund : public Zeichnung
    {
    public:
        class Style : public Zeichnung::Style
        {
        public:
            const static __int64 Rahmen = 0x00010; //! Wenn dieser Flag gesetzt wird, bekommt die Zeichnugn einen Rahmen
            const static __int64 Hintergrund = 0x00020; //! Wenn dieser Flag gesetzt wird, bekommt die Zeichnung einen Hintergrund
            const static __int64 HAlpha = 0x00040; //! Wenn dieser Flag gesetzt wird, wird der Hintergrund durchsichtig. Benötigt Flag Hintergrund
            const static __int64 HBild = 0x00080; //! Wenn dieser Flag gesetzt wird, wird ein Bild als hintergrund verwendet. Benötigt Flag Hintergrund
            const static __int64 Buffered = 0x00100; //! Wenn dieser Flag gesetzt wird, Erscheint ein Farbübergang als Rahmen
            const static __int64 VScroll = 0x00200; //! Wenn dieser Flag gesetzt wird, erscheint eine Scrollbar am rechten Rand
            const static __int64 HScroll = 0x00400; //! Wenn dieser Flag gesetzt wird, erscheint eine Scrollbar am unteren Rand
        };

    protected:
        int hintergrundFarbe;
        Rahmen *rahmen;
        Bild *hintergrundBild;
        AlphaFeld *hintergrundFeld;
        VScrollBar *vertikalScrollBar;
        HScrollBar *horizontalScrollBar;
        Punkt innenPosition;
        Punkt innenSize;

    public:
        //! Konstruktor 
        DLLEXPORT ZeichnungHintergrund();
        //! Destruktor 
        DLLEXPORT virtual ~ZeichnungHintergrund();
        //! Setzt das Hintergrund Bild (benötigt Flag zum Zeichnen: Style::Hintergrund, HBild)
        //! \param bild Das Bild wird kopiert und als Hintergrundbild verwendet
        DLLEXPORT void setHintergrundBild( Bild *bild );
        //! Setzt einen Zeiger auf das Hintergrund Bild (benötigt Flag zum Zeichnen: Style::Hintergrund)
        //! \param bild Das Bild wid ohne es zu kopieren verwendet
        DLLEXPORT void setHintergrundBildZ( Bild *bild );
        //! Setzt die Hintergrund Farbe (benötigt Flag zum Zeichnen: Style::Hintergrund)
        //! \param fc Die Hintergrundfarbe im A8R8G8B8 Format
        DLLEXPORT void setHintergrundFarbe( int fc );
        //! Setzt einen Zeiger auf das AlphaFeld (benötigt Flag zum Zeichnen: Style::Buffered)
        //! \param buff Das AlphaFeld, das über den Hintergrund gezeichnet werden soll
        DLLEXPORT void setAlphaFeldZ( AlphaFeld *buff );
        //! Setzt die Stärke des AlphaFeldes (benötigt Flag zum Zeichnen: Style::Buffered)
        //! \param st Die Stärke des AlphaFeldes, welches über dem Hintergrund gezeichnet werden soll
        DLLEXPORT void setAlphaFeldStrength( int st );
        //! Setzt die Farbe des AlphaFeldes (benötigt Flag zum Zeichnen: Style::Buffered)
        //! \param fc Die Farbe des AlphaFeldes, welches über dem Hintergrund gezeichnet werden soll
        DLLEXPORT void setAlphaFeldFarbe( int fc );
        //! Setzt einen Zeiger zu dem Linien Rahmen, der um das TextFeld gezeichnet werden soll (benötigt Flag zum Zeichnen: Style::Rahmen)
        //! \param ram Der Rahmen
        DLLEXPORT void setRahmenZ( Rahmen *ram );
        //! Setzt die Breite des Linien Rahmens (benötigt Flag zum Zeichnen: Style::Rahmen)
        //! \param br Die Breite in Pixeln
        DLLEXPORT void setRahmenBreite( int br );
        //! Setzt die Farbe des Linien Rahmens (benötigt Flag zum Zeichnen: Style::Rahmen)
        //! \param fc Die Farbe im A8R8G8B8 Format
        DLLEXPORT void setRahmenFarbe( int fc );
        //! Setzt die Scrollgeschwindigkeit der vertikalen ScrollBar (benötigt Flag zum Zeichnen: Style::VScroll)
        //! \param ks Die Scrollgeschwindigkeit in Pixeln für jeden Maus Klick
        DLLEXPORT void setVertikalKlickScroll( int ks );
        //! Scrollt an eine Bestimmte Stelle bei der vertikalen ScrollBar (benötigt Flag zum Zeichnen: Style::VScroll)
        //! \param pos Das Scroll Offset in Pixeln.
        DLLEXPORT void setVertikalScrollPos( int pos );
        //! Setzt die Farbe der vertikalen ScrollBar (benötigt Flag zum Zeichnen: Style::VScroll)
        //! \param f Die Fordergrundfarbe der ScrollBar im A8R8G8B8 Format
        //! \param bgF Die Hintergrundfarbe der ScrollBar im A8R8G8B8 Format
        DLLEXPORT void setVertikalScrollFarbe( int f, int bgF );
        //! Setzt die Scrollgeschwindigkeit der horizontalen ScrollBar (benötigt Flag zum Zeichnen: Style::HScroll)
        //! \param ks Die Scrollgeschwindigkeit in Pixeln für jeden Maus Klick
        DLLEXPORT void setHorizontalKlickScroll( int ks );
        //! Scrollt an eine Bestimmte Stelle bei der horizontalen ScrollBar (benötigt Flag zum Zeichnen: Style::HScroll)
        //! \param pos Das Scroll Offset in Pixeln.
        DLLEXPORT void setHorizontalScrollPos( int pos );
        //! Setzt die Farbe der horizontalen ScrollBar (benötigt Flag zum Zeichnen: Style::HScroll)
        //! \param f Die Fordergrundfarbe der ScrollBar im A8R8G8B8 Format
        //! \param bgF Die Hintergrundfarbe der ScrollBar im A8R8G8B8 Format
        DLLEXPORT void setHorizontalScrollFarbe( int f, int bgF );
        //! Updated den Zeichenhintergrund
        //! \param tickVal Die vergangene Zeit in Sekunden, die seit dem Letzten Aufruf dieser Funktion verstrichen ist
        //! \return 1, wenn das Bild neu gezeichnet werden muss. 0 sonnst
        DLLEXPORT bool tick( double tickVal ) override;
        //! Zeichnet den Hintergrund eines Zeichnunges nach rObj
        DLLEXPORT void render( Bild &rObj ) override;

        //! Gibt die Breite des Innenraumes in der Zeichnung in Pixeln zurück
        DLLEXPORT virtual int getInnenBreite() const override;
        //! Gibt die Höhe des Innenraumes in der Zeichnung in Pixeln zurück
        DLLEXPORT virtual int getInnenHeight() const override;
        //! Gibt das Hintergrundbild zurück.
        //! \return 0, falls kein Hintergrundbild verwendet wird
        DLLEXPORT Bild *getHintergrundBild() const;
        //! Gibt das Hintergrundbild ohne erhöhten reference Counter zurück.
        //! \return 0, falls kein Hintergrundbild verwendet wird
        DLLEXPORT Bild *zHintergrundBild() const;
        //! Gibt die Hintergrundfarbe im A8R8G8B8 Format zurück
        DLLEXPORT int getHintergrundFarbe() const;
        //! Gibt das AlphaFeld zurück, das über den Hintergrund gezeichnet wird.
        //! \return 0, falls das AlphaFeld nicht definiert wurde
        DLLEXPORT AlphaFeld *getAlphaFeld() const;
        //! Gibt das AlphaFeld ohne erhöhten Reference Counter zurück, das über den Hintergrund gezeichnet wird.
        //! \return 0, falls das AlphaFeld nicht definiert wurde
        DLLEXPORT AlphaFeld *zAlphaFeld() const;
        //! Git die Stärke des Alphafeldes zurück
        DLLEXPORT int getAlphaFeldStrength() const;
        //! Gibt die Farbe des Alphafedes im A8R8G8B8 Format zurück
        DLLEXPORT int getAlphaFeldFarbe() const;
        //! Gibt den Rahmen zurück
        //! \return 0, falls kein Rahmen definiert wurde
        DLLEXPORT Rahmen *getRahmen() const;
        //! Gibt den Rahmen ohne erhöhten Reference Counter zurück
        //! \return 0, falls kein Rahmen definiert wurde
        DLLEXPORT Rahmen *zRahmen() const;
        //! Gibt die Breite des Rahmens in Pixeln zurück
        DLLEXPORT int getRahmenBreite() const;
        //! Gibt die Farbe des Rahmens im A8R8G8B8 Format zurück
        DLLEXPORT int getRahmenFarbe() const;
        //! Gibt die Scroll geschwindigkeit der vertikalen Scroll Bar zurück
        DLLEXPORT int getVertikalKlickScroll() const;
        //! Gibt die Scroll Position der vertikalen Scroll Bar zurück
        DLLEXPORT int getVertikalScrollPos() const;
        //! Gibt die Farbe der vertikalen Scroll Bar im A8R8G8B8 Format zurück
        DLLEXPORT int getVertikalScrollFarbe() const;
        //! Gibt die Hintergrundfarbe der vertikalen Scroll Bar im A8R8G8B8 Format zurück
        DLLEXPORT int getVertikalScrollHintergrund() const;
        //! Gibt die Scroll geschwindigkeit der horizontalen Scroll Bar zurück
        DLLEXPORT int getHorizontalKlickScroll() const;
        //! Gibt die Scroll Position der horizontalen Scroll Bar zurück
        DLLEXPORT int getHorizontalScrollPos() const;
        //! Gibt die Farbe der horizontalen Scroll Bar im A8R8G8B8 Format zurück
        DLLEXPORT int getHorizontalScrollFarbe() const;
        //! Gibt die Hintergrundfarbe der horizontalen Scroll Bar im A8R8G8B8 Format zurück
        DLLEXPORT int getHorizontalScrollHintergrund() const;
        //! Erzeugt eine Kopie der Zeichnung, die ohne Auswirkungen auf das Original verändert werden kann
        DLLEXPORT virtual Zeichnung *dublizieren() const;
    };
}

#endif