#ifndef VIS_HELPERS_H
#define VIS_HELPERS_H

#include <TSystem.h>
#include <TEvePointSet.h>
#include <TTree.h>
#include <vector>
#include <mutex>

static TEvePointSet* gVisPts = nullptr;
static std::mutex gVisMutex;

// Recommended: call once after opening TEve and adding a point set to gEve
inline void SetVisPointSet(TEvePointSet* pts) { gVisPts = pts; }

inline void UpdateVisPointSet(const std::vector<double>& x,
                              const std::vector<double>& y,
                              const std::vector<double>& z)
{
  if(!gVisPts) return;
  std::lock_guard<std::mutex> lk(gVisMutex);
  gVisPts->Reset();
  size_t n = std::min({x.size(), y.size(), z.size()});
  for(size_t i=0; i<n; ++i) gVisPts->SetNextPoint(x[i], y[i], z[i]);
  if(gEve) {
    gEve->Redraw3D();
    gSystem->ProcessEvents();
  }
}

// Fill a tree with pointlists (one entry per event); must have branches defined once by caller
inline void RecordTreeXYZ(TTree* outTree,
                           const std::vector<double>& x,
                           const std::vector<double>& y,
                           const std::vector<double>& z)
{
  if(!outTree) return;
  static std::vector<double> tx, ty, tz;
  tx = x;
  ty = y;
  tz = z;

  if(outTree->GetBranch("x") == nullptr) outTree->Branch("x", &tx);
  if(outTree->GetBranch("y") == nullptr) outTree->Branch("y", &ty);
  if(outTree->GetBranch("z") == nullptr) outTree->Branch("z", &tz);

  // Do NOT call SetBranchAddress() for the branch we are filling.
  outTree->Fill();
  outTree->GetCurrentFile()->Flush();
}

inline void PushEventAndRecord(const std::vector<double>& x,
                               const std::vector<double>& y,
                               const std::vector<double>& z,
                               TTree* outTree = nullptr)
{
  if(outTree) RecordTreeXYZ(outTree, x, y, z);
  UpdateVisPointSet(x,y,z);
}

#endif // VIS_HELPERS_H
