#pragma once

#include <util/generic/ptr.h>
#include <util/generic/string.h>
#include <util/string/join.h>
#include <library/cpp/regex/pire/regexp.h>

#include <wmconsole/version3/wmcutil/regex.h>
#include <wmconsole/version3/protos/queries2.pb.h>
#include <wmconsole/version3/protos/querygroups.pb.h>

namespace NWebmaster {

struct TScanner {
    typedef TAtomicSharedPtr<TScanner> Ptr;

public:
    TScanner(const TDeque<TString> &partitions);
    Pire::Scanner Compile(const char* pattern);

public:
    Pire::Scanner Scanner;
};

struct TBatchMatcher {
    typedef TAtomicSharedPtr<TBatchMatcher> Ptr;

    TBatchMatcher(const NWebmaster::proto::querygroups::HostGroupInfo &groupInfo) {
        TDeque<TString> queries;

        for (int i = 0; i < groupInfo.queries_size(); i++) {
            const TString pattern = "^" + EscapePireRegex(groupInfo.queries(i).text()) + "$";
            queries.push_back(pattern);
        }

        TString filter = JoinSeq("|", queries);

        if (!filter.empty()) {
            Filters.push_back(filter);
        }
    }

    TBatchMatcher(const TDeque<TString> &filters)
        : Filters(filters)
    {
    }

    bool Matches(const char* ptr, size_t len) {
        if (Filters.empty()) {
            return false;
        }

        if (ScannerPtr.Get() == nullptr) {
            ScannerPtr.Reset(new TScanner(Filters));
        }

        Pire::Scanner::State state = Pire::Runner(ScannerPtr->Scanner)
            .Begin()                    // Начало строки
            .Run(ptr, len)              // Строка
            .End()                      // Конец строки
            .State();

        Accepted = ScannerPtr->Scanner.AcceptedRegexps(state);

        return Accepted.first != Accepted.second;
    }

    bool Matches(const TString &data) {
        return Matches(data.data(), data.size());
    }

public:
    TDeque<TString> Filters;
    TScanner::Ptr ScannerPtr;
    std::pair<const size_t*, const size_t*> Accepted;
};

} //namespace NWebmaster
