#ifndef vtk_m_tracer_h
#define vtk_m_tracer_h

#include <chrono>
#include <fstream>
#include <iostream>
#include <mutex>
#include <sstream>
#include <vector>

#include <vtkm/cont/Timer.h>
#include <vtkm/filter/flow/vtkm_filter_flow_export.h>

namespace vtkm
{
namespace filter
{
namespace flow
{

class Buffer
{
public:
  //the step of the simulation, it might contains multiple step
  //this value is set by reader

  //std::vector<char> bufferTime;
  //std::vector<char> bufferCounter;

  std::stringstream bufferTime;
  std::stringstream bufferCounter;
  std::stringstream bufferTerminatedParticles;
  std::stringstream bufferParticlesInBlock;
  std::stringstream bufferParticleDetailsInBlock;


  //the start point of the timer is the reader's program
  vtkm::cont::Timer timer;
  std::chrono::time_point<std::chrono::steady_clock> InitTime;

  int m_iterationStep;
  int m_tracingParticleId = -1;
  int m_rank=-1;
  bool m_iftracingParticle=false;
};

class VTKM_FILTER_FLOW_EXPORT Tracer
{

public:
  VTKM_FILTER_FLOW_EXPORT Tracer(){};

  VTKM_FILTER_FLOW_EXPORT void Init(int rank);

  VTKM_FILTER_FLOW_EXPORT void StartTimer();

  VTKM_FILTER_FLOW_EXPORT void ResetIterationStep(int step);

  VTKM_FILTER_FLOW_EXPORT void OutputBuffer(int rank);

  //the particle advection may contains multiple round in one operation
  //which round it is now
  VTKM_FILTER_FLOW_EXPORT
  vtkm::Id TimeTraceToBuffer(const std::string& nm);

  VTKM_FILTER_FLOW_EXPORT
  void CounterToBuffer(vtkm::Id round,
                       vtkm::Id AdvectedSteps,
                       std::unordered_map<int, int> sendParticleInfo);

  VTKM_FILTER_FLOW_EXPORT
  void ParticleToBuffer(vtkm::Id simCycle,
                        vtkm::Id particleID,
                        char removedReason,
                        vtkm::FloatDefault activeTime,
                        vtkm::Id numComm,
                        vtkm::Id traversedNumofBlocks) const;

  VTKM_FILTER_FLOW_EXPORT vtkm::Id GetElapsedTime() const;

  VTKM_FILTER_FLOW_EXPORT void Finalize();

  VTKM_FILTER_FLOW_EXPORT int GetIterationStep() const;

  VTKM_FILTER_FLOW_EXPORT void ParticleInBlockToBuffer(vtkm::Id simCycle,
                                                       vtkm::Id rank,
                                                       vtkm::Id particleID,
                                                       vtkm::Id numAdvecSteps,
                                                       const vtkm::Vec3f& pos,
                                                       vtkm::FloatDefault aliveTime) const;

  VTKM_FILTER_FLOW_EXPORT void SetTraceParticleId(int particleId) const;

  VTKM_FILTER_FLOW_EXPORT int GetTraceParticleId() const;

  VTKM_FILTER_FLOW_EXPORT void ParticleDetailsToBuffer(vtkm::Id simCycle,
                                                       vtkm::Id rank,
                                                       vtkm::Id particleID,
                                                       const std::string& Event,
                                                       vtkm::FloatDefault currTime,
                                                       vtkm::Id AdvectedSteps, vtkm::Id pnum) const;

  VTKM_FILTER_FLOW_EXPORT bool IfTracingCustomized(vtkm::Id pid) const;

VTKM_FILTER_FLOW_EXPORT void SetBegOverheadStart() { this->BegOverhead[0] = this->GetElapsedTime();} // this->BegOverhead[1] = -10000; } //this->BegOverhead[0];}
  VTKM_FILTER_FLOW_EXPORT void SetBegOverheadEnd() { this->BegOverhead[1] = this->GetElapsedTime();}
  VTKM_FILTER_FLOW_EXPORT void SetEndOverheadStart() { this->EndOverhead[0] = this->GetElapsedTime();}
  VTKM_FILTER_FLOW_EXPORT void SetEndOverheadEnd() { this->EndOverhead[1] = this->GetElapsedTime();}
  VTKM_FILTER_FLOW_EXPORT void SetAdvectStart()
  {
    this->Advect[0] = this->TimeTraceToBuffer("WORKLET_Start");
  }
  VTKM_FILTER_FLOW_EXPORT void SetAdvectEnd()
  {
    this->Advect[1] = this->TimeTraceToBuffer("WORKLET_End");
  }

  //particle timers.
vtkm::Id2 BegOverhead = {0,0}, EndOverhead = {0,0}, Advect = {0,0};

  VTKM_FILTER_FLOW_EXPORT bool SetTracingStatus(bool iftracing) const;

  VTKM_FILTER_FLOW_EXPORT bool GetTracingStatus() const;

  VTKM_FILTER_FLOW_EXPORT int GetRankID() const;
};


/*

VTKM_EXEC void
IncCounter(const std::string& nm, int iterationStep, int rank, uint num);

VTKM_EXEC
void ParticleCounter(const std::string& nm,
                     int iterationStep,
                     int rank,
                     uint numActive,
                     uint numInactive,
                     uint numTerminated);

VTKM_EXEC
void DestProcLog(const std::string& nm,
                 int iterationStep,
                 int myrank,
                 uint sendIndex,
                 uint sendTotalNum,
                 uint destrank,
                 uint particleNum);

VTKM_EXEC
void VectorCounter(const std::string& nm, int iterationStep, int rank, std::vector<int> numbers);
*/

}
}
}

#endif
