#ifndef OverbyteIcsThrdSrvV2_1H
#define OverbyteIcsThrdSrvV2_1H

#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>

#include "OverbyteIcsWSocket.hpp"
#include "OverbyteIcsWSocketS.hpp"
#include "OverbyteIcsWndControl.hpp"
#include "OverbyteIcsIniFiles.hpp"
#include "OverbyteIcsTypes.hpp"

#include <atomic>
#include <mutex>
#include <vector>

const unsigned WM_APPSTARTUP = WM_USER + 1;
const unsigned WM_UNLEASH_THREAD = WM_USER + 2;

typedef void __fastcall (__closure *TDisplayProc)(const String &Msg);

class TClientThread : public TThread
{
public:
    TClientThread(TWSocket *WSocket, TDisplayProc OnDisplay);
    __fastcall ~TClientThread();
    void Display(const String &Msg);
    void Unleash();
    void RequestStop();
    bool WaitForStop(DWORD TimeoutMs);
    std::atomic<bool> ThreadAttached;

protected:
    void __fastcall Execute() override;

private:
    TWSocket *FWSocket;
    TDisplayProc FOnDisplay;
    String FMsg;
    HANDLE FStartGate;
    HANDLE FStopEvent;
    void __fastcall DisplayMsg();
};

class TThrdSrvClient : public TWSocketClient
{
public:
    __fastcall virtual TThrdSrvClient(TComponent *AOwner) : TWSocketClient(AOwner) {}
    __fastcall virtual ~TThrdSrvClient();
    void StopThread();
    virtual void __fastcall StartConnection();
    TClientThread *ClientThread = nullptr;
    String RcvdLine;
    TDateTime ConnectTime;

protected:
    virtual void __fastcall WndProc(TMessage &MsgRec);
    virtual int __fastcall MsgHandlersCount();
    virtual void __fastcall AllocateMsgHandlers();
    virtual void __fastcall FreeMsgHandlers();
    void __fastcall WMStartCnx(TMessage &Msg);

private:
    unsigned FMsgStartCnx = 0;
};

struct TWhoEntry
{
    TObject *Client;
    String Addr;
    String Port;
    TDateTime ConnectTime;
};

class TTcpSrvForm : public TForm
{
__published:
    TPanel *ToolPanel;
    TMemo *DisplayMemo;
    TWSocketServer *WSocketServer1;
    void __fastcall FormShow(TObject *Sender);
    void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall WSocketServer1ClientConnect(TObject *Sender, TWSocketClient *Client, System::Word Error);
    void __fastcall WSocketServer1ClientDisconnect(TObject *Sender, TWSocketClient *Client, System::Word Error);
    void __fastcall WSocketServer1BgException(TObject *Sender, Exception *E, bool &CanClose);
    void __fastcall WSocketServer1ClientCreate(TObject *Sender, TWSocketClient *Client);

protected:
    void __fastcall WMAppStartup(TMessage &Msg);
    void __fastcall WMUnleashThread(TMessage &Msg);

    BEGIN_MESSAGE_MAP
        VCL_MESSAGE_HANDLER(WM_APPSTARTUP, TMessage, WMAppStartup)
        VCL_MESSAGE_HANDLER(WM_UNLEASH_THREAD, TMessage, WMUnleashThread)
    END_MESSAGE_MAP(TForm)

private:
    String FIniFileName;
    bool FInitialized = false;
    std::mutex FWhoMutex;
    std::vector<TWhoEntry> FWho;

    void __fastcall Display(const String &Msg);
    void __fastcall ClientDataAvailable(TObject *Sender, System::Word Error);
    void ProcessData(TThrdSrvClient *Client);
    void __fastcall ClientBgException(TObject *Sender, Exception *E, bool &CanClose);
    void __fastcall ClientLineLimitExceeded(TObject *Sender, int Cnt, bool &ClearData);

public:
    __fastcall TTcpSrvForm(TComponent *Owner);
    __fastcall ~TTcpSrvForm();
    __property String IniFileName = {read = FIniFileName, write = FIniFileName};
};

extern PACKAGE TTcpSrvForm *TcpSrvForm;

#endif
