#pragma once

#include "containers.h"

#include <saas/util/queue.h>
#include <library/cpp/regex/pire/pire.h>

#include <util/generic/set.h>
#include <util/generic/string.h>
#include <util/system/mutex.h>
#include <util/system/event.h>
#include <util/charset/wide.h>
#include <utility>

namespace NRtyInfraTests {

    class TMachine {
    public:
        void Run(const TScriptData& script);
        void WriteOut(const TString& message);
    private:
        inline TString MakeMessage(const TCommand& command, const TString& message);
        inline void DoLogMessage(const TCommand& command, const TString& message);
    private:
        TRTYMtpQueue MainQueue;
        TMutex OutputMutex;
        typedef THashMap<TString, TSimpleSharedPtr<TSystemEvent> > TWaitMap;
        TWaitMap WaitMap;

        static const TString WAIT;
    };


    class TBasicWorker : public IObjectInQueue {
    public:
        TBasicWorker(const TScriptData &script, const TCommand &command);
        virtual ~TBasicWorker();
    protected:
        const TScriptData &Script;
        const TCommand &Command;
        const TAttrs& Objective;
    };

    class TGenericWorkerData : public TBasicWorker {
    public:
        TGenericWorkerData(const TScriptData &script, const TCommand &command);
        virtual ~TGenericWorkerData();
        virtual void Process(void*);
    public:
        typedef std::pair<bool, TString> TTestResult;
    protected:
        TString LogLabel;
        bool FailsTest;
        int ExpectedCode;
        int AttemptsNumber;
        ui64 AttemptsInterval;
    protected:
        virtual TTestResult ProcessImpl();
        NPire::TSimpleScanner AnswerRegex;
        virtual void CompileRegex(TString value);
        virtual bool IsMatchRegex(TString value);
    };

    class THttpWorkerData {
    public:
        THttpWorkerData(){}
        THttpWorkerData(ui16 port, const TString& url, const TString& host = "localhost");
        virtual ~THttpWorkerData();
    protected:
        ui16 Port;
        TString Url
             , Host;
    protected:
        TString SendGet(TString& answer);
    };


    class TGetWorker : public TGenericWorkerData, public THttpWorkerData {
    public:
        TGetWorker(const TScriptData &script, const TCommand &command);
        virtual ~TGetWorker();
    protected:
        virtual TTestResult ProcessImpl();
    };


    class TSyscomWorker : public TGenericWorkerData {
    public:
        TSyscomWorker(const TScriptData &script, const TCommand &command);
        virtual ~TSyscomWorker();
    protected:
        virtual TTestResult ProcessImpl();
        TString SystemCommand;
    };

    class TMainWorker : public TBasicWorker {
    public:
        TMainWorker(const TScriptData &script, const TCommand &command, TSystemEvent *event = nullptr);
        virtual ~TMainWorker();
        virtual void Process(void*);
        virtual const TMainWorker& SetEvent(TSystemEvent *event);
    protected:
        IObjectInQueue* CreateSpecificWorker(const TString& type);
    protected:
        TRTYMtpQueue ObjectQueue;
        TSystemEvent *IsDone;
    protected:
        const TString& Name
                   ,& Id;
    public:
        static const TString TYPE;
        static const TString SYSTEM;
        static const TString GET;
    };
}
