#pragma once

#include <Critical.h>
#include <Either.h>
#include <Klient.h>
#include <Network.h>
#include <Punkt.h>
#include <Text.h>
#include <Thread.h>
#include <VecN.h>

#include "Entity.h"

class FactoryClient : public Framework::ReferenceCounter
{
private:
    Network::SSLKlient* client;
    Network::Klient* foreground;
    Network::Klient* 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(char* data, unsigned short length);
    void sendPlayerMovement(MovementFrame& frame);
    void entityAPIRequest(int entityId, char* message, unsigned short length);
    void blockAPIRequest(Vec3<int> pos, char* message, unsigned short length);
    void blockAPIRequest(
        int dimensionId, Vec3<int> pos, char* message, unsigned short length);
    void chunkAPIRequest(
        Framework::Punkt center, char* message, unsigned short length);
    void dimensionAPIRequest(char* message, unsigned short length);
    void inventoryAPIRequest(
        Framework::Either<int, Framework::VecN<int, 4>> target,
        char* message,
        unsigned short length);
    void uiRequest(Framework::Text dialogId, char* message, unsigned short length);
    void craftingUIMLRequest(int itemTypeId);
    void sendChatMessage(Framework::Text message);
    void chatAPIRequest(char* data, unsigned short length);
    bool isConnected();
    void leaveGame();
};