#pragma once
#include <afxmt.h>
#include <afxsock.h>

#include "ConcurrentQueue.h"

#ifdef BUILD_COMMDLL
#define COMMDLL_DLLCLASS __declspec(dllexport)
#else
#define COMMDLL_DLLCLASS __declspec(dllimport)
#endif

class IBufferSocketCallBack
{
public:
    virtual void OnReceive(const char* buffer, int len) = 0;
    virtual void OnDisconnect(int errorCode)            = 0;
};

class COMMDLL_DLLCLASS CBufferedSocket
{
    // Forward declaration of internal classes
public:
    class CBufferedSocketMessage;
    class CBufferMessageThread;
    class CReceivingThread;
    class CSenderThread;
    class CInternalMessageThread;
    friend class CInternalMessageThread;
    friend class CReceivingThread;
    friend class CSenderThread;

    // Private fields
private:
    CConcurrentQueue<CBufferedSocketMessage>* m_pMessageQueue;
    CConcurrentQueue<CBufferedSocketMessage>* m_pSendQueue;
    CBufferMessageThread*                     m_pMessageThread;
    CBufferMessageThread*                     m_PSenderThread;
    IBufferSocketCallBack*                    m_pCallBack;
    CReceivingThread*                         m_pReceivingThread;
    CEvt*                                     m_hConnectedEvent;
    SOCKET                                    s;
    bool                                      bIsConnected;

    // Private methods
protected:
    void OnReceive(const char* buf, size_t len);
    void OnDisconnect(int errorCode);
    int  Read(char* buf, size_t size);
    int  Write(const char* buf, size_t len);

private:
    CBufferedSocket(const CBufferedSocket&);
    // Public methods
public:
    CBufferedSocket(IBufferSocketCallBack* pCallBack);
    ~CBufferedSocket(void);
    void ProcessMessage(CBufferedSocketMessage& message);
    void Close();
    bool Connect(const char* IpAddress, int port);
    bool Send(const char* buf, size_t len, int milliSeconds = INFINITE);
    bool IsConnected()
    {
        return bIsConnected;
    }

    bool WaitConnected();
    bool WaitConnected(int milliseconds);
    /* returns the percentage representing how full the send queue is */
    double SendQueueFullState();
};
