#ifndef Zeichnung_H
#define Zeichnung_H

#include <functional>

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

namespace Framework
{
    struct MausEreignis;     //! MausEreignis.h
    struct TastaturEreignis; //! TastaturEreignis.h
    class Bild;              //! Bild.h
    class Zeichnung;         //! From this file
    class ToolTip;           //! ToolTip.h
    class Bildschirm;        //! Bildschirm.h
    class Rahmen;            //! Rahmen.h
    class AlphaFeld;         //! AlphaFeld.h
    class VScrollBar;        //! Scroll.h
    class HScrollBar;        //! Scroll.h
    class Schrift;

    //! A drawing element for the 2D GUI Framework
    class Zeichnung : public virtual ReferenceCounter
    {
    public:
        class Style
        {
        public:
            //! If this style is set, the drawing is displayed when rendered
            static const __int64 Sichtbar = 0x00001;
            //! If this style is set, the user can interact with the drawing
            static const __int64 Erlaubt = 0x00002;
            //! If this style is set, keyboard events are processed by the drawing
            static const __int64 Fokus = 0x00004;
            //! If this style is set, mouse events are processed even when
            //! the object is not visible
            static const __int64 MEIgnoreSichtbar = 0x0800000000000000;
            //! If this style is set, the thread locks the object while
            //! the mouse event is being processed
            static const __int64 MELockZeichnung = 0x1000000000000000;
            //! If this style is set, mouse events are processed even when
            //! they are outside the drawing
            static const __int64 MEIgnoreInside = 0x2000000000000000;
            //! If this style is set, mouse events are processed even when
            //! they have already been processed by another drawing
            static const __int64 MEIgnoreVerarbeitet = 0x4000000000000000;
            //! If this style is set, mouse events are processed even when
            //! they are outside the drawing to which this drawing belongs
            static const __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::function<bool(Zeichnung*, Punkt localPos)> onNeedToolTip;
        bool toolTipRequested;

        //! Processes a mouse event. Called automatically by the framework.
        //! \param me The mouse event \param userRet true if
        //! MausEreignis::verarbeitet should be set to true
        DLLEXPORT virtual void doMausEreignis(MausEreignis& me, bool userRet);

    public:
        //! Constructor
        DLLEXPORT Zeichnung();
        //! Destructor
        DLLEXPORT virtual ~Zeichnung();
        //! Specifies whether the drawing has changed since the last frame
        //! and needs to be redrawn
        DLLEXPORT void setRender();
        //! Sets the text that appears when the user hovers the mouse over
        //! the drawing for a longer time \param txt The text to display
        //! \param zScreen A pointer to the screen object without increased
        //! reference counter \param zSchrift A pointer to the font to use
        //! without increased reference counter
        DLLEXPORT void setToolTipText(
            const char* txt, Bildschirm* zScreen, Schrift* zSchrift);
        //! Sets a function called when a tooltip is needed and none has
        //! been set yet \param initToolTip The function
        DLLEXPORT void setNeedToolTipEvent(
            std::function<bool(Zeichnung*, Punkt localPos)> onNeedTooltip);
        //! Sets the tooltip
        //! \param tt The tooltip
        DLLEXPORT void setToolTipZ(ToolTip* tt);
        //! This is necessary if multiple threads use the drawing simultaneously.
        //! If lockZeichnung() is called by two threads, the last one waits
        //! until the first has called unlockZeichnung().
        DLLEXPORT void lockZeichnung();
        //! This is necessary if multiple threads use the drawing simultaneously.
        //! If lockZeichnung() is called by two threads, the last one waits
        //! until the first has called unlockZeichnung().
        DLLEXPORT void unlockZeichnung();
        //! Sets the parameter passed to the callback function on a mouse event
        //! \param p The parameter
        DLLEXPORT void setMausEreignisParameter(void* p);
        //! Setzt den Parameter, der bei einem Tastatur Ereignis an die
        //! Rueckruffunktion uebergeben wird \param p Der Parameter
        DLLEXPORT void setTastaturEreignisParameter(void* p);
        //! Setzt die Rueckruffunktion, die bei einem Maus Ereignis aufgerufen
        //! werden soll. Wenn die Rueckruffunktion 0 zurueckgiebt, 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 and always returns 1 \param ak A pointer to
        //! the callback function
        DLLEXPORT void setMausEreignis(MausAktion ak);
        //! Adds a callback function to be called on a mouse event.
        //! If any callback returns 0, or none was set, the mouse event
        //! is not further processed by the drawing. The standard function
        //! __ret1ME can be used, which is defined in MausEreignis.h and always
        //! returns 1 \param ak A pointer to the callback function
        DLLEXPORT void addMausEreignis(MausAktion ak);
        //! Sets the callback function to be called on a keyboard event.
        //! If the callback returns 0, or was not set, the keyboard event
        //! is not further processed by the drawing. The standard function
        //! __ret1TE can be used, which is defined in TastaturEreignis.h and
        //! always returns 1. Other standard functions are _nurNummernTE and
        //! _nurHexTE also from TastaturEreignis.h \param ak A pointer to
        //! the callback function
        DLLEXPORT void setTastaturEreignis(TastaturAktion ak);
        //! Adds a callback function to be called on a keyboard event.
        //! If any callback returns 0, or none was set, the keyboard event
        //! is not further processed by the drawing. The standard function
        //! __ret1TE can be used, which is defined in TastaturEreignis.h and
        //! always returns 1. Other standard functions are _nurNummernTE and
        //! _nurHexTE also from TastaturEreignis.h \param ak A pointer to
        //! the callback function
        DLLEXPORT void addTastaturEreignis(TastaturAktion ak);
        //! Sets the parameter passed to the callback function on a mouse event
        //! that is called after the event was processed by the drawing
        //! \param p The parameter
        DLLEXPORT void setNMausEreignisParameter(void* p);
        //! Sets the parameter passed to the callback function on a keyboard
        //! event that is called after the event was processed by the drawing
        //! \param p The parameter
        DLLEXPORT void setNTastaturEreignisParameter(void* p);
        //! Sets the callback function to be called on a mouse event after
        //! the event has already been processed by the drawing. If the callback
        //! returns 1, or was not set, the mouse event will not be processed
        //! by any other drawing, such as ones behind this drawing. The standard
        //! function __ret1ME can be used, which is defined in MausEreignis.h
        //! and always returns 1 \param ak A pointer to the callback function
        DLLEXPORT void setNMausEreignis(MausAktion ak);
        //! Sets the callback function to be called on a keyboard event after
        //! the event has already been processed by the drawing. If the callback
        //! returns 1, or was not set, the keyboard event will not be processed
        //! by any other drawing. The standard function __ret1TE can be used,
        //! which is defined in TastaturEreignis.h and always returns 1. Other
        //! standard functions are _nurNummernTE and _nurHexTE also from
        //! TastaturEreignis.h \param ak A pointer to the callback function
        DLLEXPORT void setNTastaturEreignis(TastaturAktion ak);
        //! Processes a mouse event. Called automatically by the framework.
        //! \param me The event
        DLLEXPORT virtual void doPublicMausEreignis(MausEreignis& me);
        //! Processes a keyboard event. Called automatically by the framework
        //! \param te The event
        DLLEXPORT virtual void doTastaturEreignis(TastaturEreignis& te);
        //! Processes the time elapsed since the last call of this function
        //! \param tickVal The elapsed time in seconds
        DLLEXPORT virtual bool tick(double tickval);
        //! Sets the position of the drawing
        //! \param pos The position in pixels
        DLLEXPORT void setPosition(const Punkt& pos);
        //! Sets the X position of the drawing
        //! \param xPos The position in pixels
        DLLEXPORT void setX(int xPos);
        //! Sets the Y position of the drawing
        //! \param yPos The position in pixels
        DLLEXPORT void setY(int yPos);
        //! Sets the size of the drawing
        //! \param gr A point with x as width and y as height in pixels
        DLLEXPORT void setSize(const Punkt& gr);
        //! Sets the position of the drawing
        //! \param x The X position in pixels
        //! \param y The Y position in pixels
        DLLEXPORT void setPosition(int x, int y);
        //! Sets the size of the drawing
        //! \param br The width in pixels
        //! \param height The height in pixels
        DLLEXPORT void setSize(int br, int height);
        //! Set the width in pixel
        //! \param width the width
        DLLEXPORT void setWidth(int width);
        //! Set the height in pixel
        //! \param width the height
        DLLEXPORT void setHeight(int height);
        //! Sets the style of the drawing
        //! \param style The new style consisting of flags from the
        //! corresponding Style class
        DLLEXPORT void setStyle(__int64 style);
        //! Sets the style of the drawing
        //! \param style All style flags to be modified
        //! \param add_remove 1 if the style should be added. 0 if the style
        //! should be removed
        DLLEXPORT void setStyle(__int64 style, bool add_remove);
        //! Adds style flags
        //! \param style The style to add
        DLLEXPORT void addStyle(__int64 style);
        //! Removes style flags
        //! \param style The style to remove
        DLLEXPORT void removeStyle(__int64 style);
        //! Renders the drawing into a specific image
        //! \param zRObj The image to draw into
        DLLEXPORT virtual void render(Bild& zRObj);
        //! Returns whether a callback function for mouse events was set
        DLLEXPORT bool hatMausEreignis() const;
        //! Returns whether a callback function for keyboard events was set
        DLLEXPORT bool hatTastaturEreignis() const;
        //! Returns the position of the drawing in pixels
        DLLEXPORT const Punkt& getPosition() const;
        //! Returns the size of the drawing in pixels. x for width and y
        //! for height
        DLLEXPORT const Punkt& getSize() const;
        //! Returns the width of the drawing in pixels
        DLLEXPORT int getBreite() const;
        //! Returns the height of the drawing in pixels
        DLLEXPORT int getHeight() const;
        //! Returns the inner width of the drawing in pixels
        DLLEXPORT virtual int getInnenBreite() const;
        //! Returns the inner height of the drawing in pixels
        DLLEXPORT virtual int getInnenHeight() const;
        //! Returns the X position of the drawing in pixels
        DLLEXPORT int getX() const;
        //! Returns the Y position of the drawing in pixels
        DLLEXPORT int getY() const;
        //! Prueft, 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;
        //! Prueft, 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;
        //! Returns a pointer to the tooltip object, if it is used
        DLLEXPORT ToolTip* getToolTip() const;
        //! Returns a pointer to the tooltip object without increased
        //! reference counter, if it is used
        DLLEXPORT ToolTip* zToolTip() const;
        //! Returns whether specific styles are set
        //! \param style The styles to check
        //! \return 1 if all styles in style are set
        DLLEXPORT bool hatStyle(__int64 style) const;
        //! Returns whether specific styles are not set
        //! \param style The styles to check
        //! \return 1 if all styles in style are not set
        DLLEXPORT bool hatStyleNicht(__int64 style) const;
        //! returns all currently active styles
        DLLEXPORT __int64 getStyles() const;
        //! Copies the complete drawing so it can be modified without
        //! affecting the original
        DLLEXPORT virtual Zeichnung* dublizieren() const;
    };

    //! A drawing element for the 2D GUI Framework with background, border
    //! and scroll bars
    class ZeichnungHintergrund : public Zeichnung
    {
    public:
        class Style : public Zeichnung::Style
        {
        public:
            //! If this flag is set, the drawing gets a border
            static const __int64 Rahmen = 0x00010;
            //! If this flag is set, the drawing gets a background
            static const __int64 Hintergrund = 0x00020;
            //! If this flag is set, the background is transparent.
            //! Requires flag Hintergrund
            static const __int64 HAlpha = 0x00040;
            //! If this flag is set, an image is used as background.
            //! Requires flag Hintergrund
            static const __int64 HBild = 0x00080;
            //! If this flag is set, a color gradient appears as border
            static const __int64 Buffered = 0x00100;
            //! If this flag is set, a scrollbar appears at the right edge
            static const __int64 VScroll = 0x00200;
            //! If this flag is set, a scrollbar appears at the bottom edge
            static const __int64 HScroll = 0x00400;
            //! If this flag is set, the image is scaled
            static const __int64 HBildScale = 0x00800;
        };

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

    protected:
        //! Processes mouse messages
        //! \param me The event triggered by the mouse input
        DLLEXPORT void doMausEreignis(MausEreignis& me, bool userRet) override;

    public:
        //! Constructor
        DLLEXPORT ZeichnungHintergrund();
        //! Destructor
        DLLEXPORT virtual ~ZeichnungHintergrund();
        //! Sets the background image (requires drawing flag:
        //! Style::Hintergrund, HBild) \param bild The image is copied and used
        //! as background image
        DLLEXPORT void setHintergrundBild(Bild* bild);
        //! Sets a pointer to the background image (requires drawing flag:
        //! Style::Hintergrund) \param bild The image is used without copying
        DLLEXPORT void setHintergrundBildZ(Bild* bild);
        //! Sets the background color (requires drawing flag:
        //! Style::Hintergrund) \param fc The background color in A8R8G8B8 format
        DLLEXPORT void setHintergrundFarbe(int fc);
        //! Sets a pointer to the AlphaFeld (requires drawing flag:
        //! Style::Buffered) \param buff The AlphaFeld to draw over the background
        DLLEXPORT void setAlphaFeldZ(AlphaFeld* buff);
        //! Setzt die Staerke des AlphaFeldes (benoetigt Flag zum Zeichnen:
        //! Style::Buffered) \param st Die Staerke des AlphaFeldes, welches ueber
        //! dem Hintergrund gezeichnet werden soll
        DLLEXPORT void setAlphaFeldStrength(int st);
        //! Setzt die Farbe des AlphaFeldes (benoetigt Flag zum Zeichnen:
        //! Style::Buffered) \param fc Die Farbe des AlphaFeldes, welches ueber
        //! dem Hintergrund gezeichnet werden soll
        DLLEXPORT void setAlphaFeldFarbe(int fc);
        //! Sets a pointer to the line border drawn around the text field
        //! (requires drawing flag: Style::Rahmen)
        //! \param ram The border
        DLLEXPORT void setRahmenZ(Rahmen* ram);
        //! Sets the width of the line border (requires drawing flag:
        //! Style::Rahmen) \param br The width in pixels
        DLLEXPORT void setRahmenBreite(int br);
        //! Sets the color of the line border (requires drawing flag:
        //! Style::Rahmen) \param fc The color in A8R8G8B8 format
        DLLEXPORT void setRahmenFarbe(int fc);
        //! Sets the scroll speed of the vertical scroll bar (requires drawing
        //! flag: Style::VScroll) \param ks The scroll speed in pixels per mouse click
        DLLEXPORT void setVertikalKlickScroll(int ks);
        //! Scrolls to a specific position on the vertical scroll bar
        //! (requires drawing flag: Style::VScroll) \param pos The scroll offset in pixels
        DLLEXPORT void setVertikalScrollPos(int pos);
        //! Sets the color of the vertical scroll bar (requires drawing flag:
        //! Style::VScroll) \param f The foreground color in A8R8G8B8 format
        //! \param bgF The background color in A8R8G8B8 format
        DLLEXPORT void setVertikalScrollFarbe(int f, int bgF);
        //! Sets the scroll speed of the horizontal scroll bar (requires drawing
        //! flag: Style::HScroll) \param ks The scroll speed in pixels per mouse click
        DLLEXPORT void setHorizontalKlickScroll(int ks);
        //! Scrolls to a specific position on the horizontal scroll bar
        //! (requires drawing flag: Style::HScroll) \param pos The scroll offset in pixels
        DLLEXPORT void setHorizontalScrollPos(int pos);
        //! Sets the color of the horizontal scroll bar (requires drawing flag:
        //! Style::HScroll) \param f The foreground color in A8R8G8B8 format
        //! \param bgF The background color in A8R8G8B8 format
        DLLEXPORT void setHorizontalScrollFarbe(int f, int bgF);
        //! Updates the drawing background
        //! \param tickVal The elapsed time in seconds since the last call
        //! of this function \return 1 if the image needs to be redrawn. 0 otherwise
        DLLEXPORT bool tick(double tickVal) override;
        //! Renders the background of a drawing to rObj
        DLLEXPORT void render(Bild& rObj) override;

        //! Returns the inner width of the drawing in pixels
        DLLEXPORT virtual int getInnenBreite() const override;
        //! Returns the inner height of the drawing in pixels
        DLLEXPORT virtual int getInnenHeight() const override;
        //! Returns the background image.
        //! \return 0 if no background image is used
        DLLEXPORT Bild* getHintergrundBild() const;
        //! Returns the background image without increased reference counter.
        //! \return 0 if no background image is used
        DLLEXPORT Bild* zHintergrundBild() const;
        //! Returns the background color in A8R8G8B8 format
        DLLEXPORT int getHintergrundFarbe() const;
        //! Returns the AlphaFeld drawn over the background.
        //! \return 0 if the AlphaFeld was not defined
        DLLEXPORT AlphaFeld* getAlphaFeld() const;
        //! Returns the AlphaFeld without increased reference counter drawn
        //! over the background. \return 0 if the AlphaFeld was not defined
        DLLEXPORT AlphaFeld* zAlphaFeld() const;
        //! Returns the strength of the AlphaFeld
        DLLEXPORT int getAlphaFeldStrength() const;
        //! Returns the color of the AlphaFeld in A8R8G8B8 format
        DLLEXPORT int getAlphaFeldFarbe() const;
        //! Returns the border
        //! \return 0 if no border was defined
        DLLEXPORT Rahmen* getRahmen() const;
        //! Returns the border without increased reference counter
        //! \return 0 if no border was defined
        DLLEXPORT Rahmen* zRahmen() const;
        //! Returns the width of the border in pixels
        DLLEXPORT int getRahmenBreite() const;
        //! Returns the color of the border in A8R8G8B8 format
        DLLEXPORT int getRahmenFarbe() const;
        //! Returns the scroll speed of the vertical scroll bar
        DLLEXPORT int getVertikalKlickScroll() const;
        //! Returns the scroll position of the vertical scroll bar
        DLLEXPORT int getVertikalScrollPos() const;
        //! Returns the color of the vertical scroll bar in A8R8G8B8 format
        DLLEXPORT int getVertikalScrollFarbe() const;
        //! Returns the background color of the vertical scroll bar in A8R8G8B8
        //! format
        DLLEXPORT int getVertikalScrollHintergrund() const;
        //! Returns the scroll speed of the horizontal scroll bar
        DLLEXPORT int getHorizontalKlickScroll() const;
        //! Returns the scroll position of the horizontal scroll bar
        DLLEXPORT int getHorizontalScrollPos() const;
        //! Returns the color of the horizontal scroll bar in A8R8G8B8 format
        DLLEXPORT int getHorizontalScrollFarbe() const;
        //! Returns the background color of the horizontal scroll bar in A8R8G8B8
        //! format
        DLLEXPORT int getHorizontalScrollHintergrund() const;
        //! Creates a copy of the drawing that can be modified without
        //! affecting the original
        DLLEXPORT virtual Zeichnung* dublizieren() const;
    };
} // namespace Framework

#endif