#pragma once

#include <Camera3D.h>
#include <Screen.h>
#include <Thread.h>
#include <World3D.h>

#include "Dimension.h"
#include "FactoryClient.h"
#include "PlayerKam.h"

class World : public Framework::Thread
{
public:
    static World* INSTANCE;

private:
    Dimension* currentDimension;
    Framework::World3D* renderedWorld;
    Framework::Screen3D* zScreenPtr;
    PlayerKam* kam;
    bool firstMessage;
    int ownEntityId;
    Framework::Model3D* currentTarget;
    Array<Point> subscriptions;
    FactoryClient* client;
    FactoryCraftModel* selectionModel;
    ReadWriteLock subLock;
    Critical targetLock;
    float dayLightFactor;
    double time;
    double dayLength;
    double transitionLength;
    double nightLength;

public:
    World(Framework::Screen3D* zScreen, FactoryClient* client);
    ~World();
    int update(bool background);
    void onTick(double time);
    void setChunk(Chunk* chunk);
    void thread() override;

    Block* zBlockAt(Framework::Vec3<int> location) const;
    Block* getBlockAt(Framework::Vec3<int> location) const;
    Dimension* zDimension() const;
    void setVisibility(Entity* zEntity, bool visible);
    Framework::Point getChunkCenter(int x, int y) const;
    Entity* zEntity(int id) const;
    Entity* getEntity(int id) const;
    void removeEntity(int id);
    PlayerKam* zKamera() const;
    int getCurrentPlayerId() const;
    Entity* getCurrentPlayerEntity() const;
    void setTarget(Framework::Model3D* zTarget);
    void onChunkAdded(Point pos);
    Chunk* zChunk(Point center);
    Lock& getChunkReadLock();
    Framework::Model3D* getCurrentTarget() const;
    FactoryCraftModel* zSelectedEffectModel() const;
    FactoryClient* zClient() const;
    float getDayLightFactor() const;
};