#ifndef Screen_H
#define Screen_H

#include <queue>

#include "Array.h"
#include "Critical.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "Point.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 Image;          //! Image.h
    class NativeWindow;   //! Window.h
    class Screen;         //! from this file
    class Drawable;       //! Drawing.h
    class Drawable3D;     //! Drawing3D.h
    class Timer;          //! Time.h
    struct MouseEvent;    //! MouseEvent.h
    struct KeyboardEvent; //! KeyboardEvent.h
    class ToolTip;        //! Tooltip.h
    class PixelShader;    //! Shader.h
    class VertexShader;   //! Shader.h
    class Cam3D;          //! Camera3D.h
    class Render3D;       //! Render3D.h
    class DXVertexBuffer; //! DXBuffer.h
    class DXIndexBuffer;  //! DXBuffer.h
    class Texture;        //! Texture.h
    class TextureModel;   //! TextureModel.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, width,
            height;  //! Coordinates of the monitor and its resolution
        bool exists; //! Stores whether the monitor really exists
        Text name;
    };

    //! This class manages the image on the screen
    class Screen : public virtual ReferenceCounter
    {
    protected:
        GraphicsApi* api;
        NativeWindow* fenster;
        RCArray<Drawable>* members;
        int fillColor;
        int deckColor;
        Drawable* onTop;
        bool renderOnTop;
        bool renderDrawables;
        bool rendering;
        Timer* renderTime;
        ReadWriteLock rwLock;
        RCArray<ToolTip>* tips;
        bool testRend;
        bool fill;
        bool rend;
        bool handleUserInputsOnTick;
        Critical queueCs;
        Array<MouseEvent> meQueue;
        Array<KeyboardEvent> teQueue;
        std::queue<std::function<void()>> actions;

    public:
        //! Constructor
        //! \param fenster The window whose content should be managed
        DLLEXPORT Screen(NativeWindow* fenster);
        //! Destructor
        DLLEXPORT virtual ~Screen();
        //! 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 mouse 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);
        //! returns a lock for reading.
        DLLEXPORT virtual Lock& readLock();
        //! returns a lock for writing.
        DLLEXPORT virtual Lock& writeLock();
        //! 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 setRenderDrawables(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 setOnTopDrawable(Drawable* obj);
        //! Sets a color that is alpha-blended over the entire image after
        //! drawing, if setOnTop(1) was set. The drawing set with
        //! setOnTopDrawable() is not affected \param f The color in A8R8G8B8
        //! format
        DLLEXPORT virtual void setdeckColor(int f);
        //! Adds a drawing to the image that is always drawn when
        //! setRenderDrawables(1) was set. \param obj The drawing
        DLLEXPORT virtual void addMember(Drawable* obj);
        //! Removes a drawing from the image. Must not be called while
        //! doMouseEvent(), doKeyboardEvent(), tick() or render() is
        //! being called. \param obj The drawing (without increased reference
        //! counter)
        DLLEXPORT virtual void removeMember(Drawable* zObj);
        //! Draws an image and presents it on the screen
        DLLEXPORT virtual void render() = 0;
        //! 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 setFillColor(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 setFullscreen(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 Width The width of the image in pixels
        //! \param height The height of the image in pixels
        DLLEXPORT virtual void setBackBufferSize(int Width, 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(Point& 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 doMouseEvent(MouseEvent& 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 doKeyboardEvent(KeyboardEvent& 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 Image* getRenderImage() const;
        //! Returns the image without increased reference counter into which
        //! the 2D GUI drawings of the framework are drawn
        DLLEXPORT virtual Image* zRenderImage() const;
        //! Returns an array of 2D GUI drawings in the image
        DLLEXPORT virtual ArrayIterator<Drawable*> getMembers() const;
        //! Returns the color in A8R8G8B8 format used to fill the image
        //! before drawing
        DLLEXPORT virtual int getFillColor() const;
        //! Returns whether fullscreen mode is active
        DLLEXPORT virtual bool isFullscreen() const;
        //! Returns the resolution in pixels at which drawing occurs
        DLLEXPORT virtual const Point getBackBufferSize() const;
        //! Waits until the current image has finished drawing
        DLLEXPORT virtual void waitForRendering() 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 Screen2D : public Screen
    {
    public:
        //! Constructor
        //! \param fenster The window whose content should be managed
        DLLEXPORT Screen2D(NativeWindow* fenster);
        //! Destructor
        DLLEXPORT virtual ~Screen2D();
        //! 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 Screen3D : public Screen
    {
    private:
        RCArray<Cam3D>* kameras;
        bool rend3D;

    public:
        //! Constructor
        //! \param fenster The window whose content should be managed
        DLLEXPORT Screen3D(NativeWindow* fenster);
        DLLEXPORT Screen3D(NativeWindow* fenster, GraphicApiType apiTyp);
        DLLEXPORT Screen3D(NativeWindow* fenster, GraphicsApi* api);
        //! Destructor
        DLLEXPORT virtual ~Screen3D();
        //! Adds a camera to the screen
        //! \param obj The camera
        DLLEXPORT void addKamera(Cam3D* obj);
        //! Removes a camera from the screen
        DLLEXPORT void removeKamera(Cam3D* 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 doMouseEvent(MouseEvent& 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 doKeyboardEvent(KeyboardEvent& 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 exists flag of the returned Monitor structure is 0
    DLLEXPORT Monitor getMonitor(int id);
#endif
} // namespace Framework

#endif