#ifndef OverbyteIcsSslMultiFtpServ1H
#define OverbyteIcsSslMultiFtpServ1H

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

#include "OverbyteIcsTypes.hpp"
#include "OverbyteIcsWSocket.hpp"
#include "OverbyteIcsWSocketS.hpp"
#include "OverbyteIcsWndControl.hpp"
#include "OverbyteIcsSslBase.hpp"
#include "OverbyteIcsFtpSrv.hpp"
#include "OverbyteIcsOneTimePw.hpp"
#include "OverbyteIcsSslX509Certs.hpp"
#include "OverbyteIcsMailQueue.hpp"
#include "OverbyteIcsSslHttpOAuth.hpp"
#include "OverbyteIcsSslUtils.hpp"

#include <memory>

const unsigned WM_STARTUP = WM_USER + 712;

class TGetProcessingThread;

class TMyClient : public TFtpCtrlSocket
{
public:
    TGetProcessingThread *FWorkerThread = nullptr;
    bool FWorkerCancelled = false;
    bool ReportSslCert = false;
    __fastcall virtual TMyClient(TComponent *AOwner) : TFtpCtrlSocket(AOwner) {}
    __fastcall virtual ~TMyClient();
};

class TGetProcessingThread : public TThread
{
public:
    TFtpServer *Server = nullptr;
    TMyClient *Client = nullptr;
    __fastcall TGetProcessingThread() : TThread(true) {}
protected:
    void __fastcall Execute() override;
};

class TFtpServerForm : public TForm
{
__published:
    TPanel *ToolsPanel;
    TMemo *DisplayMemo;
    TButton *StartButton;
    TButton *StopButton;
    TTimer *Timer1;
    TButton *RecheckCertsButton;
    TSslX509Certs *IcsSslX509Certs;
    TIcsMailQueue *IcsMailQueue;
    TSslFtpServer *SslFtpServer1;
    TIcsRestEmail *IcsRestEmail;
    void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall StartButtonClick(TObject *Sender);
    void __fastcall StopButtonClick(TObject *Sender);
    void __fastcall Timer1Timer(TObject *Sender);
    void __fastcall RecheckCertsButtonClick(TObject *Sender);
    void __fastcall IcsSslX509CertsCertProg(TObject *Sender, TLogOption LogOption, const String Msg);
    void __fastcall IcsSslX509CertsNewCert(TObject *Sender);
    void __fastcall IcsMailQueueLogEvent(TMailLogLevel LogLevel, const String Info);
    void __fastcall IcsSslX509CertsChallengeDNS(TObject *Sender, const TChallengeItem &ChallengeItem, bool &ChlgOK);
    void __fastcall IcsSslX509CertsChallgRefresh(TObject *Sender);
    void __fastcall SslFtpServer1ValidateRnFr(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &FilePath,
                                              bool &Allowed);
    void __fastcall SslFtpServer1AlterDirectory(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &Directory,
                                                bool Detailed);
    void __fastcall SslFtpServer1AnswerToClient(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &Answer);
    void __fastcall SslFtpServer1Authenticate(TObject *Sender, TFtpCtrlSocket *Client, TFtpString UserName,
                                              TFtpString Password, bool &Authenticated);
    void __fastcall SslFtpServer1BgException(TObject *Sender, Exception *E, bool &CanClose);
    void __fastcall SslFtpServer1BuildDirectory(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &Directory,
                                                bool Detailed);
    void __fastcall SslFtpServer1ChangeDirectory(TObject *Sender, TFtpCtrlSocket *Client, TFtpString Directory,
                                                 bool &Allowed);
    void __fastcall SslFtpServer1ClientCommand(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &Keyword,
                                               TFtpString &Params, TFtpString &Answer);
    void __fastcall SslFtpServer1ClientConnect(TObject *Sender, TFtpCtrlSocket *Client, System::Word AError);
    void __fastcall SslFtpServer1ClientDisconnect(TObject *Sender, TFtpCtrlSocket *Client, System::Word AError);
    void __fastcall SslFtpServer1Display(TObject *Sender, TFtpCtrlSocket *Client, TFtpString Msg);
    void __fastcall SslFtpServer1GetProcessing(TObject *Sender, TFtpCtrlSocket *Client, bool &DelayedSend);
    void __fastcall SslFtpServer1MakeDirectory(TObject *Sender, TFtpCtrlSocket *Client, TFtpString Directory,
                                               bool &Allowed);
    void __fastcall SslFtpServer1OtpGetPassword(TObject *Sender, TFtpCtrlSocket *Client, TFtpString UserName,
                                                String &UserPassword);
    void __fastcall SslFtpServer1OtpMethod(TObject *Sender, TFtpCtrlSocket *Client, TFtpString UserName,
                                           TOtpMethod &OtpMethod);
    void __fastcall SslFtpServer1Rein(TObject *Sender, TFtpCtrlSocket *Client, bool &Allowed);
    void __fastcall SslFtpServer1RetrDataSent(TObject *Sender, TFtpCtrlSocket *Client, TWSocket *Data,
                                              System::Word AError);
    void __fastcall SslFtpServer1RetrSessionClosed(TObject *Sender, TFtpCtrlSocket *Client, TWSocket *Data,
                                                   System::Word AError);
    void __fastcall SslFtpServer1RetrSessionConnected(TObject *Sender, TFtpCtrlSocket *Client, TWSocket *Data,
                                                      System::Word AError);
    void __fastcall SslFtpServer1SslHandshakeDone(TObject *Sender, System::Word ErrCode, TX509Base *PeerCert,
                                                  bool &Disconnect);
    void __fastcall SslFtpServer1SslServerName(TObject *Sender, TSslContext *&Ctx, TTlsExtError &ErrCode);
    void __fastcall SslFtpServer1SslVerifyPeer(TObject *Sender, int &Ok, TX509Base *Cert);
    void __fastcall SslFtpServer1Start(TObject *Sender);
    void __fastcall SslFtpServer1Stop(TObject *Sender);
    void __fastcall SslFtpServer1StorSessionConnected(TObject *Sender, TFtpCtrlSocket *Client, TWSocket *Data,
                                                      System::Word AError);
    void __fastcall SslFtpServer1ValidateDele(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &FilePath,
                                              bool &Allowed);
    void __fastcall SslFtpServer1ValidatePut(TObject *Sender, TFtpCtrlSocket *Client, TFtpString &FilePath,
                                             bool &Allowed);
    void __fastcall SslFtpServer1Host(TObject *Sender, TFtpCtrlSocket *Client, TFtpString Host, bool &Allowed);
    void __fastcall IcsRestEmailEmailNewToken(TObject *Sender);
    void __fastcall IcsRestEmailEmailProg(TObject *Sender, TLogOption LogOption, const String Msg);
    void __fastcall IcsMailQueueOATokenEvent(int ServNr, String &Token, String &TokAccount, TDateTime &TokExpireDT);

public:
    __fastcall TFtpServerForm(TComponent *Owner);
    __fastcall virtual ~TFtpServerForm();
    void Display(String Msg);
    void ReportHosts();
    String UnEscapeStr(const String &Buffer);
    __property String IniFileName = {read=FIniFileName, write=FIniFileName};

private:
    String FIniFileName;
    bool FFinalized = false;
    int FOtpSequence = 0;
    String FOtpSeed;
    String FAccountPath;
    String FWinLinesBuff;
    int FWinDispCur = 0;
    int FLogDate = 0;
    String FSrvCompName;
    String FStatSrvSslCert;
    __int64 FHouseKeepingTrg = 0;
    __int64 FCertCheckTrigger = 0;
    std::unique_ptr<TIcsBuffLogStream> FDiagLogBuffer;
    String FAdminEmailTo;
    String FLastErrorEmail;
    String FOldRefrToken;
    void __fastcall WorkerThreadTerminated(TObject *Sender);
    void __fastcall WMStartup(TMessage &Msg);
    void __fastcall ApplicationEventsException(TObject *Sender, Exception *E);
    void FlushDiagLog();
    void SetDefaultAccount(TFtpCtrlSocket *Client);
    void StartQueueMail();
    void StopQueueMail();
    void SendAdminEmail(const String &EmailTo, const String &Subject, const String &Body);

    BEGIN_MESSAGE_MAP
        VCL_MESSAGE_HANDLER(WM_STARTUP, TMessage, WMStartup)
    END_MESSAGE_MAP(TForm)
};

extern PACKAGE TFtpServerForm *FtpServerForm;

#endif
