
/*---------------------------------------------------------------------------*/
/* apirelay.h                                                                */
/* copyright (c) innovaphone 2017                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

class ApiRelayService: public AppService {
    void AppServiceApps(istd::list<AppServiceApp> * appList) override {};

public:
    ApiRelayService(class IIoMux * const iomux, ISocketProvider * localSocketProvider, IWebserverPluginProvider * const webserverPluginProvider, AppServiceArgs * args, const char * localSocketPath = NULL);
    ~ApiRelayService();

    class AppInstance * CreateInstance(AppInstanceArgs * args) override;

    class IIoMux * iomux;
    class IWebserverPluginProvider * webserverPluginProvider;
    ISocketProvider * localSocketProvider;
    char * localSocketPath;
};

typedef std::list<class ClientSession *> ClientSessions;
typedef std::list<class LocalSession *> LocalSessions;

class ApiRelay : public UWebserverPlugin, public AppInstance, public USocket
{
    void WebserverPluginWebsocketListenResult(IWebserverPlugin * plugin, const char * path, const char * registeredPathForRequest, const char * host) override;
    void WebserverPluginClose(IWebserverPlugin * plugin, wsp_close_reason_t reason, bool lastUser) override;
    void Stop() override;
    void AppInstanceShutdownTimeout() override;
    void TryStop();

    class IIoMux * iomux;
    class ApiRelayService * service;
    class IWebserverPlugin * webserverPlugin;
    bool stopping;
    class ClientSession * activeClient;
    ISocket * localSocket;

    void SocketListenResult(ISocket * const socket, const char * remoteAddr, word remotePort) override;
    void SocketShutdown(ISocket * const socket, shutdownreason_t reason) override;
    void SocketRecvCanceled(ISocket * const socket, void * buf) override {};

public:
    ApiRelay(IIoMux * const iomux, ApiRelayService * service, AppInstanceArgs * args);
    ~ApiRelay();

    const char * GetAppPassword();
    void SessionClosed(class ClientSession * session);
    void SessionClosed(class LocalSession * session);

    ClientSessions clientSessions;
    LocalSessions localSessions;

    void SetActiveClient(class ClientSession * session);
    class ClientSession * ActiveClient() { return activeClient; };
    const char * GetApiUpdate();
};

class ProvidedApiSet {
    class btree * tree;

public:
    ProvidedApiSet();
    ~ProvidedApiSet();

    void Add(const char * name, const char * message);
    void SetProvideApi(const char * name, const char * message);
    void SetApiModel(const char * name, const char * message);
    void Remove(const char * name);
    bool Contains(const char * name);
    class ProvidedApi * GetNext(class ProvidedApi * api);
};

class ProvidedApi : public btree {
public:
    ProvidedApi(const char * name, const char * message);
    ~ProvidedApi();
    int btree_compare(void * key) override;
    int btree_compare(class btree * b) override;
    void SetProvideApi(const char * message);
    void SetApiModel(const char * message);
    char * name;
    char * provideApi;
    char * apiModel;
};

class ClientSession : public AppWebsocket {
    class ApiRelay * instance;
    bool closing;
    bool appWebsocketClosed;

    char * AppWebsocketPassword() override;
    bool AppWebsocketConnectComplete(class json_io & msg, word base) override;
    void AppWebsocketMessage(class json_io & msg, word base, const char * mt, const char * src) override;
    void AppWebsocketClosed() override;
    void AppWebsocketSendResult() override {};
    void TryClose();

public:
    ClientSession(class ApiRelay * instance, class IWebserverPlugin * webserverPlugin);
    ~ClientSession();

    void AppWebsocketMessageSend(class json_io & msg, char * buffer);
    void AppWebsocketMessageSendText(const char * buffer);
    void AppWebsocketMessageSendBinary(char * buffer, int len);
    void Close();

    bool connected;
    char * name;
    char * apiUpdate;
    char * apiObsolete;
};

class LocalSession : public AppWebsocket, public USocket {
    class ApiRelay * instance;
    bool closing;
    bool appWebsocketClosed;
    ISocket * localSocket;
    char recvBuf[WS_MAX_DATA_SIZE];
    unsigned recvLen;
    unsigned jsonLevel;
    bool jsonQuotes;
    bool jsonEsc;

    void SocketAcceptComplete(ISocket * const socket) override;
    void SocketShutdown(ISocket * const socket, shutdownreason_t reason) override;
    void SocketSendResult(ISocket * const socket) override {};
    void SocketRecvResult(ISocket * const socket, void * buf, size_t len) override;
    void SocketRecvCanceled(ISocket * const socket, void * buf) override {};

    char * AppWebsocketPassword() override;
    bool AppWebsocketConnectComplete(class json_io & msg, word base) override;
    void AppWebsocketMessage(class json_io & msg, word base, const char * mt, const char * src) override;
    void AppWebsocketClosed() override;
    void AppWebsocketSendResult() override {};
    void TryClose();

public:
    LocalSession(class ApiRelay * instance, class IWebserverPlugin * webserverPlugin);
    ~LocalSession();

    void AppWebsocketMessageSend(class json_io & msg, char * buffer);
    void AppWebsocketMessageSendText(const char * buffer);
    void AppWebsocketMessageSendBinary(char * buffer, int len);
    void Close();

    bool connected;
    char * name;
    class ProvidedApiSet providedApis;
    bool consumedApis;
};
