#ifndef Bildschirm_H
#define Bildschirm_H

#include <queue>

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

//! DirectX 11 Types

struct ID3D11Device;
struct ID3D11DeviceContext;
struct IDXGISwapChain;
struct ID3D11Texture2D;
struct ID3D11SamplerState;
struct ID3D11ShaderResourceView;
struct ID3D11RenderTargetView;
struct ID3D11DepthStencilView;
struct ID3D11DepthStencilState;
struct ID3D11RasterizerState;
struct ID3D11BlendState;
struct D3D11_VIEWPORT;

//! DirectX 9 Types

struct IDirect3D9;
struct IDirect3DDevice9;
struct IDirect3DSurface9;
struct _D3DLOCKED_RECT;

namespace Framework
{
    class Bild;              //! Bild.h
    class WFenster;          //! Fenster.h
    class Bildschirm;        //! from this file
    class Zeichnung;         //! Zeichnung.h
    class Zeichnung3D;       //! Zeichnung3D.h
    class ZeitMesser;        //! Zeit.h
    struct MausEreignis;     //! MausEreignis.h
    struct TastaturEreignis; //! TastaturEreignis.h
    class ToolTip;           //! Tooltip.h
    class PixelShader;       //! Shader.h
    class VertexShader;      //! Shader.h
    class Kam3D;             //! Kam3D.h
    class Render3D;          //! Render3D.h
    class DXVertexBuffer;    //! DXBuffer.h
    class DXIndexBuffer;     //! DXBuffer.h
    class Textur;            //! Textur.h
    class TexturModel;       //! TexturModel.h
    class GraphicsApi;       //! GraphicsApi.h
    class DirectX9;          //! GraphicsApi.h

    enum GraphicApiType
    {
        NOT_SUPPORTED, //! no graphic api supported
        DIRECTX9,      //! only 2d
        DIRECTX11,     //! 3d simple phong model without shadows
        DIRECTX12      //! 3d phong model with raytraycing
    };

    //! A structure containing information about a monitor
    struct Monitor
    {
        int x, y, breite,
            height;     //! Coordinates of the monitor and its resolution
        bool existiert; //! Stores whether the monitor really exists
        Text name;
    };

    //! This class manages the image on the screen
    class Bildschirm : public virtual ReferenceCounter
    {
    protected:
        GraphicsApi* api;
        WFenster* fenster;
        RCArray<Zeichnung>* members;
        int fillColor;
        int deckFarbe;
        Zeichnung* onTop;
        bool renderOnTop;
        bool renderZeichnungen;
        bool rendering;
        ZeitMesser* renderZeit;
        Critical cs;
        RCArray<ToolTip>* tips;
        bool testRend;
        bool fill;
        bool rend;
        bool handleUserInputsOnTick;
        Critical queueCs;
        Array<MausEreignis> meQueue;
        Array<TastaturEreignis> teQueue;
        std::queue<std::function<void()>> actions;

    public:
        //! Constructor
        //! \param fenster The window whose content should be managed
        DLLEXPORT Bildschirm(WFenster* fenster);
        //! Destructor
        DLLEXPORT virtual ~Bildschirm();
        //! Passes a void function pointer to an action that should be executed
        //! once by the main thread. Called at the beginning of tick()
        DLLEXPORT void postAction(std::function<void()> action);
        //! if set to true, then maus and keyboard events are added to a queue
        //! and will be handled at the next call of tick. Otherwise they are
        //! handled by the calling thread after waiting for a lock between the
        //! rendering and ticks. This can lead to longer waiting times since the
        //! lock can not allways be aquired betwean two frames
        DLLEXPORT void setHandleUserInputsOnTick(bool handleOnTick);
        //! This is necessary if multiple threads use the screen simultaneously.
        //! If lock() is called by two threads, the last one waits until the
        //! first has called unlock().
        DLLEXPORT virtual void lock();
        //! This is necessary if multiple threads use the screen simultaneously.
        //! If lock() is called by two threads, the last one waits until the
        //! first has called unlock().
        DLLEXPORT virtual void unlock();
        //! Specifies whether the screen is refilled with a color after each
        //! frame (set by default) \param f 1 if the image should be reset
        //! before drawing
        DLLEXPORT virtual void setFill(bool f);
        //! Updates the objects that manage the graphics card
        DLLEXPORT virtual void update();
        //! Specifies whether it is checked before drawing if the image differs
        //! from the last one (set by default) \param tr 1 if drawing should
        //! only occur when necessary
        DLLEXPORT virtual void setTestRend(bool tr);
        //! Specifies whether 2D GUI drawings should be drawn
        //! (set by default) \param rO 1 if drawings should be drawn
        DLLEXPORT virtual void setRenderZeichnungen(bool rO);
        //! Specifies whether a drawing should be drawn above all other drawings
        //! (not set by default) \param onTop 1 if a drawing should be drawn
        //! above everything
        DLLEXPORT virtual void setOnTop(bool onTop);
        //! Sets the drawing to be drawn above everything, if setOnTop(1) was
        //! set
        //! \param obj The drawing
        DLLEXPORT virtual void setOnTopZeichnung(Zeichnung* obj);
        //! Sets a color that is alpha-blended over the entire image after
        //! drawing, if setOnTop(1) was set. The drawing set with
        //! setOnTopZeichnung() is not affected \param f The color in A8R8G8B8
        //! format
        DLLEXPORT virtual void setdeckFarbe(int f);
        //! Adds a drawing to the image that is always drawn when
        //! setRenderZeichnungen(1) was set. \param obj The drawing
        DLLEXPORT virtual void addMember(Zeichnung* obj);
        //! Removes a drawing from the image. Must not be called while
        //! doMausEreignis(), doTastaturEreignis(), tick() or render() is
        //! being called. \param obj The drawing (without increased reference
        //! counter)
        DLLEXPORT virtual void removeMember(Zeichnung* zObj);
        //! Draws an image and presents it on the screen
        DLLEXPORT virtual void render();
        //! Sets the color used to fill the image before drawing, if
        //! setFill(1) was set \param f The color in A8R8G8B8 format
        DLLEXPORT virtual void setFillFarbe(int f);
        //! Specifies whether the image should be presented in fullscreen mode.
        //! (not set by default) \param fullscreen 1 for fullscreen mode
        DLLEXPORT virtual void setVollbild(bool fullscreen);
        //! Processes the time elapsed since the last call of this function.
        //! Calls the tick functions of all drawings in the image
        //! \param tickval The elapsed time in seconds
        DLLEXPORT virtual void tick(double tickval);
        //! Sets the resolution of the displayed image. It is automatically
        //! scaled by the graphics card to fill the window
        //! \param breite The width of the image in pixels
        //! \param height The height of the image in pixels
        DLLEXPORT virtual void setBackBufferSize(int breite, int height);
        //! Sets the resolution of the displayed image. It is automatically
        //! scaled by the graphics card to fill the window
        //! \param size The width and height in pixels
        DLLEXPORT virtual void setBackBufferSize(Punkt& size);
        //! Processes a mouse event. Called automatically by the framework.
        //! Passes the event to all drawings in the image
        //! \param me The event
        DLLEXPORT virtual void doMausEreignis(MausEreignis& me);
        //! Processes a keyboard event. Called automatically by the framework.
        //! Passes the event to all drawings in the image
        //! \param te The event
        DLLEXPORT virtual void doTastaturEreignis(TastaturEreignis& te);
        //! Adds a tooltip.
        //! \param tip The tooltip
        DLLEXPORT virtual void addToolTip(ToolTip* tip);
        //! Returns the image into which the 2D GUI drawings of the framework
        //! are drawn
        DLLEXPORT virtual Bild* getRenderBild() const;
        //! Returns the image without increased reference counter into which
        //! the 2D GUI drawings of the framework are drawn
        DLLEXPORT virtual Bild* zRenderBild() const;
        //! Returns an array of 2D GUI drawings in the image
        DLLEXPORT virtual ArrayIterator<Zeichnung*> getMembers() const;
        //! Returns the color in A8R8G8B8 format used to fill the image
        //! before drawing
        DLLEXPORT virtual int getFillFarbe() const;
        //! Returns whether fullscreen mode is active
        DLLEXPORT virtual bool istVolbild() const;
        //! Returns the resolution in pixels at which drawing occurs
        DLLEXPORT virtual const Punkt getBackBufferSize() const;
        //! Waits until the current image has finished drawing
        DLLEXPORT virtual void warteAufRendern() const;
        //! Returns the time in seconds needed to draw the last image
        DLLEXPORT virtual double getRenderZeit() const;
        //! Returns the graphics API (without increased reference counter)
        DLLEXPORT GraphicsApi* zGraphicsApi() const;
        //! Returns the graphics API
        DLLEXPORT GraphicsApi* getGraphicsApi() const;
    };
#ifdef WIN32
    //! This class manages the image on the screen without 3D elements
    class Bildschirm2D : public Bildschirm
    {
    public:
        //! Constructor
        //! \param fenster The window whose content should be managed
        DLLEXPORT Bildschirm2D(WFenster* fenster);
        //! Destructor
        DLLEXPORT virtual ~Bildschirm2D();
        //! Draws an image and presents it on the screen
        DLLEXPORT virtual void render();
    };

    //! This class manages the image on the screen with 3D elements
    class Bildschirm3D : public Bildschirm
    {
    private:
        RCArray<Kam3D>* kameras;
        bool rend3D;

    public:
        //! Constructor
        //! \param fenster The window whose content should be managed
        DLLEXPORT Bildschirm3D(WFenster* fenster);
        DLLEXPORT Bildschirm3D(WFenster* fenster, GraphicApiType apiTyp);
        DLLEXPORT Bildschirm3D(WFenster* fenster, GraphicsApi* api);
        //! Destructor
        DLLEXPORT virtual ~Bildschirm3D();
        //! Adds a camera to the screen
        //! \param obj The camera
        DLLEXPORT void addKamera(Kam3D* obj);
        //! Removes a camera from the screen
        DLLEXPORT void removeKamera(Kam3D* zObj);
        //! Processes the time elapsed since the last call of this function.
        //! Calls the tick functions of all drawings and cameras in the image
        //! \param tickval The elapsed time in seconds
        DLLEXPORT void tick(double tickval);
        //! Processes a mouse event. Called automatically by the framework.
        //! Passes the event to all drawings and cameras in the image
        //! \param me The event
        DLLEXPORT void doMausEreignis(MausEreignis& me);
        //! Processes a keyboard event. Called automatically by the framework.
        //! Passes the event to all drawings and cameras in the image
        //! \param te The event
        DLLEXPORT void doTastaturEreignis(TastaturEreignis& te);
        //! Draws an image and presents it on the screen
        DLLEXPORT void render();
    };

    //! Finds the position and resolution of a monitor
    //! \param id The ID of the monitor. If the monitor was not found,
    //! the existiert flag of the returned Monitor structure is 0
    DLLEXPORT Monitor getMonitor(int id);
#endif
} // namespace Framework

#endif