#include "zoo_sync.h"

#include <library/cpp/watchdog/lib/factory.h>

namespace {
    class TSwitcher : public NRTYServer::ISwitcher {
    private:
        class TLock : public ILock {
        private:
            const TSwitcher& Switcher;

        public:
            TLock(const TSwitcher& switcher)
                : Switcher(switcher)
            {
                Switcher.SwitchLock();
            }
            ~TLock() override {
                Switcher.SwitchUnlock();
            }
        };

    private:
        const TZooSynchronizer& Synchronizer;

    public:
        TSwitcher(const TZooSynchronizer& synchronizer)
            : Synchronizer(synchronizer)
        {
            Y_UNUSED(Synchronizer);
        }

        ILockPtr Lock() final {
            return MakeHolder<TLock>(*this);
        }

    private:
        void SwitchLock() const {
        }
        void SwitchUnlock() const {
        }
    };

    class TStorageChangesWatchDogHandle: public IWatchDogHandleFreq {
    private:
        const TZooSynchronizer& Synchronizer;
        ui32 Version = 0;

    public:
        TStorageChangesWatchDogHandle(const TZooSynchronizer& synchronizer)
            : IWatchDogHandleFreq(synchronizer.GetConfig().GetCheckIntervalSeconds())
            , Synchronizer(synchronizer)
        {
        }

        void DoCheck(TInstant /*timeNow*/) override {
            ui32 version;
            if (Synchronizer.GetGlobalBaseVersion(version)) {
                if (Version != version) {
                    NRTYServer::ISwitcherPtr switcher = MakeAtomicShared<TSwitcher>(Synchronizer);
                    SendGlobalMessage<TMessageBaseVersionChanged>(Version, version, switcher);
                    Version = version;
                }
            }
        }
    };
}

bool TZooSynchronizer::Start(const TStartContext& /*startContext*/) {
    Storage.Reset(NSaas::IVersionedStorage::Create(SyncConfig->StorageOptions));
    CHECK_WITH_LOG(Storage);
    WatchDogHandle.Reset(Singleton<TWatchDogFactory>()->RegisterWatchDogHandle(new TStorageChangesWatchDogHandle(*this)));
    RegisterGlobalMessageProcessor(this);
    return true;
}

bool TZooSynchronizer::Process(IMessage* message) {
    TRequestCurrentDatabaseVersion* messRequest = dynamic_cast<TRequestCurrentDatabaseVersion*>(message);
    if (messRequest) {
        ui32 version = 0;
        if (!GetGlobalBaseVersion(version))
            WARNING_LOG << "Can't receive information about last version" << Endl;
        messRequest->Version = version;
        return true;
    }
    return false;
}

bool TZooSynchronizer::Stop(const TStopContext& /*stopContext*/) {
    UnregisterGlobalMessageProcessor(this);
    WatchDogHandle.Destroy();
    Storage.Destroy();
    return true;
}

TDaemonModules::TFactory::TRegistrator<TZooSynchronizer> TZooSynchronizer::Registrator(NRTYServer::ZooSynchronizerModuleName);
TZooSynchronizerConfig::TFactory::TRegistrator<TZooSynchronizerConfig> TZooSynchronizerConfig::Registrator(NRTYServer::ZooSynchronizerModuleName);
