/* Copyright (C) 2010-2021 Frankfurt Institute for Advanced Studies, Goethe-Universität Frankfurt, Frankfurt
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Igor Kulakov [committer], Maksym Zyzak, Valentina Akishina */

#include "CaFramework.h"

#include "CaGridEntry.h"
// #include "CaToolsDebugger.h"

using namespace cbm::algo::ca;

namespace
{
  using namespace cbm::algo;  // to keep ca:: prefices in the code
}

Framework::Framework()
{

}

using cbm::algo::ca::ECounter;  // monitor counter key type
using cbm::algo::ca::EDetectorID;
using cbm::algo::ca::ETimer;  // monitor timer key type
//using cbm::ca::tools::Debugger;

// ---------------------------------------------------------------------------------------------------------------------
//
void Framework::Init(const TrackingMode mode)
{
  fTrackingMode = mode;
  for (int iThread = 0; iThread < fNofThreads; ++iThread) {
    fvWData.emplace_back();
    fvMonitorDataThread.emplace_back();
  }
  for (int iThread = 0; iThread < fNofThreads; ++iThread) {
    fvTrackFinderWindow.emplace_back(*this, fvWData[iThread], fvMonitorDataThread[iThread]);
  }
  fTrackFinder.Init();
}

// ---------------------------------------------------------------------------------------------------------------------
//
void Framework::Finish()
{
  //Debugger::Instance().Write();
}

// ---------------------------------------------------------------------------------------------------------------------
//
void Framework::ReceiveInputData(InputData&& inputData)
{
  // ----- Get input data ----------------------------------------------------------------------------------------------
  fInputData = std::move(inputData);
}


// ---------------------------------------------------------------------------------------------------------------------
//
void Framework::ReceiveParameters(Parameters<fvec>&& parameters)
{
  fParameters = std::move(parameters);

  fNstationsBeforePipe = fParameters.GetNstationsActive(static_cast<EDetectorID>(0));

  // FIXME: SZh 24.08.2022
  //        This approach is suitable only for a case, when all the stations inside a magnetic field come right before
  //        all the stations outside of the field!
  fNfieldStations = std::lower_bound(fParameters.GetStations().cbegin(),
                                     fParameters.GetStations().cbegin() + fParameters.GetNstationsActive(),
                                     0,  // we are looking for the first zero element
                                     [](const ca::Station<fvec>& s, int edge) { return bool(s.fieldStatus) > edge; })
                    - fParameters.GetStations().cbegin();


  ca::FieldRegion<fvec>::ForceUseOfOriginalField(fParameters.DevIsUseOfOriginalField());
}

int Framework::GetMcTrackIdForCaHit(int /*iHit*/) const
{
  return -1;
  /*
  int hitId    = iHit;
  int iMcPoint = CbmL1::Instance()->GetHitBestMcRefs()[hitId];
  if (iMcPoint < 0) return -1;
  return CbmL1::Instance()->GetMcPoints()[iMcPoint].ID;
  */
}

int Framework::GetMcTrackIdForWindowHit(int /*iHit*/) const
{
  return -1;
  /*
  int hitId    = fWindowHits[iHit].Id();
  int iMcPoint = CbmL1::Instance()->GetHitBestMcRefs()[hitId];
  if (iMcPoint < 0) return -1;
  return CbmL1::Instance()->GetMcPoints()[iMcPoint].ID;
  */
}

/*
const CbmL1MCTrack* Framework::GetMcTrackForWindowHit(int iHit) const
{
  return nullptr;
  int id = GetMcTrackIdForWindowHit(iHit);
  if (id < 0) return nullptr;
  return &CbmL1::Instance()->GetMcTracks()[id];
}
*/

//   bool Framework::SortTrip(TripSort const& a, TripSort const& b) {
//       return   ( a.trip.GetLevel() >  b.trip.GetLevel() );
// }
//
// bool Framework::SortCand(CandSort const& a, CandSort const& b) {
//     if (a.cand.Lengtha != b.cand.Lengtha) return (a.cand.Lengtha > b.cand.Lengtha);
//
//     if (a.cand.ista != b.cand.ista ) return (a.cand.ista  < b.cand.ista );
//
//     if (a.cand.chi2  != b.cand.chi2 )return (a.cand.chi2  < b.cand.chi2 );
//     //return (a->chi2  < b->chi2 );
//     //   return (a->CandIndex < b->CandIndex );
//    // return (a.cand.CandIndex > b.cand.CandIndex );
// }

//   inline int Framework::PackIndex(const int& a, const int& b, const int& c) {
//       return   (a) + ((b)*10000) + (c*100000000);
// }
//
//   inline int Framework::UnPackIndex(const int& i, int& a, int& b, int& c) {