#pragma once

#include "Mat4.h"
#include "Punkt.h"
#include "Zeichnung3D.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:
            static const __int64 Movable = 0x1;
            static const __int64 Rotatable = 0x2;
            static const __int64 Zoomable = 0x4;
            static const __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;
        float speed;

        //! 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);
        //! Set the movement speed per second if the camera has style Movable
        DLLEXPORT void setMovementSpeed(float speed);
        //! 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;
    };
} // namespace Framework