#pragma once

#include "Mat4.h"
#include "Zeichnung3D.h"
#include "Punkt.h"

//! DirectX 11 Types

struct D3D11_VIEWPORT;

namespace Framework
{
    struct MausEreignis; //! MausEreignis.h
    class Render3D; //! Render3D.h
    class Welt3D; //! Welt3D.h

    struct ViewPort
    {
        float x;
        float y;
        float width;
        float height;
        float front;
        float back;
    };

    //! Eine 3d Kamera, die einen Ausschnitt einer 3D Welt in einen bestimmten Teil des Bildschirms zeichnet
    class Kam3D : public virtual Framework::ReferenceCounter
    {
    public:
        class Style
        {
        public:
            const static __int64 Movable = 0x1;
            const static __int64 Rotatable = 0x2;
            const static __int64 Zoomable = 0x4;
            const static __int64 Tick = 0x8;
        };
    protected:
        bool rend;

    private:
        Mat4< float > view;
        Mat4< float > proj;

        float openingAngle;
        float minZ;
        float maxZ;
        Vec3< float > pos;
        float rotX;
        float rotY;
        float rotZ;

        ViewPort viewport;
        Welt3D *welt;
        __int64 style;

        //! Aktualisiert die view und projektion matrizen
        void updateMatrix();

    public:
        //! Konstruktor
        DLLEXPORT Kam3D();
        //! Destruktor
        DLLEXPORT ~Kam3D();
        //! Setzt die Position der Kamera in der 3D Welt
        DLLEXPORT void setPosition( Vec3< float > pos );
        //! zoomt heran, indem sich die Kamera etwas auf das Blickziel zubewegt
        //! \param val Die länge der Strecke um die sich die Kamera bewegen soll
        DLLEXPORT void scrollIn( float val );
        //! zppmt heraus, indem sich die Kamera etwas von dem Blockziel entfernt
        //! \param val Die länge der Strecke um die sich die Kamera bewegen soll
        DLLEXPORT void scrollOut( float val );
        //! Richtet die Kamera so aus, dass sie genau auf einen bestimmten Punkt zeigt
        //! \param ziel Der Punkt, auf den die Kamera zeigen soll
        DLLEXPORT void setAusrichtung( Vec3< float > ziel );
        //! Legt die Drehung der Kamera um die einzelnen Axen fest
        //! \param rotation Die Drehung um die einzelnen Axen
        DLLEXPORT void setRotation( Vec3< float > rotation );
        //! Setzt die Position des Bildes auf dem Bildschirm
        //! \param p Ein Punkt mit x und y Koordinaten in Pixeln
        DLLEXPORT void setBildschirmPosition( Punkt p );
        //! Setzt die Position des Bildes auf dem Bildschirm
        //! \param x Die x Koordinate in Pixeln
        //! \param y Die y Koordinate in Pixeln
        DLLEXPORT void setBildschirmPosition( int x, int y );
        //! Setzt die Größe des Bildes auf dem Bildschirm
        //! \param p Ein Punkt, mit x als Breite und y als Höhe in Pixlen
        DLLEXPORT void setBildschirmSize( Punkt p );
        //! Setzt die Größe des Bildes auf dem Bildschirm
        //! \param br Die Breite in Pixeln
        //! \param hi Die Höhe in Pixeln
        DLLEXPORT void setBildschirmSize( int br, int hi );
        //! Setzt die Welt, die gezeichnet werden soll
        //! \param w Die Welt
        DLLEXPORT void setWelt( Welt3D *w );
        //! Setzt den Style der Kamera
        //! \param style Der neue Style bestehend aus den Flags aus der zugehörigen Style Klasse
        DLLEXPORT void setStyle( __int64 style );
        //! Setzt den Style der Kamera
        //! \param style Alle Style Flags, die verändert werden sollen
        //!  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 );
        //! Verarbeitet die vergangene Zeit
        //! \param tickval Die zeit in sekunden, die seit dem letzten Aufruf der Funktion vergangen ist
        //! \return true, wenn sich das Bild neu gezeichnet werden muss, false sonnst.
        DLLEXPORT virtual bool tick( double tv );
        //! Verarbeitet ein Mausereignis
        //! \param me Das Mausereignis, das verarbeitet werden soll
        DLLEXPORT virtual void doMausEreignis( MausEreignis &me );
        //! Verarbeitet ein Tastaturereignis
        //! \param te das Tastaturereignis, das verarbeitet werden soll
        DLLEXPORT virtual void doTastaturEreignis( TastaturEreignis &te );
        //! 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;
        //! Gibt einen Zeiger auf den Viewport zurück
        DLLEXPORT const ViewPort *zViewPort() const;
        //! Gibt die Position der Kamera in der Welt zurück
        DLLEXPORT const Vec3< float > &getWorldPosition() const;
        //! Gibt die Position in der Welt zurück
        //! \param screen die Position auf dem Bildschirm, die übersetzt werden soll
        DLLEXPORT const Vec3< float > getWorldPosition( Punkt screen ) const;
        //! Gibt die Richtung der Kamera in der Welt zurück
        //! \param screen die Position auf dem Bildschirm, die übersetzt werden soll
        DLLEXPORT const Vec3< float > getWorldDirection( Punkt screen ) const;
        //! Gibt die Projektionsmatrix der Kamera zurück
        DLLEXPORT const Mat4< float > &getProjectionMatrix() const;
        //! Gibt die Ansichtsmatrix der Kamera zurück
        DLLEXPORT const Mat4< float > &getViewMatrix() const;
        //! Gibt die Rotation um die einzelnen axen zurück
        DLLEXPORT const Vec3< float > getRotation() const;
        //! Gibt die Position der Kamera auf dem Bildschirm zurück
        DLLEXPORT const Punkt getScreenPos() const;
        //! Gibt die Größe der Kamera auf dem Bildschirm zurück
        DLLEXPORT const Punkt getScreenSize() const;
        //! Gibt die Welt zurück
        DLLEXPORT Welt3D *getWelt() const;
        //! Gibt die Welt zurück
        DLLEXPORT Welt3D *zWelt() const;
    };
}