#ifndef PAMVMCDIGMGR_H
#define PAMVMCDIGMGR_H
#include <iostream>

#include <TSystem.h>
#include <TMap.h>
#include <TObjString.h>
#include "PamVMCDigitizer.h"
#include "PamVMCTrkDig.h"
#include "PamVMCDigRunHeader.h"
#include "PamVMCDigRunTrailer.h"
#include "PamVMCTofDig.h"
#include "PamVMCAcDig.h"
#include "PamVMCCaloDig.h"
#include "PamVMCS4Dig.h"
#include "PamVMCNDDig.h"

class PamVMCDigMgr: public TObject {

 private:
 
  static PamVMCDigMgr * fdig;
  TMap fdigmap;

  /* This method calls only from manager. It is owner of all
   digitizer objects */
  void SetDIG(const char *name, PamVMCDigitizer *detDIG){
    fdigmap.Add(new TObjString(name),detDIG);
    fdigmap.Print();
  }
  

 protected:
  PamVMCDigMgr(UInt_t seed){
    //detectors should be ordered.. First calibrations
    SetDIG("Tof", new PamVMCTofDig(seed));
    SetDIG("AC", new PamVMCAcDig(seed));
    SetDIG("CAST",new PamVMCCaloDig(seed));
    SetDIG("TSPA", new PamVMCTrkDig(seed));
    SetDIG("S4",new PamVMCS4Dig(seed));
    SetDIG("NDTI",new PamVMCNDDig(seed));
//    SetDIG("RunHeader", new PamVMCDigRunHeader());
//    SetDIG("RunTrailer", new PamVMCDigRunTrailer());
  }

 public:

  ~PamVMCDigMgr(){ fdigmap.DeleteAll(); }
  
  static PamVMCDigMgr * Instance(UInt_t seed = 567);

  PamVMCDigitizer * GetDIG(const char *name){
    return (PamVMCDigitizer*)fdigmap(name);
  }

  /* All digitizers load calibrations and calibrate */
  void LoadCalib(){
    TMapIter *n= (TMapIter *)fdigmap.MakeIterator(); 
    TObject *o; while( o=(TObject *) n->Next()) { 
    ((PamVMCDigitizer *)fdigmap.GetValue(o))->LoadCalib();
    }
  }

  /* This calls digitization for all detector */
  void Digitize(Int_t EventNo, Int_t PrimaryPDG){
    TMapIter *n= (TMapIter *)fdigmap.MakeIterator(); 
    TObject *o; while( o=(TObject *) n->Next()) {
    ((PamVMCDigitizer *)fdigmap.GetValue(o))->Digitize();
    }
    
    TObject* ob1 = fdigmap.FindObject("Tof");
    if(ob1) ((PamVMCTofDig*)((TPair*)ob1)->Value())->DigitizeTOF(EventNo, PrimaryPDG);

    TObject* ob2 = fdigmap.FindObject("AC");
    if(ob2) ((PamVMCAcDig*)((TPair*)ob2)->Value())->DigitizeAC(EventNo);

    /* +++From this moment all detctors a filled their buffers an we will form packet+++ */

    TObject* b1 = fdigmap.FindObject("Tof");
    if(b1) ((PamVMCTofDig*)((TPair*)b1)->Value())->WriteToBuff();

    cout<<"TOF Written.."<<endl;

    TObject* b2 = fdigmap.FindObject("AC");
    if(b2) ((PamVMCAcDig*)((TPair*)b2)->Value())->WriteToBuff();
    
    cout<<"AC Written.."<<endl;

    TObject* b3 = fdigmap.FindObject("CAST");
    if(b3) ((PamVMCCaloDig*)((TPair*)b3)->Value())->WriteToBuff();  

    cout<<"CALO Written.."<<endl;

    TObject* b4 = fdigmap.FindObject("TSPA");
    if(b4) ((PamVMCTrkDig*)((TPair*)b4)->Value())->WriteToBuff();  

    cout<<"TRK Written.."<<endl;

    TObject* b5 = fdigmap.FindObject("S4");
    if(b5) ((PamVMCS4Dig*)((TPair*)b5)->Value())->WriteToBuff();  

    cout<<"S4 Written.."<<endl;

    TObject* b6 = fdigmap.FindObject("NDTI");
    if(b6) ((PamVMCNDDig*)((TPair*)b6)->Value())->WriteToBuff();  

    cout<<"ND Written.."<<endl;

  }

  /* This written for RunTrailer. It should put his data
     to raw-file only once, when run is over */
  void FinishRun(){
    TMapIter *n= (TMapIter *)fdigmap.MakeIterator(); 
    TObject *o; while( o=(TObject *) n->Next()) { 
    ((PamVMCDigitizer *)fdigmap.GetValue(o))->FinishRun();
    }
  }

  virtual void Print(const Option_t* = "") const { fdigmap.Print(); }

  void PrintCollections(){
    TMapIter *n= (TMapIter *)fdigmap.MakeIterator(); 
    TObject *o; while( o=(TObject *) n->Next()) { 
      ((PamVMCDigitizer *)fdigmap.GetValue(o))->PrintCollections();
    }
  }

};

#endif
