/*++

Program name:

 dm

Module Name:

  WebSocketClient.hpp

Notices:

  WebSocket Client

Author:

  Copyright (c) Prepodobny Alen

  mailto: alienufo@inbox.ru
  mailto: ufocomp@gmail.com

--*/

#ifndef APOSTOL_WEB_SOCKET_CLIENT_HPP
#define APOSTOL_WEB_SOCKET_CLIENT_HPP
//----------------------------------------------------------------------------------------------------------------------

extern "C++" {

namespace Apostol {

    namespace Client {

        //--------------------------------------------------------------------------------------------------------------

        //-- CWebSocketClient ------------------------------------------------------------------------------------------

        //--------------------------------------------------------------------------------------------------------------

        typedef std::function<void (CObject *Sender, const CWSMessage &Request, const CWSMessage &Response)> COnWebSocketClientEvent;
        //--------------------------------------------------------------------------------------------------------------

        class CWebSocketClient: public CCustomWebSocketClient {
        private:

            CContext *m_pContext;

            int m_SendCount;

            bool m_Authorized;

            int m_HeartbeatInterval;

            CDateTime m_PingDateTime;
            CDateTime m_PongDateTime;
            CDateTime m_HeartbeatDateTime;
            CDateTime m_RegistrationDateTime;

            TList<CWSMessage> m_MessageList;

            COnWebSocketClientEvent m_OnAuthorizeEvent;
            COnWebSocketClientEvent m_OnSubscribeEvent;
            COnWebSocketClientEvent m_OnKeyEvent;
            COnWebSocketClientEvent m_OnWebSocketEvent;

            void CheckCallError(const CWSMessage &Error, const CWSMessage &Message);

            void PushMessageList();

        protected:

            void Heartbeat(CDateTime Now) override;

            void DoPing(CObject *Sender) override;
            void DoPong(CObject *Sender) override;

            void DoAuthorizeEvent(const CWSMessage &Request, const CWSMessage &Response);
            void DoSubscribeEvent(const CWSMessage &Request, const CWSMessage &Response);
            void DoKeyEvent(const CWSMessage &Request, const CWSMessage &Response);
            void DoWebSocketEvent(const CWSMessage &Request, const CWSMessage &Response);

        public:

            CWebSocketClient();
            explicit CWebSocketClient(CContext *Context, const CLocation &URI);

            bool Authorized() const;

            void Authorize();
            void Subscribe();
            void UpdateKey();

            void Send(const CString &Action, const CJSON &Payload, COnMessageHandlerEvent &&Handler = nullptr);

            void Reload();

            CContext *Context() const { return m_pContext; }

            const COnWebSocketClientEvent &OnAuthorize() const { return m_OnAuthorizeEvent; }
            void OnAuthorize(COnWebSocketClientEvent && Value) { m_OnAuthorizeEvent = Value; }

            const COnWebSocketClientEvent &OnSubscribe() const { return m_OnSubscribeEvent; }
            void OnSubscribe(COnWebSocketClientEvent && Value) { m_OnSubscribeEvent = Value; }

            const COnWebSocketClientEvent &OnKey() const { return m_OnKeyEvent; }
            void OnKey(COnWebSocketClientEvent && Value) { m_OnKeyEvent = Value; }

            const COnWebSocketClientEvent &OnWebSocketEvent() const { return m_OnWebSocketEvent; }
            void OnWebSocketEvent(COnWebSocketClientEvent && Value) { m_OnWebSocketEvent = Value; }

        };

        //--------------------------------------------------------------------------------------------------------------

        //-- CWebSocketClientItem --------------------------------------------------------------------------------------

        //--------------------------------------------------------------------------------------------------------------

        class CWebSocketClientManager;
        //--------------------------------------------------------------------------------------------------------------

        class CWebSocketClientItem: public CCollectionItem, public CWebSocketClient {
        public:

            explicit CWebSocketClientItem(CWebSocketClientManager *AManager);

            explicit CWebSocketClientItem(CWebSocketClientManager *AManager, CContext *Context, const CLocation &URI);

        };

        //--------------------------------------------------------------------------------------------------------------

        //-- CWebSocketClientManager -----------------------------------------------------------------------------------

        //--------------------------------------------------------------------------------------------------------------

        class CWebSocketClientManager: public CCollection {
            typedef CCollection inherited;

        protected:

            CWebSocketClientItem *GetItem(int Index) const override;

        public:

            CWebSocketClientManager(): CCollection(this) {

            };

            ~CWebSocketClientManager() override = default;

            CWebSocketClientItem *Add(CContext *Context, const CLocation &URI);

            CWebSocketClientItem *First() const { return GetItem(0); };
            CWebSocketClientItem *Last() const { return GetItem(GetCount() - 1); };

            CWebSocketClientItem *Items(int Index) const override { return GetItem(Index); };

            CWebSocketClientItem *operator[] (int Index) const override { return Items(Index); };

        };

    }
}

using namespace Apostol::Client;
}

#endif //APOSTOL_WEB_SOCKET_CLIENT_HPP
