#pragma once

#include "Array.h"
#include "Critical.h"
#include "GraphicsApi.h"
#include "Model3DCollection.h"
#include "Vec3.h"

namespace Framework
{
    class Zeichnung3D;     //! Zeichnung.h
    class Render3D;        //! Render3D.h
    struct MausEreignis3D; //! MausEreignis.h
    class Model3D;
    class DXBuffer;
    class Welt3D;

    //! Speichert alle 3D Zeichnungen einer Szene ab
    class Welt3D : public Model3DCollection
    {
    protected:
        DiffuseLight* diffuseLights;
        RCArray<Model3DCollection> modelCollections;
        int diffuseLightCount;
        PointLight* pointLights;
        int pointLightCount;

    private:
        RCArray<Model3D>* members;
        bool rend;
        Critical cs;

    public:
        //! Konstructor
        DLLEXPORT Welt3D();
        //! Destruktor
        DLLEXPORT virtual ~Welt3D();
        //! Blockiert den zugriff auf das Objekt und wartet gegebenfalls auf den
        //! Zugriff
        DLLEXPORT void lock();
        //! Gibt das Objekt für andere Threads frei
        DLLEXPORT void unlock();
        //! Fügt der Welt ein Objekt hinzu
        //! \param obj Das Objekt, was hinzugefügt werden soll
        DLLEXPORT void addZeichnung(Model3D* obj);
        //! Entfernt ein Objekt aus der Welt
        //! \param obj Das Objekt, das entwernt werden soll (ohne erhöhten
        //! reference Counter)
        DLLEXPORT void removeZeichnung(Model3D* zObj);
        //! Fügt der Welt eine Collection von Objekten hinzu
        //! \param collection Die Collection, die hinzugefügt werden soll
        DLLEXPORT void addCollection(Model3DCollection* collection);
        //! removes a collection of models from the world
        //! \param zCollection Die Collection die entfernt werden soll
        DLLEXPORT void removeCollection(Model3DCollection* zCollection);
        //! Verarbeitet ein Mausereignis
        //! \param me Das Mausereignis, das verarbeitet werden soll
        DLLEXPORT void doMausEreignis(MausEreignis3D& me);
        //! Verarbeitet die vergangene Zeit
        //! \param tickval Die zeit in sekunden, die seit dem letzten Aufruf der
        //! Funktion vergangen ist \return true, wenn sich das Objekt verändert
        //! hat, false sonnst.
        DLLEXPORT virtual bool tick(double tickval);
        //! brerechnet die Farbe eines Sichtstrahls, der von einem bestimmten
        //! punkt aus in eine bestimmte richtung schaut \param point Der
        //! ursprung des Strahls, \param dir Die Richtung des Strahls \return
        //! Die Farbe des Strahls
        DLLEXPORT virtual int traceRay(Vec3<float>& point, Vec3<float>& dir);
        //! führt eine funktion auf jedem Model aus
        DLLEXPORT virtual void forAll(std::function<void(Model3D*)> f) override;
        //! Gibt die Anzahl an Punkt Lichtquellen zurück
        DLLEXPORT int getPointLightCount() const;
        //! Gibt die Anzahl an Richtungs Lichtquellen zurück
        DLLEXPORT int getDiffuseLightCount() const;
        //! Kopiert alle Lichtquellen in die Buffer
        //! \param zDiffuse der Buffer für die rechtungs Lichtquellen
        //! \param zPoints der Buffer für die Punkt Lichtquellen
        DLLEXPORT void copyLight(DXBuffer* zDiffuse, DXBuffer* zPoints) const;
        //! fügt eine neue diffuse lichtquelle hinzu
        //! \param light Die neue Lichtquelle
        DLLEXPORT void addDiffuseLight(DiffuseLight light);
        //! fügt eine neue Punkt lichtquelle hinzu
        //! \param light Die neue Lichtquelle
        DLLEXPORT void addPointLight(PointLight light);
        //! Gibt die Referenz auf eine Diffuse Lichtquelle zurück
        //! \param index Der Index der Lichtquelle
        DLLEXPORT DiffuseLight& getDiffuseLight(int index) const;
        //! Gibt die Referenz auf eine Punkt Lichtquelle zurück
        //! \param index Der Index der Lichtquelle
        DLLEXPORT PointLight& getPointLight(int index) const;
    };
} // namespace Framework