#include "FillHvFromSingles.h"
 
#include "MessageService/MsgService.h"
#include "MinosObjectMap/MomNavigator.h"
#include "JobControl/JobCommand.h"
#include "JobControl/JobCModuleRegistry.h"

#include "Validity/VldRange.h"
#include "Validity/VldTimeStamp.h"
#include "Validity/VldContext.h"  

#include "DatabaseInterface/DbiResultPtr.h"
#include "DatabaseInterface/DbiSqlContext.h"
#include "DatabaseInterface/DbiValidityRec.h"
#include "DatabaseInterface/DbiCascader.h"
#include "DatabaseInterface/DbiTableProxyRegistry.h"
#include "DatabaseInterface/DbiWriter.h"

#include "RawData/RawRecord.h"
#include "RawData/RawHeader.h"
#include "RawData/RawDaqHeader.h"
#include "RawData/RawChannelId.h"
   
#include "RawData/RawDaqHeaderBlock.h"
#include "RawData/RawTpSinglesSummaryBlock.h"

#include "DcsUser/DbuHvFromSingles.h"

//
// $Log $
//
  
ClassImp(FillHvFromSingles)
  
CVSID("$Id: FillHvFromSingles.cxx,v 1.9 2008/01/14 21:59:55 bspeak Exp $");
  
JOBMODULE(FillHvFromSingles,"FillHvFromSingles","FillHvFromSingles");
  
FillHvFromSingles::FillHvFromSingles() :
  fBegTime(-1),
  fEndTime(-1),
  fRecord(0),
  fCounter(0),
  fWriteEntries(0),
  fReadEntries(0),
  fTask(1),
  fMinVaRate(50),
  fMinQieRate(0),
  fMaxColdChips(20),
  fWriteToDatabase(0),
  fReadFromDatabase(0),
  fWriteOutResults(0),
  fPruneShortEntries(0),
  fPruneMinTime(0),
  fPruneMinChips(0),
  fHvFile(0),
  fHvFileName("hvstatus.root"),
  fHvTree(0),
  fRawReadout(0)
{
  MSG("HvStatus",Msg::kInfo) << " *** FillHvFromSingles::FillHvFromSingles() *** " << endl;
 
  fCurrColdChipsSM1 = -1;
  fCurrColdChipsSM2 = -1;

  fDetector = Detector::kUnknown;
  fRawReadout = new RawReadout();
}

FillHvFromSingles::~FillHvFromSingles()
{
  MSG("HvStatus",Msg::kInfo) << " *** FillHvFromSingles::~FillHvFromSingles() *** " << endl;

  if( fRawReadout) delete fRawReadout;
}

void FillHvFromSingles::BeginJob()
{
  MSG("HvStatus",Msg::kInfo) << " *** FillHvFromSingles::BeginJob() *** " << endl;
 
}

JobCResult FillHvFromSingles::Get(MomNavigator* mom)
{
  MSG("HvStatus",Msg::kInfo) << " *** FillHvFromSingles::Get(...) *** " << endl;
  
  JobCResult result(JobCResult::kPassed);

  TObject* momobject = 0;

  fRecord=0;

  TIter momitr(mom->FragmentIter());
  while((momobject = momitr())){
    if(momobject->InheritsFrom("RawRecord")){
      RawRecord* rawrec = dynamic_cast<RawRecord*>(momobject);
      fRecord=1; fCounter++;
      MSG("HvStatus",Msg::kInfo) << "  *** RAW RECORD [" << fCounter << "] ***  " << endl;

      // set the detector type
      if(fDetector==Detector::kUnknown){
        fDetector=rawrec->GetHeader()->GetVldContext().GetDetector();
        MSG("HvStatus",Msg::kDebug) << " Detector = " << fDetector << endl;
      }
      
      // iterate over raw blocks
      TIter rawrecitr = rawrec->GetRawBlockIter();
      TObject* tob = 0;
      while((tob = rawrecitr())){
        MSG("HvStatus",Msg::kDebug) << " " << tob->GetName() << endl;
        this->ProcessBlock(tob);
      }

    }
  }
                                                                                            
  if( !fRecord ){
    MSG("HvStatus",Msg::kWarning) << "  *** FAILED TO FIND RAW RECORD ***  " << endl;
    return result.SetFailed();
  }

  return result;
}

// 
// JobCResult FillHvFromSingles::Ana(const MomNavigator* mom)
// {
//   MSG("HvStatus",Msg::kInfo) << " *** FillHvFromSingles::Ana(...) *** " << endl;
//
//   JobCResult result(JobCResult::kPassed);
//
//   return result;
// }
//

const Registry& FillHvFromSingles::DefaultConfig() const
{
  MSG("HvStatus",Msg::kDebug) << " *** FillHvFromSingles::DefaultConfig() *** " << endl;
 
  static Registry r;
  r.SetName("HvStatus.config.default");
  r.UnLockValues();
  r.Set("HvFileName",fHvFileName.Data());
  r.Set("WriteToDatabase",fWriteToDatabase);
  r.Set("ReadFromDatabase",fReadFromDatabase);
  r.Set("WriteOutResults",fWriteOutResults);
  r.Set("PruneShortEntries",fPruneShortEntries);
  r.Set("PruneMinTime",fPruneMinTime);
  r.Set("PruneMinChips",fPruneMinChips);
  r.Set("MinVaRate",fMinVaRate);
  r.Set("MinQieRate",fMinQieRate);
  r.Set("MaxColdChips",fMaxColdChips);
  r.Set("TaskNumber",fTask);
  r.LockValues();
                    
  return r;
}
  
void FillHvFromSingles::Config(const Registry& r)
{
  MSG("HvStatus",Msg::kDebug) << " *** FillHvFromSingles::Config() *** " << endl;

  Int_t tmpint; const char* tmpchar = 0;

  if(r.Get("HvFileName",tmpchar)) fHvFileName = tmpchar;
  if(r.Get("WriteToDatabase",tmpint)) fWriteToDatabase = tmpint;
  if(r.Get("WriteToDatabase",tmpint)) fWriteToDatabase = tmpint;
  if(r.Get("ReadFromDatabase",tmpint)) fReadFromDatabase = tmpint;
  if(r.Get("WriteOutResults",tmpint)) fWriteOutResults = tmpint;
  if(r.Get("PruneShortEntries",tmpint)) fPruneShortEntries = tmpint;
  if(r.Get("PruneMinTime",tmpint)) fPruneMinTime = tmpint;
  if(r.Get("PruneMinChips",tmpint)) fPruneMinChips = tmpint;
  if(r.Get("MinVaRate",tmpint)) fMinVaRate = tmpint;
  if(r.Get("MinQieRate",tmpint)) fMinQieRate = tmpint;
  if(r.Get("MaxColdChips",tmpint)) fMaxColdChips = tmpint;
  if(r.Get("TaskNumber",tmpint)) fTask = tmpint;

  MSG("HvStatus",Msg::kDebug)
    << "  configuration: " << endl
    << "     HvFileName=" << fHvFileName << endl
    << "     WriteToDatabase=" << fWriteToDatabase << endl
    << "     ReadFromDatabase=" << fReadFromDatabase << endl
    << "     WriteOutResults=" << fWriteOutResults << endl
    << "     PruneShortEntries=" << fPruneShortEntries << endl
    << "     PruneMinTime=" << fPruneMinTime << endl
    << "     PruneMinChips=" << fPruneMinChips << endl
    << "     MinVaRate=" << fMinVaRate << endl
    << "     MinQieRate=" << fMinQieRate << endl
    << "     MaxColdChips=" << fMaxColdChips << endl
    << "     TaskNumber=" << fTask << endl;

  return;
}
  
void FillHvFromSingles::HandleCommand(JobCommand* command)
{
  TString cmd = command->PopCmd();
  if(cmd=="Set"){
    TString opt = command->PopOpt();

  }

  return;
}

void FillHvFromSingles::EndJob()
{
  MSG("HvStatus",Msg::kInfo) << " *** FillHvFromSingles::EndJob() *** " << endl;

  // add final entry for SM1
  if( vecTimeSM1.size()>0 ){
    vecTimeSM1.push_back(fEndTime+1);
    vecStatusSM1.push_back(-1);
    vecColdChipsSM1.push_back(-1);
  }

  // add final entry for SM2
  if( vecTimeSM2.size()>0 ){
    vecTimeSM2.push_back(fEndTime+1);
    vecStatusSM2.push_back(-1);
    vecColdChipsSM2.push_back(-1);
  }

  // print out results
  this->PrintResults();

  // prune short entries
  if( fPruneShortEntries ){
    MSG("HvStatus",Msg::kInfo) << " *** pruning short entries *** " << endl;
    this->PruneShortEntries(fPruneMinTime,fPruneMinChips);
    this->PrintResults();
  }

  // write out results
  if( fWriteOutResults ){
    MSG("HvStatus",Msg::kInfo) << " *** writing to file..." << endl; 
    this->WriteToFile();
    MSG("HvStatus",Msg::kInfo) << "      ... finished writing to file *** " << endl; 
  }

  // write HV information to database
  if( fWriteToDatabase ){
    MSG("HvStatus",Msg::kInfo) << " *** writing to database..." << endl; 
    this->WriteToDatabase();
    MSG("HvStatus",Msg::kInfo) << "   WROTE " << fWriteEntries << " ENTRIES TO DATABASE " << endl;
    MSG("HvStatus",Msg::kInfo) << "      ... finished writing to database *** " << endl; 
  }

  // read HV information from database
  if( fReadFromDatabase ){
    MSG("HvStatus",Msg::kInfo) << " *** reading from database..." << endl; 
    this->ReadFromDatabase();
    MSG("HvStatus",Msg::kInfo) << "   READ " << fReadEntries << " ENTRIES FROM DATABASE " << endl;
    MSG("HvStatus",Msg::kInfo) << "      ... finished reading from database *** " << endl; 
  }

  // save HV information in root file
  if(fHvFile){
    MSG("HvStatus",Msg::kInfo) << " *** saving info to file ... " << endl;
    TDirectory* tmpd = gDirectory;
    fHvFile->cd();
    fHvTree->Write();
    fHvFile->Close();
    gDirectory = tmpd;
    MSG("HvStatus",Msg::kInfo) << "      ... info saved to file *** " << endl;
  }
}

void FillHvFromSingles::PrintResults()
{
  // print out results for supermodule 1
  MSG("HvStatus",Msg::kDebug) << " results for supermodule 1: " << endl;
  for( unsigned int i=0; i<vecTimeSM1.size(); i++){
    MSG("HvStatus",Msg::kDebug) << "   time=" << vecTimeSM1[i] << " coldchips=" << vecColdChipsSM1[i] << " status=" << vecStatusSM1[i] << endl;
  }

  // print out results from supermodule 2
  MSG("HvStatus",Msg::kDebug) << " results for supermodule 2: " << endl;
  for( unsigned int i=0; i<vecTimeSM2.size(); i++){
    MSG("HvStatus",Msg::kDebug) << "   time=" << vecTimeSM2[i] << " coldchips=" << vecColdChipsSM2[i] << " status=" << vecStatusSM2[i] << endl;
  }
}

void FillHvFromSingles::ProcessBlock(TObject* obj)
{

  if(obj->InheritsFrom("RawTpSinglesSummaryBlock")){
    MSG("HvStatus",Msg::kDebug) << " ... found RawTpSinglesSummaryBlock " << endl;
    RawTpSinglesSummaryBlock* rdb = (RawTpSinglesSummaryBlock*)(obj);
    
    Int_t Time = rdb->GetStartTimeStamp().GetSec();
    Double_t FrameTime = (rdb->GetEndTimeStamp().GetSec()-rdb->GetStartTimeStamp().GetSec())+1.0e-9*(rdb->GetEndTimeStamp().GetNanoSec()-rdb->GetStartTimeStamp().GetNanoSec());
    if( fBegTime<0 ) fBegTime=Time;
    if( Time>fEndTime ) fEndTime=Time;

    Int_t Source = rdb->GetSource();
    Int_t SourceCheck = 0;
    Int_t AllChipsSM1 = 0;
    Int_t AllChipsSM2 = 0;
    Int_t ColdChipsSM1 = 0;
    Int_t ColdChipsSM2 = 0;
    Int_t StatusSM1 = -1;
    Int_t StatusSM2 = -1;
    Int_t MaxColdChips = 99999;
    Int_t MinRate = 0;

    Detector::Detector_t Detector = Detector::kUnknown;

    switch( Source ){
      case 0: // Crate only
        Detector = Detector::kUnknown;
        break;
      case 1: // Crate and VARC (VA)
        Detector = Detector::kFar;
        break;
      case 2: // Crate and VFB/ADCSEL (VA)
        Detector = Detector::kFar;
        break;
      case 3: // Crate and VACHIP (VA)
        Detector = Detector::kFar;
        break;
      case 4: // Crate and Plane
        Detector = Detector::kUnknown;
        break;
      case 5: // Crate and MASTER (QIE)
        Detector = Detector::kNear;
        break;
      case 6: // Crate and MINDER (QIE)
        Detector = Detector::kNear;
        break;
      case 7: // Crate and MENU (QIE)
        Detector = Detector::kNear;
        break;
      default:
        break;
    }

    // check source type
    if( Source==3 && Detector==Detector::kFar ){
      MinRate=fMinVaRate;
      MaxColdChips=fMaxColdChips;
      SourceCheck=1;
    }      

    if( Source==7 && Detector==Detector::kNear ){
      MinRate=fMinQieRate;
      MaxColdChips=fMaxColdChips;
      SourceCheck=1;
    }

    // Iterate over raw channels and record any hot/cold chips
    typedef std::map<RawChannelId,UInt_t> RCIdToRateMap;
    const RCIdToRateMap& rates = rdb->GetRates();
    RCIdToRateMap::const_iterator rateItr = rates.begin();
    RCIdToRateMap::const_iterator rateEnd = rates.end();
    while ( rateItr != rateEnd ) {
      RawChannelId rawch = rateItr->first;
      Int_t rawrate = rateItr->second;
      Int_t correctedrate = (Int_t)(rawrate/FrameTime);
      Int_t rate = correctedrate;
      Int_t crate = rawch.GetCrate();

      RawReadout::ReadoutType_t readout = fRawReadout->GetReadoutType(rawch);
            
      if( ( SourceCheck )
       && ( readout==RawReadout::kDetector 
	 || readout==RawReadout::kVetoShield ) ){     

        // supermodule 1   
        if( crate>=0 && crate<8 ){
          AllChipsSM1++; 
          if(rate<MinRate){
            ColdChipsSM1++;
            MSG("HvStatus",Msg::kVerbose) << "   cold chip (SM1): crate=" << crate << " corrected rate=" << correctedrate << endl; 
	  }
	}

        // supermodule 2
        if( crate>=8 && crate<16 ){
          AllChipsSM2++; 
          if(rate<MinRate){
            ColdChipsSM2++;
            MSG("HvStatus",Msg::kVerbose) << "   cold chip (SM2): crate=" << crate << " corrected rate=" << correctedrate << endl; 
	  }
	}

      }

      rateItr++;
    }

    MSG("HvStatus",Msg::kVerbose) << "   Time=" << Time << " FrameTime=" << FrameTime << " Source=" << Source << " Check=" << SourceCheck << endl;
    MSG("HvStatus",Msg::kVerbose) << "   MinRate=" << MinRate << " MaxColdChips=" << MaxColdChips << endl;
    MSG("HvStatus",Msg::kVerbose) << "   SM1: AllChips=" << AllChipsSM1 << " ColdChips=" << ColdChipsSM1 << endl;
    MSG("HvStatus",Msg::kVerbose) << "   SM2: AllChips=" << AllChipsSM2 << " ColdChips=" << ColdChipsSM2 << endl;

    // analyse the singles data
    if( SourceCheck ){

      // supermodule 1
      if( AllChipsSM1>0 ){

        // set HV status
        if( ColdChipsSM1<fMaxColdChips ) StatusSM1=1;
        else StatusSM1=0;

        // store new data if things have changed
        if( ColdChipsSM1!=fCurrColdChipsSM1 ){
          MSG("HvStatus",Msg::kDebug) << "   new data (SM1): time=" << Time << " status=" << StatusSM1 << " coldchips=" << ColdChipsSM1 << endl;
          vecTimeSM1.push_back(Time);
          vecStatusSM1.push_back(StatusSM1);
          vecColdChipsSM1.push_back(ColdChipsSM1);
          fCurrColdChipsSM1=ColdChipsSM1;
        }
      }

      // supermodule 2
      if( AllChipsSM2>0 ){

        // set HV status
        if( ColdChipsSM2<fMaxColdChips ) StatusSM2=1;
        else StatusSM2=0;

        // store new data if things have changed
        if( ColdChipsSM2!=fCurrColdChipsSM2 ){ 
          MSG("HvStatus",Msg::kDebug) << "   new data (SM2): time=" << Time << " status=" << StatusSM2 << " coldchips=" << ColdChipsSM2 << endl;
          vecTimeSM2.push_back(Time);
          vecStatusSM2.push_back(StatusSM2);
          vecColdChipsSM2.push_back(ColdChipsSM2);
          fCurrColdChipsSM2=ColdChipsSM2;
        }
      }

    }

  }

  return;
}

void FillHvFromSingles::PruneShortEntries(Int_t nSecs, Int_t nChips)
{
  MSG("HvStatus",Msg::kDebug) << " *** FillHvFromSingles::PruneShortEntries(...) *** " << endl;

  MSG("HvStatus",Msg::kVerbose) << " nSecs=" << nSecs << " nChips=" << nChips << endl;

  Int_t delta=3;
  Int_t delta_coldchips=10;

  Bool_t carryon=1,newentry=0;
  Int_t currchips=-1,newchips=0;
  Int_t size_old=0,size_new=0;
  Int_t dt_pos=-1,dt_neg=-1;
  Int_t ctr=0;

  vector<int> tempTime;
  vector<int> tempStatus;
  vector<int> tempColdChips;

  // prune supermodule 1
  MSG("HvStatus",Msg::kVerbose) << "    pruning entries for SM1 " << endl;
  ctr=0;
  carryon=1;
  while(carryon){
    carryon=0;
    size_old=vecTimeSM1.size();

    tempTime=vecTimeSM1;
    tempStatus=vecStatusSM1;
    tempColdChips=vecColdChipsSM1;

    for( unsigned int i=0; i+1<vecTimeSM1.size(); i++){

      if( 1 // vecColdChipsSM1[i]<nChips
       && vecTimeSM1[i+1]-vecTimeSM1[i]<nSecs ){

        newentry=0;
        newchips=vecColdChipsSM1[i];
        dt_pos=-1;
        dt_neg=-1;

        if( i+2<vecTimeSM1.size() ) dt_pos=vecTimeSM1[i+2]-vecTimeSM1[i+1];
        if( i>=1 ) dt_neg=vecTimeSM1[i]-vecTimeSM1[i-1];
        if( dt_pos>=nSecs || dt_neg>=nSecs ) newchips=-1;

        if( i+1<vecTimeSM1.size()
	 && vecColdChipsSM1[i+1]>newchips ){
          if( ( vecColdChipsSM1[i+1]-vecColdChipsSM1[i]>=-delta 
             && vecColdChipsSM1[i+1]-vecColdChipsSM1[i]<=+delta )
	   || ( vecColdChipsSM1[i+1]>=fMaxColdChips+delta_coldchips 
             && vecColdChipsSM1[i]>=fMaxColdChips+delta_coldchips ) ){
            if( dt_pos>=nSecs || dt_neg<nSecs ){
              newchips=vecColdChipsSM1[i+1];
              newentry=1;
	    }
	  }
        }
      
        if( i>=1 
	 && vecColdChipsSM1[i-1]>newchips ){
          if( ( vecColdChipsSM1[i-1]-vecColdChipsSM1[i]>=-delta 
             && vecColdChipsSM1[i-1]-vecColdChipsSM1[i]<=+delta ) 
	   || ( vecColdChipsSM1[i-1]>=fMaxColdChips+delta_coldchips 
             && vecColdChipsSM1[i]>=fMaxColdChips+delta_coldchips ) ){
            if( dt_neg>=nSecs || dt_pos<nSecs ){
              newchips=vecColdChipsSM1[i-1];
              newentry=1;
	    }
	  }
	}

        if( newentry ){
          tempColdChips[i]=newchips;
          carryon=1;
	}

      }
    }

    vecTimeSM1.clear();
    vecStatusSM1.clear();
    vecColdChipsSM1.clear();
    currchips=-1;

    for( unsigned int i=0; i<tempColdChips.size(); i++){
      if( tempColdChips[i]!=currchips ){
        vecTimeSM1.push_back(tempTime[i]);
        vecStatusSM1.push_back(tempStatus[i]);
        vecColdChipsSM1.push_back(tempColdChips[i]);
        currchips=tempColdChips[i];
      }
    }

    size_new=vecTimeSM1.size();
    if( size_new>=size_old ) carryon=0;

    ctr++;
  }
  MSG("HvStatus",Msg::kVerbose) << "      ..." << ctr << " iterations " << endl; 
  
  // prune supermodule 2
  MSG("HvStatus",Msg::kVerbose) << "    pruning entries for SM2 " << endl;
  ctr=0;
  carryon=1;
  while(carryon){
    carryon=0;
    size_old=vecTimeSM2.size();

    tempTime=vecTimeSM2;
    tempStatus=vecStatusSM2;
    tempColdChips=vecColdChipsSM2;

    for( unsigned int i=0; i+1<vecTimeSM2.size(); i++){
      
      if( 1 // vecColdChipsSM2[i]<nChips
       && vecTimeSM2[i+1]-vecTimeSM2[i]<nSecs ){

        newentry=0;
        newchips=vecColdChipsSM2[i];
        dt_pos=-1;
        dt_neg=-1;

        if( i+2<vecTimeSM2.size() ) dt_pos=vecTimeSM2[i+2]-vecTimeSM2[i+1];
        if( i>=1 ) dt_neg=vecTimeSM2[i]-vecTimeSM2[i-1];
        if( dt_pos>=nSecs || dt_neg>=nSecs ) newchips=-1;

        if( i+1<vecTimeSM2.size()
	 && vecColdChipsSM2[i+1]>newchips ){
          if( ( vecColdChipsSM2[i+1]-vecColdChipsSM2[i]>=-delta 
             && vecColdChipsSM2[i+1]-vecColdChipsSM2[i]<=+delta ) 
	   || ( vecColdChipsSM2[i+1]>=fMaxColdChips+delta_coldchips 
             && vecColdChipsSM2[i]>=fMaxColdChips+delta_coldchips ) ){
            if( dt_pos>=nSecs || dt_neg<nSecs ){
              newchips=vecColdChipsSM2[i+1];
              newentry=1;
	    }
	  }
	}

        if( i>=1 
	 && vecColdChipsSM2[i-1]>newchips ){
          if( ( vecColdChipsSM2[i-1]-vecColdChipsSM2[i]>=-delta
	     && vecColdChipsSM2[i-1]-vecColdChipsSM2[i]<=+delta )
	   || ( vecColdChipsSM2[i-1]>=fMaxColdChips+delta_coldchips 
	     && vecColdChipsSM2[i]>=fMaxColdChips+delta_coldchips ) ){
            if( dt_neg>=nSecs || dt_pos<nSecs ){
              newchips=vecColdChipsSM2[i-1];
              newentry=1;
	    }
	  }
	}

        if( newentry ){
          tempColdChips[i]=newchips;
          carryon=1;
	}

      }
    }

    vecTimeSM2.clear();
    vecStatusSM2.clear();
    vecColdChipsSM2.clear();
    currchips=-1;

    for( unsigned int i=0; i<tempColdChips.size(); i++){
      if( tempColdChips[i]!=currchips ){
        vecTimeSM2.push_back(tempTime[i]);
        vecStatusSM2.push_back(tempStatus[i]);
        vecColdChipsSM2.push_back(tempColdChips[i]);
        currchips=tempColdChips[i];
      }
    }

    size_new=vecTimeSM2.size();
    if( size_new>=size_old ) carryon=0;

    ctr++;
  }
  MSG("HvStatus",Msg::kVerbose) << "      ..." << ctr << " iterations " << endl; 
  
  return;
}

void FillHvFromSingles::WriteToFile()
{
  MSG("HvStatus",Msg::kDebug) << " *** FillHvFromSingles::WriteToFile() *** " << endl;

  Int_t begtime,endtime,coldchips,hvstatus;  

  // supermodule 1
  if( vecTimeSM1.size()>0 ){
    for( unsigned int i=0; i+1<vecTimeSM1.size(); i++){
      begtime=vecTimeSM1[i];
      endtime=vecTimeSM1[i+1];
      hvstatus=vecStatusSM1[i];
      coldchips=vecColdChipsSM1[i];
      if( fWriteOutResults ){
        this->WriteOutResults(0,begtime,endtime,fDetector,1,hvstatus,coldchips);
      }
    }
  }

  // supermodule 2
  if( vecTimeSM2.size()>0 ){
    for( unsigned int i=0; i+1<vecTimeSM2.size(); i++){
      begtime=vecTimeSM2[i];
      endtime=vecTimeSM2[i+1];
      hvstatus=vecStatusSM2[i];
      coldchips=vecColdChipsSM2[i];
      if( fWriteOutResults ){
        this->WriteOutResults(0,begtime,endtime,fDetector,2,hvstatus,coldchips);
      }
    }
  }

  return;
}

void FillHvFromSingles::WriteToDatabase()
{
  MSG("HvStatus",Msg::kDebug) << " *** FillHvFromSingles::WriteToDatabase() *** " << endl;

  Int_t begtime,endtime,coldchips,hvstatus;  

  // supermodule 1
  if( vecTimeSM1.size()>0 ){
    for( unsigned int i=0; i+1<vecTimeSM1.size(); i++){
      begtime=vecTimeSM1[i];
      endtime=vecTimeSM1[i+1];
      hvstatus=vecStatusSM1[i];
      coldchips=vecColdChipsSM1[i];
      this->WriteToDatabase(begtime,endtime,fDetector,1,hvstatus,coldchips);
      if( fWriteOutResults ){
        this->WriteOutResults(1,begtime,endtime,fDetector,1,hvstatus,coldchips);
      }
    }
  }

  // supermodule 2
  if( vecTimeSM2.size()>0 ){
    for( unsigned int i=0; i+1<vecTimeSM2.size(); i++){
      begtime=vecTimeSM2[i];
      endtime=vecTimeSM2[i+1];
      hvstatus=vecStatusSM2[i];
      coldchips=vecColdChipsSM2[i];
      this->WriteToDatabase(begtime,endtime,fDetector,2,hvstatus,coldchips);
      if( fWriteOutResults ){
        this->WriteOutResults(1,begtime,endtime,fDetector,2,hvstatus,coldchips);
      }
    }
  }

  return;
}

void FillHvFromSingles::WriteToDatabase(Int_t begtime, Int_t endtime, Detector::Detector_t detector, Int_t supermodule, Int_t hvstatus, Int_t coldchips)
{
  MSG("HvStatus",Msg::kVerbose) << " *** FillHvFromSingles::WriteToDatabase(...) *** " << endl;

  DbiCascader& cascader = DbiTableProxyRegistry::Instance().GetCascader();

  if( !cascader.TableExists("DBUHVFROMSINGLES") ){
    MSG("HvStatus",Msg::kDebug) << "    Creating temporary DBUHVFROMSINGLES table " << endl;

    string tableDescr = "(SEQNO int, HV_STATUS int, HV_SUPERMODULE int, HV_COLDCHIPS int)";
    Int_t dbNoTempHvStatus = cascader.CreateTemporaryTable("DBUHVFROMSINGLES",tableDescr);

    MSG("HvStatus",Msg::kDebug) << "    DbNoTempHvStatus=" << dbNoTempHvStatus << endl;
  }  

  if( cascader.TableExists("DBUHVFROMSINGLES") ){
    MSG("HvStatus",Msg::kVerbose) << "    Writing to DBUHVFROMSINGLES table... " << endl;

    VldTimeStamp start(begtime);
    VldTimeStamp finish(endtime);
    TString logentry("HV status from singles (");
    logentry.Append(start.AsString("s"));
    logentry.Append(" to ");
    logentry.Append(finish.AsString("s"));
    logentry.Append(")");

    VldRange range(detector,SimFlag::kData,start,finish,logentry.Data());

    DbuHvFromSingles row(hvstatus,supermodule,coldchips);

    Int_t aggNo = row.GetAggregateNo();
    Dbi::Task task = fTask;
    VldTimeStamp creationDate;

    DbiWriter<DbuHvFromSingles> writer(range,aggNo,task,creationDate,0,logentry.Data());

    writer << row;
    writer.Close();

    MSG("HvStatus",Msg::kVerbose) << "    " << logentry.Data() << endl;
    MSG("HvStatus",Msg::kVerbose) << "    supermodule=" << supermodule << " hvstatus=" << hvstatus << " coldchips=" << coldchips << endl;

    fWriteEntries++;
  }

  return;
}

void FillHvFromSingles::ReadFromDatabase()
{
  MSG("HvStatus",Msg::kDebug) << " *** FillHvFromSingles::ReadFromDatabase() *** " << endl;

  Int_t time,hvstatus,coldchips;  

  // supermodule 1
  if( vecTimeSM1.size()>0 ){
    for( unsigned int i=0; i+1<vecTimeSM1.size(); i++){
      time=vecTimeSM1[i];
      hvstatus=-1;
      coldchips=0;
      this->ReadFromDatabase(time,fDetector,1,hvstatus,coldchips);
      if( fWriteOutResults ){
        this->WriteOutResults(2,time,time,fDetector,1,hvstatus,coldchips);
      }
    }
  }

  // supermodule 2
  if( vecTimeSM2.size()>0 ){
    for( unsigned int i=0; i+1<vecTimeSM2.size(); i++){
      time=vecTimeSM2[i];
      hvstatus=-1;
      coldchips=0;
      this->ReadFromDatabase(time,fDetector,2,hvstatus,coldchips);
      if( fWriteOutResults ){
        this->WriteOutResults(2,time,time,fDetector,2,hvstatus,coldchips);
      }
    }
  }
 
  return;   
}

void FillHvFromSingles::ReadFromDatabase(Int_t time, Detector::Detector_t detector, Int_t supermodule, Int_t& hvstatus, Int_t& coldchips)
{
  MSG("HvStatus",Msg::kVerbose) << " *** FillHvFromSingles::ReadFromDatabase(...) *** " << endl;

  hvstatus=-1; coldchips=0;

  DbiCascader& cascader = DbiTableProxyRegistry::Instance().GetCascader();

  if( cascader.TableExists("DBUHVFROMSINGLES") ){
    MSG("HvStatus",Msg::kVerbose) << "    Reading from DBUHVFROMSINGLES table... " << endl;

    Int_t tmpsupermodule=-1, tmphvstatus=-1, tmpcoldchips=0;

    VldTimeStamp timestamp(time,0);
    VldContext vldc(detector,SimFlag::kData,timestamp);
    DbiResultPtr<DbuHvFromSingles> resptr("DBUHVFROMSINGLES",vldc,fTask);

    MSG("HvStatus",Msg::kVerbose) << "    Number Of Rows = " << resptr.GetNumRows() << endl;

    if( resptr.GetNumRows()>0 ){
      for( unsigned int i=0; i<resptr.GetNumRows(); i++){
        const DbuHvFromSingles* rowptr = resptr.GetRow(i);
        tmpsupermodule=rowptr->GetSupermodule();
        if( tmpsupermodule==supermodule ){
          tmphvstatus=rowptr->GetStatus();
          tmpcoldchips=rowptr->GetColdChips();
        }
      }
    }

    hvstatus=tmphvstatus; coldchips=tmpcoldchips;

    MSG("HvStatus",Msg::kVerbose) << "    " << timestamp.AsString("s") << " supermodule=" << supermodule << " hvstatus=" << hvstatus << " coldchips=" << coldchips << endl;

    fReadEntries++;
  }

  return;
}

void FillHvFromSingles::WriteOutResults(Int_t source, Int_t begtime, Int_t endtime, Detector::Detector_t detector, Int_t supermodule, Int_t hvstatus, Int_t coldchips)
{
  MSG("HvStatus",Msg::kVerbose) << " *** FillHvFromSingles::WriteOutResults() *** " << endl;

  Source=source; 
  BegTime=begtime;
  EndTime=endtime;
  Detector=detector;
  Supermodule=supermodule;
  HvStatus=hvstatus;
  ColdChips=coldchips;

  MSG("HvStatus",Msg::kVerbose) << "    Source=" << Source << " BegTime=" << BegTime << " EndTime=" << EndTime << " Detector=" << Detector << " Supermodule=" << Supermodule << " HvStatus=" << HvStatus << " ColdChips=" << ColdChips << endl;

  if(!fHvFile){
    TDirectory* tmpd = gDirectory;
    fHvFile = new TFile(fHvFileName.Data(),"RECREATE");
    fHvTree = new TTree("HvStatus","HvStatus");
    fHvTree->SetAutoSave(300);
    fHvTree->Branch("Source",&Source,"Source/I");
    fHvTree->Branch("BegTime",&BegTime,"BegTime/I");
    fHvTree->Branch("EndTime",&EndTime,"EndTime/I");
    fHvTree->Branch("Detector",&Detector,"Detector/I");
    fHvTree->Branch("Supermodule",&Supermodule,"Supermodule/I");
    fHvTree->Branch("HvStatus",&HvStatus,"HvStatus/I");
    fHvTree->Branch("ColdChips",&ColdChips,"ColdChips/I");
    gDirectory = tmpd;
  }
  
  if(fHvFile){
    TDirectory* tmpd = gDirectory;
    fHvFile->cd();
    fHvTree->Fill();
    gDirectory = tmpd;
  }

  return;
}
