/* Copyright (C) 2024 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Sergei Zharko [committer] */

/// \file   Data.cxx
/// \date   12.02.2024
/// \brief  A unified data-structure to handle QA objects for the online reconstruction (implementation)
/// \author Sergei Zharko <s.zharko@gsi.de>

#include "QaData.h"

#include <algorithm>

using cbm::algo::qa::Data;


// ---------------------------------------------------------------------------------------------------------------------
//
void Data::Init(std::shared_ptr<HistogramSender> histSender)
try {
  if (histSender.get()) {
    // Forming a histogram config message
    std::vector<std::pair<std::string, std::string>> vHistCfgs;
    size_t nHistograms = 0;
    // NOTE: Important to keep the order of filling the histograms: 1D -> 2D -> ..
    nHistograms += std::distance(fHistograms.fvH1.begin(), fHistograms.fvH1.end());
    nHistograms += std::distance(fHistograms.fvH2.begin(), fHistograms.fvH2.end());
    nHistograms += std::distance(fHistograms.fvP1.begin(), fHistograms.fvP1.end());
    nHistograms += std::distance(fHistograms.fvP2.begin(), fHistograms.fvP2.end());
    vHistCfgs.reserve(nHistograms);

    for (const auto& task: fvTaskProperties) {
      auto RegHist = [&](const auto& h) {
        if (!h.GetMetadata().CheckFlags()) {
          std::stringstream msg;
          msg << "attempt to pass a histogram " << h.GetName()
              << " with inconsistent flags (see HistogramMetadata::CheckFlags for detailes)";
          throw std::runtime_error(msg.str());
        }
        vHistCfgs.emplace_back(h.GetName() + "!" + h.GetMetadataString(), task.fsName);
      };
      fsTaskNames += fmt::format("{} ", task.fsName);
      std::for_each(task.fRangeH1.first, task.fRangeH1.second, RegHist);
      std::for_each(task.fRangeH2.first, task.fRangeH2.second, RegHist);
      std::for_each(task.fRangeP1.first, task.fRangeP1.second, RegHist);
      std::for_each(task.fRangeP2.first, task.fRangeP2.second, RegHist);
    }

    // Forming a canvas config message
    std::vector<std::pair<std::string, std::string>> vCanvCfgs;
    vCanvCfgs.reserve(fvsCanvCfgs.size());
    for (const auto& canv : fvsCanvCfgs) {
      vCanvCfgs.emplace_back(std::make_pair(canv.substr(0, canv.find_first_of(';')), canv));
    }

    histSender->PrepareAndSendMsg(std::pair<uint32_t, uint32_t>(vHistCfgs.size(), vCanvCfgs.size()),
                                  zmq::send_flags::sndmore);

    auto RegCfg = [&](const auto& cfg) { histSender->PrepareAndSendMsg(cfg, zmq::send_flags::sndmore); };

    std::for_each(vHistCfgs.begin(), vHistCfgs.end(), RegCfg);
    std::for_each(vCanvCfgs.begin(), vCanvCfgs.end(), RegCfg);

    // Histograms serialization and emission to close multi-part message
    histSender->PrepareAndSendMsg(qa::HistogramContainer{}, zmq::send_flags::none);
  }
}
catch (const std::exception& err) {
  L_(fatal) << "cbm::algo::qa::Data for " << fsTaskNames << " fatally aborted. Reason " << err.what();
  assert(false);
}

// ---------------------------------------------------------------------------------------------------------------------
//
void Data::RegisterNewTask(std::string_view name)
{
  auto itH1 = fHistograms.fvH1.begin();
  auto itH2 = fHistograms.fvH2.begin();
  auto itP1 = fHistograms.fvP1.begin();
  auto itP2 = fHistograms.fvP2.begin();
  fvTaskProperties.emplace_back(TaskProperties{
    .fsName   = {name.begin(), name.end()},
    .fRangeH1 = std::make_pair(itH1, itH1),
    .fRangeH2 = std::make_pair(itH2, itH2),
    .fRangeP1 = std::make_pair(itP1, itP1),
    .fRangeP2 = std::make_pair(itP2, itP2)
  });
}

// ---------------------------------------------------------------------------------------------------------------------
//
void Data::Send(std::shared_ptr<HistogramSender> histoSender)
{
  histoSender->PrepareAndSendMsg(fHistograms, zmq::send_flags::none);
  auto nH1 = std::distance(fHistograms.fvH1.begin(), fHistograms.fvH1.end());
  auto nH2 = std::distance(fHistograms.fvH2.begin(), fHistograms.fvH2.end());
  auto nP1 = std::distance(fHistograms.fvP1.begin(), fHistograms.fvP1.end());
  auto nP2 = std::distance(fHistograms.fvP2.begin(), fHistograms.fvP2.end());
  L_(info) << fsTaskNames << ": Published " << nH1 << " 1D- and " << nH2 << " 2D-histograms, " << nP1 << " 1D- and " << nP2
           << " 2D-profiles";
  this->Reset();
}