#pragma once

#include <Critical.h>
#include <Either.h>
#include <Client.h>
#include <Network.h>
#include <Point.h>
#include <Text.h>
#include <Thread.h>
#include <VecN.h>

#include "Entity.h"

class FactoryClient : public Framework::ReferenceCounter
{
private:
    Network::SSLClient* client;
    Network::Client* foreground;
    Network::Client* background;
    Network::NetworkReader* foregroundReader;
    Network::NetworkReader* backgroundReader;
    Framework::Critical cs;
    Framework::Text ip;
    int bgReaderUsage;
    int fgReaderUsage;

    void disconnect();
    void loadServerInfo();

public:
    FactoryClient();
    ~FactoryClient();

    bool connect(Framework::Text ip, unsigned short sslPort);
    int ping();
    int status(Framework::Text name, Framework::Text secret);
    int join(
        Framework::Text name, Framework::Text& secret, unsigned short port);
    Network::NetworkReader* getNextForegroundMessage();
    Network::NetworkReader* getNextBackgroundMessage();
    void endMessageReading(bool bg);
    void sendPlayerAction(const char* data, unsigned short length);
    void sendPlayerFaceDirection(Vec3<float> dir);
    void sendPlayerMovement(int flags);
    void entityAPIRequest(
        int entityId, const char* message, unsigned short length);
    void blockAPIRequest(
        Vec3<int> pos, const char* message, unsigned short length);
    void componentAPIRequest(
        int* address, int addrLen, const char* message, unsigned short length);
    void blockAPIRequest(int dimensionId,
        Vec3<int> pos,
        const char* message,
        unsigned short length);
    void chunkAPIRequest(
        Framework::Point center, const char* message, unsigned short length);
    void dimensionAPIRequest(const char* message, unsigned short length);
    void inventoryAPIRequest(
        Framework::Either<int, Framework::VecN<int, 4>> target,
        const char* message,
        unsigned short length);
    void uiRequest(
        Framework::Text dialogId, const char* message, unsigned short length);
    void craftingUIMLRequest(int itemTypeId);
    void sendChatMessage(Framework::Text message);
    void chatAPIRequest(const char* data, unsigned short length);
    void giveItemRequest(int itemTypeId, bool fullStack);
    bool isConnected();
    void leaveGame();
};