#include "shared_file_rereader.h"

namespace NSrvKernel {

    namespace Internal {

        TFileUpdater::TFileUpdater(TString path)
            : Filename_(std::move(path))
        {}

        TFileUpdater::TFileUpdater(TString path, TData data)
            : Filename_(std::move(path))
            , Data_(std::move(data))
        {}

        void TFileUpdater::Update() noexcept {
            // open file and do the processing
            try {
                if (UpdateFileStat()) {
                    UpdateFileData();
                }
            } catch (...) {
            }
        }

        bool TFileUpdater::UpdateFileStat() {
            TFileStat next = TFileManager::Instance().GetStat(Filename_);
            if (next.MTime != Stat_.MTime
                || next.CTime != Stat_.CTime
                || next.INode != Stat_.INode
                || next.Size != Stat_.Size)
            {
                Stat_ = next;
                return true;
            }

            return false;
        }

        void TFileUpdater::UpdateFileData() {
            if (Stat_.NLinks) {
                THolder<IInputStream> in = TFileManager::Instance().GetInput(Filename_);
                Y_VERIFY(in);
                Data_.Update(in->ReadAll());
            } else {
                Data_.Update(Nothing());
            }
        }

    }

    TReReadTask::TReReadTask(TString path)
        : FileUpdater_(std::move(path))
        , DataStorage_(MakeIntrusive<Internal::TData>(FileUpdater_.Data()))
    {}

    THotSwap<Internal::TData>::TPtr TReReadTask::GetData() {
        return DataStorage_.AtomicLoad();
    }

    bool TReReadTask::Process() {
        FileUpdater_.Update();
        if (FileUpdater_.Data().Id() != GetData()->Id()) {
            DataStorage_.AtomicStore(MakeIntrusive<Internal::TData>(FileUpdater_.Data()));
        }
        return true;
    }

    TSharedFileReReader::TSharedFileReReader(TIntrusivePtr<TReReadTask> reReadTask) noexcept
        : ReReadTask_(std::move(reReadTask))
    {}

    const TSharedFileReReader::TData& TSharedFileReReader::Data() const noexcept {
        if (ReReadTask_) {
            auto dataPtr = ReReadTask_->GetData();
            if (Data_.Id() != dataPtr->Id()) {
                Data_ = *dataPtr;
            }
        }
        return Data_;
    }

    bool TSharedFileReReader::Empty() const noexcept {
        return ReReadTask_ ? false : true;
    }

}  // namespace NSrvKernel
