#ifndef PAMVMCDIGMGR_H
#define PAMVMCDIGMGR_H
#include <iostream>

#include <TSystem.h>
#include <TMap.h>
#include <TObjString.h>
#include "PamVMCDigitizer.h"
#include "PamVMCTrkDig.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;
  

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

  PamVMCDigMgr(TString ext){
    cout<<"External PamVMCDiG constructor called "<<ext<<endl;
  }


 public:

  ~PamVMCDigMgr(){ fdigmap.DeleteAll(); }
  
  static PamVMCDigMgr * Instance();
  static PamVMCDigMgr * Instance_ext();

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

  /* Setting pointer to random objects for all Digitizers */
  /* All digitizers load calibrations and calibrate */
  void Initialize(TRandom3* random){
    TMapIter *n= (TMapIter *)fdigmap.MakeIterator(); 
    TObject *o; while( (o=(TObject *) n->Next())) { 
    ((PamVMCDigitizer *)fdigmap.GetValue(o))->LoadCalib();
    if(!random->GetSeed()){
      cout<<"DigMgr: creating a random object, wait 1.5 s"<<endl;
      gSystem->Sleep(1500);
    }
    ((PamVMCDigitizer *)fdigmap.GetValue(o))->SetRandom(random);
    }
    delete n;
  }
  
  /* 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();
  }


  /*This method set up a random object for specific detector digitizer*/
  void SetRandom(const char *name, TRandom3* random){
    PamVMCDigitizer * dig = GetDIG(name);
    if(dig) dig->SetRandom(random);
  }

  /* 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();
    }
    delete n;

    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();

#ifdef DIG_DEBUG
    cout<<"TOF Written.."<<endl;
#endif

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

#ifdef DIG_DEBUG
    cout<<"AC Written.."<<endl;
#endif

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

#ifdef DIG_DEBUG
    cout<<"CALO Written.."<<endl;
#endif

    TObject* b4 = fdigmap.FindObject("TSPA");
    if(b4) ((PamVMCTrkDig*)((TPair*)b4)->Value())->WriteToBuff();  
#ifdef DIG_DEBUG
    cout<<"TRK Written.."<<endl;
#endif

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

#ifdef DIG_DEBUG
    cout<<"S4 Written.."<<endl;
#endif

    TObject* b6 = fdigmap.FindObject("NDTI");
    if(b6) ((PamVMCNDDig*)((TPair*)b6)->Value())->WriteToBuff();  
#ifdef DIG_DEBUG
    cout<<"ND Written.."<<endl;
#endif
  }

  
  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();
    }
    delete n;
  }

};

#endif
