#include "TMControlSPD.h"
#include "TMControlMutex.h"
#include "TMConfig.h"
#include "TMMainFrame.h"
#include "TMHistogrammingList.h"
#include "TMDisplayingList.h"
#include "SPDMood.h"
#include "AliRawReaderDate.h"
#include "AliLog.h"
#include "root2date.h"
#include <time.h>
#include <unistd.h>
#include <event.h>
#ifdef WITH_DATE
#include <monitor.h>
#endif
#include "AliGeomManager.h"
#include <TGeoManager.h>
#include <TGrid.h>

extern pthread_mutex_t gMutex;

Bool_t TMControlSPD::instanceFlag = kFALSE;
TMControlSPD* TMControlSPD::single = NULL;
//___________________________________________________________________________________
TMControlSPD* TMControlSPD::Instance() {
  if(!instanceFlag) {
    instanceFlag = kTRUE;
    single = new TMControlSPD();
    return single;
  }
  else {
    return single;
  }
}
//___________________________________________________________________________________
void* TMControlSPD::dumpC_thr(void *arg) {
  TMControlSPD* tp = (TMControlSPD*)arg;
  tp->StartRunning();
  while (!tp->IsStopRunning()) {
    while (tp->IsRunningHold()) {
      tp->SetHolding();
      usleep(1);
    }
    if (!tp->GetEvent()) {
      if (!tp->CheckToIncrementDumpX()) break;
    }
  }
  tp->FinishRunning();
  return 0;
}
//___________________________________________________________________________________
void* TMControlSPD::dump2_thr(void *arg) {
  TMControlSPD* tp = (TMControlSPD*)arg;
  tp->StartRunning();
  while (tp->GetLocalEventNumber() != (Int_t) (TMConfig::Instance()->GETstopRunEventNumber() + 1)) {
    while (tp->IsRunningHold()) {
      tp->SetHolding();
      usleep(1);
    }
    if (tp->IsStopRunning()) break;
    if (!tp->GetEvent()) {
      if (!tp->CheckToIncrementDumpX()) break;
    }
    else {
      tp->IncrementDumpNevents();
    }
  }
  tp->FinishRunning();
  return 0;
}
//___________________________________________________________________________________
void* TMControlSPD::dumpN_thr(void *arg) {
  TMControlSPD* tp = (TMControlSPD*)arg;
  tp->StartRunning();
  while (tp->GetDumpNevents() < TMConfig::Instance()->GETdumpNr()) {
    while (tp->IsRunningHold()) {
      tp->SetHolding();
      usleep(1);
    }
    if (tp->IsStopRunning()) break;
    if (!tp->GetEvent()) {
      if (!tp->CheckToIncrementDumpX()) break;
    }
    else {
      tp->IncrementDumpNevents();
    }
  }
  tp->FinishRunning();
  return 0;
}
//___________________________________________________________________________________
void* TMControlSPD::dump1_thr(void *arg) {
  TMControlSPD* tp = (TMControlSPD*)arg;
  tp->StartRunning();
  while (tp->GetDumpNevents() < 1) {
    while (tp->IsRunningHold()) {
      tp->SetHolding();
      usleep(1);
    }
    if (tp->IsStopRunning()) break;
    if (!tp->GetEvent()) {
      if (!tp->CheckToIncrementDumpX()) break;
    }
    else {
      tp->IncrementDumpNevents();
    }
  }
  if (tp->GetDumpNevents() < 1) {
    printf("No events!\n");
  }
  tp->FinishRunning();
  return 0;
}





//___________________________________________________________________________________
TMControlSPD::TMControlSPD() :
  fYpitchSPD(0.0050), fZ1pitchSPD(0.0425), fZ2pitchSPD(0.0625),
  fHwSPD(0.64), fHlSPD(3.48), fNySPD(256), fNzSPD(160),
  fRunNb(0), fLastNbInRun(-1), fGlobalEventNumber(0), fLocalEventNumber(0),
  fRunning(kFALSE), fRunningHold(0), fHolding(kFALSE), fStopRunning(kFALSE),
  fRetrievingEvent(kFALSE), fStopOnError(kFALSE),
  fDisplayErrorEvents(kTRUE), fDumpNevents(0),
  fAdvEvCountCheck(kFALSE), fMiniEvIdCheck(kFALSE),
  fClustering(kFALSE), fEventToBePlotted(kFALSE), 
  fLastUpdateTime(0), fLastStatusUpdate(0),
  fMovieEventNr(-1), fThisIsAMovieEvent(kFALSE), 
  fLastGlobalX(0), fLastGlobalY(0), fLastGlobalZ(0),
  fFileListIndex(0), fNrFileListFiles(0), fOfflineFileList(),
  fTableDeclared(kFALSE), fRootEventCounter(0),
  timeStampSafeUpdate(time(NULL)),
  fSlowDownRunningTime(time(NULL)), fSlowDownRunningLength(0),
  fErrorFlagNiveau(0)
{

  new AliLog;
  AliLog::Instance()->SetGlobalDebugLevel(-20);

  fYSPD[0]=0.5*fYpitchSPD;
  for (Int_t m=1; m<fNySPD; m++) fYSPD[m]=fYSPD[m-1]+fYpitchSPD; 
  fZSPD[0]=fZ1pitchSPD;
  for (Int_t m=1; m<fNzSPD; m++) {
    Double_t dz=fZ1pitchSPD;
    if (m==31 || m==32 || m==63  || m==64  || m==95 || m==96 || 
	m==127 || m==128) dz=fZ2pitchSPD; 
    fZSPD[m]=fZSPD[m-1]+dz;
  }
  for (Int_t m=0; m<fNzSPD; m++) {
    Double_t dz=0.5*fZ1pitchSPD;
    if (m==31 || m==32 || m==63  || m==64  || m==95 || m==96 || 
	m==127 || m==128) dz=0.5*fZ2pitchSPD; 
    fZSPD[m]-=dz;
  }

  fEvCountCheckObj = NULL;
  fRootEvent = NULL;
  fRootFile = NULL;
  fRootTree = NULL;

  // init buffer for root files
  fBuffer = new unsigned char[100000000];

  // calib handler (for noisy pixel masking)
  cHand = new AliITSOnlineCalibrationSPDhandler();

  // advanced error logger
  fAdvLogger = new AliITSRawStreamSPDErrorLog();
  for (UInt_t eq=0; eq<20; eq++) {
    fAdvLogger->SetByteOffset(eq,60); // hard coded to 60 (should be the eq header length)
  }
  UpdateSupprError();

  // clusterer
  fClusterFinderSPD = new HenrikClusterFinderSPD();

  // geometry 
  if(!gGeoManager){
    TString geoFile = Form("%s/config/geometry.root",getenv("SPDMOOD_SITE"));
    AliGeomManager::LoadGeometry(geoFile.Data());
  }

  // load pixel mask
  LoadMask();

#ifndef WITH_DATE
  fRawReaderDateHenrik = NULL;
#endif

  fLastUpdateTime = time(NULL);
  fLastStatusUpdate = time(NULL);

}
//___________________________________________________________________________________
TMControlSPD::~TMControlSPD() {
  instanceFlag=kFALSE;
  delete cHand;
  delete [] fBuffer;
  delete fAdvLogger;
}
//___________________________________________________________________________________
void TMControlSPD::StartRunning() {
  fRunning=kTRUE;
  fStopRunning=kFALSE;
  TMDisplayingList::Instance()->ProcessStartRun();
}
//___________________________________________________________________________________
void TMControlSPD::FinishRunning() {
  UpdateStatusBar();
  TMMainFrame::Instance()->FinishRunning();

  TMDisplayingList::Instance()->ProcessEndRun();

  fRunning=kFALSE;
  fStopRunning=kFALSE;
  fRunningHold=0;
  fHolding=kFALSE;
}
//___________________________________________________________________________________
void TMControlSPD::HoldRunning(Float_t secWait) {
  fRunningHold++;
  time_t timeStamp = time(NULL);
  if (fRunningHold==1) {
    if (fRunning && !fHolding) {
      if (fRetrievingEvent) {
	// do nothing... (if stuck in monitorGetEvent call)
	fHolding=kTRUE;
      }
      else {
	//	fHolding=kFALSE;
	while (!fHolding && fRunning && pthread_self()!=th1) {
	  usleep(1);
	}
      }
    }
  }
  while (fRunning && (time(NULL) - timeStamp < secWait)) {
    usleep(1);
  }
}
//___________________________________________________________________________________
Bool_t TMControlSPD::TmpUnLock() {
  Bool_t ctrlHasLock = (TMControlMutex::Instance()->GetThreadLocked() == th1);
  if (ctrlHasLock) {
    HoldRunning();
    TMControlMutex::Instance()->ResetMutex();
    pthread_mutex_unlock(&gMutex);
    return kTRUE;
  }
  else return kFALSE;
}
//___________________________________________________________________________________
void TMControlSPD::TmpReLock() {
  Bool_t ihavelock = TMControlMutex::Instance()->DoIHaveLock();
  if (!ihavelock) {
    pthread_mutex_lock(&gMutex);
    //    printf("TMControlSPD::TmpReLock");
    TMControlMutex::Instance()->ITakeLock();
  }
  ContinueRunning();
}
//___________________________________________________________________________________
void TMControlSPD::ContinueRunning(Float_t secWait) {
  time_t timeStamp = time(NULL);
  while (fRunning && (time(NULL) - timeStamp < secWait)) {
    usleep(1);
  }
  fRunningHold--;
  if (fRunningHold==0) {
    fHolding=kFALSE;
  }
}
//___________________________________________________________________________________
UInt_t TMControlSPD::GetNrNoisy() {
  if (cHand==NULL) return 0;
  else return cHand->GetNrNoisy();
}
//___________________________________________________________________________________
void TMControlSPD::StopRunningSafely() {
  fStopRunning=kTRUE;

  time_t timeStamp = time(NULL);
  while (fRunning && (time(NULL) - timeStamp < 2)) { // wait 2 sec to see if process finishes by itself
    usleep(1);
  }

  if (pthread_self() == th1) {
    printf("ERROR: TMControlSPD::StopRunningSafely: Called from Event Dump Thread!!!\n");
    return;
  }

  if (fRunning) { // force stop by killing thread if still running
    fRunningHold++;
    while ((time(NULL) - timeStamp < 2)) { // wait another 2 sec...
      usleep(1);
    }

    pthread_cancel(th1);
    TMControlMutex::Instance()->ResetMutex();
    Bool_t ihavelock = TMControlMutex::Instance()->DoIHaveLock();
    if (!ihavelock) {
      pthread_mutex_lock(&gMutex);
      TMControlMutex::Instance()->ITakeLock();
    }

    FinishRunning();

    if (!ihavelock) {
      TMControlMutex::Instance()->IReleaseLock();
      pthread_mutex_unlock(&gMutex);
    }

  }

}
//___________________________________________________________________________________
void TMControlSPD::printError(char* w, int e) {
#ifdef WITH_DATE
  // Outputs DATE system related error messages. See monitor.h
  fprintf(stderr,"    DATE System Error in %s : %s\n", w, monitorDecodeError(e));
  printf("    Reported Error Number is %08x\n", e);
  TString msg = Form("ERROR : %s (%s) (%08x)", w, monitorDecodeError(e), e);
  //  logThis(msg.Data());
#endif
}
//___________________________________________________________________________________
void TMControlSPD::talk2DATElogin() {
  // Talks to DATE system and sets some parameters like monitoring table, for details

  Int_t status;
  TString msg;

  //  logThis("Apply Options Summary");

#ifdef WITH_DATE
  if (TMConfig::Instance()->GETdeclareMonitor() == kTRUE) {
    status = monitorDeclareMp((Char_t*)(TMConfig::Instance()->GETnameOfMp().Data()));
    if (status != 0) {
      printError("monitorDeclareMp",status);
      return;
    }
    msg = Form("MOOD sesion is declared as %s to DATE system...", TMConfig::Instance()->GETnameOfMp().Data());
    //    logThis(msg.Data());
  }
#endif

  TMConfig::Instance()->SETaa_nbInRun_(0); // initialize evNum
  fLocalEventNumber=0;
  fLastNbInRun=-1; // initialize last evNum

#ifdef WITH_DATE

  DeclareTable();

  //  TString log = Form("monitoring table is %s, %s, NULL...",eventType,monitoringPolicy);
  //  logThis(log.Data());

  if (TMConfig::Instance()->GETsetNowait() == kTRUE) {
    status = monitorSetNowait();
    if (status != 0) {
      printError("monitorSetNowait", status);
      return;
    }
  }
  else if (TMConfig::Instance()->GETsetNowait() == kFALSE) {
    status = monitorSetWait();
    if (status != 0) {
      printError("monitorSetWait", status);
      return;
    }
    //    else {
    //      logThis("Wait option is set...");
    //    }
  }

#endif

#ifdef WITH_DATE
  status = monitorSetSwap(TMConfig::Instance()->GETswap32(), TMConfig::Instance()->GETswap16());
  if (status != 0) {
    printError("monitorSetSwap",status);
    return;
  } 
#endif

  if (TMConfig::Instance()->GETdataSourceOfflineList()) {
    if (!ReadFileList()) return;
    TMConfig::Instance()->SETdataSourceFullPath(GetDataSourceFromList(fFileListIndex));
  }

  if (TMConfig::Instance()->GETrootMode()) {
    status = rootSetDataSource((Char_t*)TMConfig::Instance()->GETdataSourceFullPath().Data());
    if (status != 0) {
      printf("rootSetDataSource error\n");
      return;
    }
  }
  else {
#ifdef WITH_DATE
    status = monitorSetDataSource((Char_t*)TMConfig::Instance()->GETdataSourceFullPath().Data());
    if (status != 0) {
      printError("monitorSetDataSource",status);
      return;
    }
#else
    status = dateSetDataSource((Char_t*)TMConfig::Instance()->GETdataSourceFullPath().Data());
    if (status != 0) {
      printf("dateSetDataSource error\n");
      return;
    }
#endif
  }

  TMMainFrame::Instance()->LoginSuccess();
}
//___________________________________________________________________________________
void TMControlSPD::talk2DATElogout() {
#ifdef WITH_DATE
  Int_t status = monitorLogout();
  if (status != 0) {
    printError("monitorLogout",status);
    return;
  }
#endif

  fGlobalEventNumber = 0;
  fLocalEventNumber=0;
  //!!!  fTabDump->ResetNbInRun();
  TMMainFrame::Instance()->UpdateStatusBar(TMConfig::Instance()->GETdataSourceFullPath().Data(), 1);
  TMMainFrame::Instance()->LogoutSuccess();
}
//___________________________________________________________________________________
#ifdef WITH_DATE
void TMControlSPD::DeclareTable() {
  if (fTableDeclared) return;

  Char_t *eventType;
  if      (TMConfig::Instance()->GETeventType() == 6) eventType="PHY";
  else if (TMConfig::Instance()->GETeventType() == 7) eventType="CAL";
  else                       eventType="ALL";
  Char_t *monitoringPolicy;
  if      (TMConfig::Instance()->GETmonitoringPolicy() == 0) monitoringPolicy="all";
  else if (TMConfig::Instance()->GETmonitoringPolicy() == 1) monitoringPolicy="yes";
  else                              monitoringPolicy="no";
  Char_t *monitorTable[5] = {"ALL","no",eventType, monitoringPolicy, NULL};
  Int_t status = monitorDeclareTable(monitorTable);
  if (status != 0) {
    printError("monitorDeclareTable",status);
    return;
  }

  fTableDeclared = kTRUE;
}
#endif
//___________________________________________________________________________________
void TMControlSPD::Reset() {
  fGlobalEventNumber=0;
  fAdvLogger->Reset();
  if (fEvCountCheckObj!=NULL) {
    fEvCountCheckObj->Reset();
  }
  fErrorFlagNiveau=0;
  UpdateStatusBar();
}
//___________________________________________________________________________________
void TMControlSPD::ResetErrorFlag() {
  Bool_t ihavelock = TMControlMutex::Instance()->DoIHaveLock();
  if (!ihavelock) {
    pthread_mutex_lock(&gMutex);
    //    printf("TMControlSPD::ResetErrorFlag");
    TMControlMutex::Instance()->ITakeLock();
  }

  fErrorFlagNiveau = fAdvLogger->GetNrErrorsTotalAllEq(0);
  TMMainFrame::Instance()->UpdateStatusBarBG(" ",0,0);

  if (!ihavelock) {
    TMControlMutex::Instance()->IReleaseLock();
    pthread_mutex_unlock(&gMutex);
  }
}
//___________________________________________________________________________________
void TMControlSPD::StartDumpC() {
  pthread_create(&th1, NULL, dumpC_thr, (void *)this);
  //  printf("Dump Thread: %ld from Thread %ld\n",th1,pthread_self());
}
//___________________________________________________________________________________
void TMControlSPD::StartDump2() {
  pthread_create(&th1, NULL, dump2_thr, (void *)this);
}
//___________________________________________________________________________________
void TMControlSPD::StartDumpN() {
  fDumpNevents = 0;
  pthread_create(&th1, NULL, dumpN_thr, (void *)this);
}
//___________________________________________________________________________________
void TMControlSPD::StartDump1() {
  fDumpNevents = 0;
  pthread_create(&th1, NULL, dump1_thr, (void *)this);
}
//!!!//___________________________________________________________________________________
//!!!Bool_t TMControlSPD::GridSourceEnv() {
//!!!  if (!fRunning) {
//!!!    TString shell = Form("%s",getenv("SHELL"));
//!!!    if (shell.Contains("bash")) {
//!!!      TString command = Form("source /tmp/gclient_env_%s",getenv("UID"));
//!!!      system(command.Data());
//!!!      return kTRUE;
//!!!    }
//!!!    else {
//!!!      printf("ERROR: TMControlSPD::GridSourceEnv: bash shell needed for this operation\n");
//!!!      return kFALSE;
//!!!    }
//!!!  }
//!!!  else {
//!!!    printf("TMControlSPD::GridSourceEnv: Not possible to source script while running\n");
//!!!    return kFALSE;
//!!!  }
//!!!}
//___________________________________________________________________________________
Bool_t TMControlSPD::GridConnect() {
  if (!fRunning) {
    if (TGrid::Connect("alien://")!=0) return kTRUE;
    else                               return kFALSE;
  }
  else {
    printf("TMControlSPD::GridConnect: Not possible to connect to grid while running\n");
    return kFALSE;
  }
}
//___________________________________________________________________________________
Bool_t TMControlSPD::ReadFileList() {
  fFileListIndex=0;
  fOfflineFileList.SetOwner(kTRUE);
  fOfflineFileList.Clear();
  fNrFileListFiles=0;

  ifstream fileListFile;
  fileListFile.open(TMConfig::Instance()->GETdataSourceFullPathOfflineList().Data(), ifstream::in);
  if (fileListFile.fail()) {
    printf("Could not find file list file!\n");
    return kFALSE;
  }
  printf("The following files will be used:\n");
  while(!fileListFile.eof()) {
    Char_t tmpVal[300];
    fileListFile >> tmpVal;
    if (fileListFile.eof()) break;
    printf("%s\n",tmpVal);
    fOfflineFileList.AddLast(new TObjString(tmpVal));
    fNrFileListFiles++;
  }
  printf("(%d files in total)\n",fNrFileListFiles);
  fileListFile.close();
  if (fNrFileListFiles==0) return kFALSE;

  return kTRUE;
}
//___________________________________________________________________________________
TString TMControlSPD::GetDataSourceFromList(UInt_t fileListIndex) {
  if (fileListIndex<fNrFileListFiles) {
    return ((TObjString*)(fOfflineFileList.At(fileListIndex)))->GetString();
  }
  else {
    return TString("");
  }
}
//___________________________________________________________________________________
void TMControlSPD::IncrementDumpNevents() {
  fDumpNevents++;
}
//___________________________________________________________________________________
void TMControlSPD::IncrementDataSourceList() {
  fFileListIndex++;
  TMConfig::Instance()->SETdataSourceFullPath(GetDataSourceFromList(fFileListIndex));
  printf("Switching to %s...\n",TMConfig::Instance()->GETdataSourceFullPath().Data());
  TMMainFrame::Instance()->UpdateStatusBar(TMConfig::Instance()->GETdataSourceFullPath().Data(), 1);
}
//___________________________________________________________________________________
void TMControlSPD::IncrementDataSource() {
  TString old = Form("%s",TMConfig::Instance()->GETdataSourceFullPath().Data());
  TString newStr = "";

  if (TMConfig::Instance()->GETmultipleFileType()==kFALSE) {
    Bool_t commafound = kFALSE;
    Int_t numbercount=0;
    Bool_t postProc=kFALSE;
    Int_t number;
    Char_t numberval[3];
    Int_t i=0;
    while (i<old.Length()) {
      //    printf("i=%d (%c)\n",i,old[i]);
      if (!commafound || postProc) {
	newStr.Append(Form("%c",old[i]));
      }
      else {
	numberval[numbercount] = old[i];
	numbercount++;
	if (numbercount==3) {
	  number=atoi(numberval);
	  number++;
	  if (number<10) {
	    sprintf(numberval,"00%d",number);
	  }
	  else if (number<100) {
	    sprintf(numberval,"0%d",number);
	  }
	  else {
	    sprintf(numberval,"%d",number);
	  }
	  newStr.Append(Form("%s",numberval));
	  postProc=kTRUE;
	}
      }
      if (old[i]=='.') {
	commafound=kTRUE;
      }
      i++;
    }
  }
  else {
    Int_t commafound = 0;
    Int_t numbercount=0;
    Bool_t postProc=kFALSE;
    Int_t number;
    Char_t numberval[5];
    Int_t i=0;
    while (i<old.Length()) {
      //    printf("i=%d (%c)\n",i,old[i]);
      if (old[i]=='.') {
	commafound++;
      }
      else if (commafound==0 || postProc) {
	newStr.Append(Form("%c",old[i]));
      }
      else {
	if (commafound==1) {
	  numberval[numbercount] = old[i];
	  numbercount++;
	}
	else if (commafound==2) {
	  number=atoi(numberval);
	  number+=10;
	  sprintf(numberval,"%d",number);
	  newStr.Append(Form(".%s.",numberval));
	  newStr.Append(Form("%c",old[i]));
	  postProc=kTRUE;
	}
      }
      i++;
    }
  }

  TMConfig::Instance()->SETdataSourceFullPath(Form("%s",newStr.Data()));
  printf("Switching to %s...\n",TMConfig::Instance()->GETdataSourceFullPath().Data());
  TMMainFrame::Instance()->UpdateStatusBar(TMConfig::Instance()->GETdataSourceFullPath().Data(), 1);
}
//___________________________________________________________________________________
Bool_t TMControlSPD::CheckToIncrementDumpX() {
  if (TMConfig::Instance()->GETdataSourceOnline()) {
    usleep(1);
    return kTRUE; // continue without changing source
  }
  
  if (TMConfig::Instance()->GETmultipleFiles() && fLocalEventNumber!=fLastNbInRun) {    //first time check
    fLastNbInRun = fLocalEventNumber;
    if (TMConfig::Instance()->GETdataSourceOfflineList()) IncrementDataSourceList();
    else                         IncrementDataSource();
    if (TMConfig::Instance()->GETdataSourceFullPath().Length()==0) return kFALSE;
    Int_t status = 0;
    if (TMConfig::Instance()->GETrootMode()) {
      status = rootSetDataSource((Char_t*)TMConfig::Instance()->GETdataSourceFullPath().Data());
      if (status != 0) {
	if (status==1) printf("rootSetDataSource failed, stopping run\n");
	else if (status==2) printf("No more data files, stopping run\n");
	return kFALSE;
      }
    }
    else {
#ifdef WITH_DATE
      status = monitorSetDataSource((Char_t*)TMConfig::Instance()->GETdataSourceFullPath().Data());
      if (status != 0) {
	printError("monitorSetDataSource",status);
	return kFALSE;
      }
#else
      status = dateSetDataSource((Char_t*)TMConfig::Instance()->GETdataSourceFullPath().Data());
      if (status != 0) {
	printf("dateSetDataSource did not succeed, stopping run\n");
	return kFALSE;
      }
#endif
    }
    if (status == 0) {
      TString msg = Form("Data source is set to %s...", TMConfig::Instance()->GETdataSourceFullPath().Data());
      return kTRUE; // success
    }
  }
  else {
    fStopRunning = kTRUE;
  }

  return kFALSE;
}
//___________________________________________________________________________________
Bool_t TMControlSPD::GetEvent() {
  // RETRIEVE ONE EVENT _________________________________
  fRetrievingEvent = kTRUE;

  pthread_mutex_lock(&gMutex);
  TMControlMutex::Instance()->ITakeLock();

  struct eventHeaderStruct *event = NULL;

  if (TMConfig::Instance()->GETrootMode()) {
    if (rootGetEvent(fBuffer)!=0) {
      fRetrievingEvent = kFALSE;
      TMControlMutex::Instance()->IReleaseLock();
      pthread_mutex_unlock(&gMutex);
      return kFALSE;
    }
  }
  else {
#ifdef WITH_DATE
    TMControlMutex::Instance()->IReleaseLock();
    pthread_mutex_unlock(&gMutex);
//!!!    time_t tst = time(NULL);
//!!!    while (time(NULL) - tst < 4) {
//!!!      usleep(1);
//!!!    }
    if (fRunningHold>0) fHolding=kTRUE;
    while (fRunningHold>0) {
      usleep(1);
    }
    fHolding=kFALSE;

    if (monitorGetEventDynamic((void **)&event)!=0) {
      fRetrievingEvent = kFALSE;
      return kFALSE;
    }
    pthread_mutex_lock(&gMutex);
    TMControlMutex::Instance()->ITakeLock();
#else
    if (!fRawReaderDateHenrik->NextEvent()) {
      fRetrievingEvent = kFALSE;
      return kFALSE;
    }
#endif
  }


  if (fRunningHold>0) fHolding=kTRUE;
  while (fRunningHold>0) {
    usleep(1);
  }
  fHolding=kFALSE;

  fRetrievingEvent = kFALSE;
  // END RETRIEVE ONE EVENT ______________________________


  // Check the event before processing...

  if (TMConfig::Instance()->GETrootMode()) {
    event = (eventHeaderStruct *)fBuffer;
    if (event->eventType != PHYSICS_EVENT) {
      fLocalEventNumber++;
      fRetrievingEvent = kFALSE;
      TMControlMutex::Instance()->IReleaseLock();
      pthread_mutex_unlock(&gMutex);
      return kTRUE;
    }
  }
  else {
#ifdef WITH_DATE
#else
    event = fRawReaderDateHenrik->GetEvent();
    if (event->eventType != PHYSICS_EVENT) {
      fRetrievingEvent = kFALSE;
      TMControlMutex::Instance()->IReleaseLock();
      pthread_mutex_unlock(&gMutex);
      return kTRUE;
    }
#endif
  }

  if (event==NULL) {
    fRetrievingEvent = kFALSE;
    TMControlMutex::Instance()->IReleaseLock();
    pthread_mutex_unlock(&gMutex);
    return kFALSE;
  }


  Bool_t SPDpresent = kFALSE;


  AliRawReader *reader = new AliRawReaderDate((void*)event);
  AliITSRawStreamSPD *str = new AliITSRawStreamSPD(reader);
  str->ActivateAdvancedErrorLog(kTRUE,fAdvLogger);
  fAdvLogger->ResetEvent();

  ULong_t runNb = reader->GetRunNumber();
  if (!TMConfig::Instance()->GETrootMode()) {
    if (fRunNb!= runNb) {
      fLocalEventNumber=0;
    }
  }
  fRunNb = runNb;



  //  if (!TMMainFrame::Instance()->IsSkipPixel() && EventNumberAccepted(fGlobalEventNumber)) {
  if (!TMMainFrame::Instance()->IsSkipPixel()) {

    // Call reset for all histos
    if (TMMainFrame::Instance()->IsAutoReset()) {
      TMHistogrammingList::Instance()->Reset();
    }
    else {
      TMHistogrammingList::Instance()->ResetAuto();
    }


    TMHistogrammingList::Instance()->StartEvent(event, fGlobalEventNumber);



    // show also inconsistent events?
    if (!TMMainFrame::Instance()->IsShowErrorEvents()) {
      fDisplayErrorEvents=kTRUE;
    }
    else {
      fDisplayErrorEvents=kFALSE;
    }
    // skip adv event counter check?
    if (TMMainFrame::Instance()->IsSkipEventCountCheck()) {
      fAdvEvCountCheck=kFALSE;
    }
    else {
      fAdvEvCountCheck=kTRUE;
    }
    // skip clustering?
    if (!TMMainFrame::Instance()->IsSkipCluster()) {
      fClustering=kTRUE;
      fClusterFinderSPD->StartEvent();
    }
    else {
      fClustering=kFALSE;
    }

    // HIT LOOP __________________________________________________
    while (str->Next()) {
      UInt_t eq = reader->GetDDLID();
      if (eq>=0 && eq<20 && IsEqActive(eq)) {
	UInt_t hs = str->GetHalfStaveNr();
	UInt_t chip = str->GetChipAddr();
	UInt_t col = str->GetChipCol();
	UInt_t row = str->GetChipRow();
	// process only if not a noisy pixel...
	if (!cHand->IsPixelNoisy(eq,hs,chip,col,row)) {
	  // process only if no consistency errors yet, or forced processing...
	  if (fAdvLogger->GetNrErrors(0,eq)==0 || fDisplayErrorEvents) {
	    TMHistogrammingList::Instance()->ProcessPixel(eq,hs,chip,col,row);
	    if (fClustering) {
	      fClusterFinderSPD->ProcessHitOnline(eq,hs,chip,col,row);
	    }
	  }
	}
      }
    }
    // ______________________________________________________________


    if (fClustering) {
      fClusterFinderSPD->FinishEvent();
      TMHistogrammingList::Instance()->ProcessClusters(fClusterFinderSPD);

      for (UInt_t mod=0; mod<240; mod++) {
	for (UInt_t cl = 0; cl<fClusterFinderSPD->GetClusterCount(mod); cl++) {
	  TransformClusterToGlobal(mod,
			     fClusterFinderSPD->GetClusterMeanCol(mod,cl),
			     fClusterFinderSPD->GetClusterMeanRow(mod,cl));
	  TMHistogrammingList::Instance()->ProcessCluster(fLastGlobalX,
							  fLastGlobalY,
							  fLastGlobalZ,
							  mod,
							  fClusterFinderSPD->GetClusterSize(mod,cl),
							  fClusterFinderSPD->GetClusterWidthZ(mod,cl),
							  fClusterFinderSPD->GetClusterWidthPhi(mod,cl),
							  fClusterFinderSPD->GetClusterType(mod,cl) );
	}
      }

      fThisIsAMovieEvent = kTRUE;
    }

    // advanced event counter check
    if (fAdvEvCountCheck) {
      if (fEvCountCheckObj==NULL) {
	fEvCountCheckObj = new AdvEvCountCheck();
      }

      fEvCountCheckObj->SetDumpAll(TMConfig::Instance()->GETadvEvCntDumpAll());

      for (UInt_t eq=0; eq<20; eq++) {
	for (UInt_t hs=0; hs<6; hs++) {
	  for (UInt_t chip=0; chip<10; chip++) {
	    Short_t evCo = str->GetEventCounterFullChip(eq,hs,chip);
	    if (evCo!=-1) fEvCountCheckObj->NewChipHeader(eq,hs,chip,evCo,fLocalEventNumber);
	  }
	}
      }

      if (fEvCountCheckObj!=NULL) {
	fEvCountCheckObj->CompareEvCount(fLocalEventNumber);
	if (fEvCountCheckObj->IsErrorEventZero()) {
	  TString mess = Form("Event Counters Unsynchronized");
	  for (UInt_t eq=0; eq<20; eq++) {
	    fAdvLogger->ProcessError(AliITSRawStreamSPD::kAdvEventCounterErr,eq,-1,-1,mess.Data());
	  }
	}
	for (UInt_t eq=0; eq<20; eq++) {
	  for (UInt_t hs=0; hs<6; hs++) {
	    Bool_t problem = kFALSE;
	    Bool_t problemJump = kFALSE;
	    for (UInt_t chip=0; chip<10; chip++) {
	      if (fEvCountCheckObj->IsErrorEvent(eq,hs,chip)) {
		problem = kTRUE;
	      }
	      if (fEvCountCheckObj->IsJumpErrorEvent(eq,hs,chip)) {
		problemJump = kTRUE;
	      }
	    }
	    if (problem) {
	      TString mess = Form("Event Counter Error, HS %d",hs);
	      fAdvLogger->ProcessError(AliITSRawStreamSPD::kAdvEventCounterErr,eq,-1,-1,mess.Data());
	    }
	    else if (problemJump) {
	      TString mess = Form("Event Counter Jump, HS %d",hs);
	      fAdvLogger->ProcessError(AliITSRawStreamSPD::kAdvEventCounterOrderErr,eq,-1,-1,mess.Data());
	    }
	  }
	}
      }
    }


    // check if stop after error...
    if (fStopOnError) {
      if (fAdvLogger->GetNrErrorsAllEq(0)>0) {
	fStopRunning=kTRUE;
      }
    }      
    
    // summarize the consistency checks for this event
    //!!!    fAdvLogger->ProcessEvent(fGlobalEventNumber);

    TMHistogrammingList::Instance()->ProcessEvent(event);

  } // end if (skip pixel)

  fGlobalEventNumber++;

  fLocalEventNumber++;

  // check if SPD present in the event
  for (UInt_t eq=0; eq<20; eq++) {
    if (str->IsActiveEq(eq)) {
      SPDpresent = kTRUE;
      break;
    }
  }


  if (SPDpresent) {
    fEventToBePlotted=kTRUE;
    TMHistogrammingList::Instance()->EndEvent(str, fGlobalEventNumber-1);
  }


  // clean up
  delete str;
  delete reader;
#ifdef WITH_DATE
  if (!TMConfig::Instance()->GETrootMode()) free(event);
#endif


  // call update methods
  if (fEventToBePlotted) {
    if ((time(NULL) - timeStampSafeUpdate) > TMConfig::Instance()->GETsafetyHoldTime()) {
      UpdateDisplays();
    }
  }

  if (time(NULL) - fLastStatusUpdate >= 1) {
    UpdateStatusBar();
  }

  TMControlMutex::Instance()->IReleaseLock();
  pthread_mutex_unlock(&gMutex);

  if (time(NULL) - fSlowDownRunningTime < fSlowDownRunningLength) {
    usleep(10);
  }

  return kTRUE;
}
//___________________________________________________________________________________
void TMControlSPD::UpdateDisplays(Bool_t force) {
  if (force || time(NULL) - fLastUpdateTime >= TMConfig::Instance()->GETupdateTime()) {
    if (TMMainFrame::Instance()->IsAutoUpdate()) {
      TMDisplayingList::Instance()->UpdateAutoAllDisplays();
    }
    else {
      TMDisplayingList::Instance()->UpdateAutoDisplays();
    }
    fEventToBePlotted=kFALSE;
    fLastUpdateTime = time(NULL);
  }
}
//___________________________________________________________________________________
void TMControlSPD::UpdateStatusBar() {
  TString runInfo = "";

  // Consistency Error status
  if (fGlobalEventNumber == 0) {
    TMMainFrame::Instance()->UpdateStatusBarBG(" ",0,0);
  }
  else {
    if (fAdvLogger->GetNrErrorsTotalAllEq(0) > fErrorFlagNiveau) {
      TMMainFrame::Instance()->UpdateStatusBarBG("Data Inconsistent",2,0);
//!!!      printf("ERRORS: ");
//!!!      for (UInt_t i=0; i<AliITSRawStreamSPDErrorLog::GetNrErrorCodes(); i++) {
//!!!	printf("%d ",fAdvLogger->GetNrErrorsTotalAllEq(i));
//!!!      }
//!!!      printf("\n");
    }
    else {
      TMMainFrame::Instance()->UpdateStatusBarBG("Data Consistent ",1,0);
    }
  }

  // Local event number
  if (fLocalEventNumber>0) {
    runInfo = Form("Run %d   Event %d", fRunNb, fLocalEventNumber-1);
  }
  else {
    runInfo = "No Events";
  }
  TMMainFrame::Instance()->UpdateStatusBar(runInfo.Data(), 2);

  // Global event number
  if (fGlobalEventNumber>0) {
    runInfo = Form("Physics Events:   %d", fGlobalEventNumber);
  }
  else {
    runInfo = "No events processed";
  }
  TMMainFrame::Instance()->UpdateStatusBar(runInfo.Data(), 3);

  fLastStatusUpdate = time(NULL);
}
//___________________________________________________________________________________
void TMControlSPD::UpdateSupprError() {
  UInt_t nrSuppr=0;
  for (UInt_t i=0; i<AliITSRawStreamSPDErrorLog::GetNrErrorCodes(); i++) {
    if (((TMConfig::Instance()->GETerrorSuppr()) >> i) & 0x1 == 0x1) {
      nrSuppr++;
      fAdvLogger->SuppressErrorMessages(i,kTRUE);
    }
    else {
      fAdvLogger->SuppressErrorMessages(i,kFALSE);
    }
  }
  TMMainFrame::Instance()->UpdateStatusMask(Form("%d error messages suppressed",nrSuppr), 2);
}
//___________________________________________________________________________________
Bool_t TMControlSPD::IsEqActive(UInt_t eqId) {
  return TMConfig::Instance()->GETeqActive(eqId);
}
//___________________________________________________________________________________
void TMControlSPD::SetMask(UInt_t eqS, UInt_t eqE, UInt_t hsS, UInt_t hsE, UInt_t chipS, UInt_t chipE, UInt_t colS, UInt_t colE, UInt_t rowS, UInt_t rowE, Bool_t bMask) {
  if (eqE>19)   eqE  = 19;
  if (hsE>5)    hsE  =  5;
  if (chipE>9)  chipE=  9;
  if (colE>31)  colE = 31;
  if (rowE>255) rowE =255;
  for (UInt_t eq=eqS; eq<=eqE; eq++) {
    for (UInt_t hs=hsS; hs<=hsE; hs++) {
      for (UInt_t chip=chipS; chip<=chipE; chip++) {
	for (UInt_t col=colS; col<=colE; col++) {
	  for (UInt_t row=rowS; row<=rowE; row++) {
	    if (bMask) {
	      cHand->SetNoisyPixel(eq, hs, chip, col, row);
	    }
	    else {
	      cHand->UnSetNoisyPixel(eq, hs, chip, col, row);
	    }
	  }
	}
      }
    }
  }
}
//___________________________________________________________________________________
void TMControlSPD::SetMask2(UInt_t eq, UInt_t hs, UInt_t chip, UInt_t col, UInt_t row, Bool_t bMask) {
  if (eq==300) {
    for (UInt_t eqRE=0; eqRE<20; eqRE++) {
      SetMask2(eqRE,hs,chip,col,row,bMask);
    }
  }
  else if (hs==300) {
    for (UInt_t hsRE=0; hsRE<6; hsRE++) {
      SetMask2(eq,hsRE,chip,col,row,bMask);
    }
  }
  else if (chip==300) {
    for (UInt_t chipRE=0; chipRE<10; chipRE++) {
      SetMask2(eq,hs,chipRE,col,row,bMask);
    }
  }
  else if (col==300) {
    for (UInt_t colRE=0; colRE<32; colRE++) {
      SetMask2(eq,hs,chip,colRE,row,bMask);
    }
  }
  else if (row==300) {
    for (UInt_t rowRE=0; rowRE<256; rowRE++) {
      SetMask2(eq,hs,chip,col,rowRE,bMask);
    }
  }

  else {
    if (eq<20 && hs<6 && chip<10 && col<32 && row<256) {
      if (bMask) {
	cHand->SetNoisyPixel(eq, hs, chip, col, row);
      }
      else {
	cHand->UnSetNoisyPixel(eq, hs, chip, col, row);
      }
    }
    else {
      printf("Error: Pixel out of bounds: %d,%d,%d,%d,%d\n",eq, hs, chip, col, row);
    }
  }

}
//___________________________________________________________________________________
void TMControlSPD::UpdateMask() {
  if (cHand!=NULL) {
    TString msg = Form("%d pixels masked",cHand->GetNrNoisy());
    TMMainFrame::Instance()->UpdateStatusMask(msg.Data(),1);
  }
}
//___________________________________________________________________________________
void TMControlSPD::ClearMask() {
    if (cHand!=NULL) {
      cHand->ResetNoisy();
      UpdateMask();
    }
}
//___________________________________________________________________________________
void TMControlSPD::SaveMask() {
  TString fileLoc = Form("%s/config/mask",getenv("SPDMOOD_SITE"));
  SaveMask(fileLoc.Data());
}
//___________________________________________________________________________________
void TMControlSPD::SaveMask(const Char_t* fileLoc) {
  if (cHand!=NULL) {
    cHand->SetFileLocation(fileLoc);
    cHand->WriteNoisyToFilesAlways();
  }
}
//___________________________________________________________________________________
void TMControlSPD::LoadMask() {
  TString fileLoc = Form("%s/config/mask",getenv("SPDMOOD_SITE"));
  LoadMask(fileLoc.Data());
}
//___________________________________________________________________________________
void TMControlSPD::LoadMask(const Char_t* fileLoc) {
  if (cHand!=NULL) {
    cHand->SetFileLocation(fileLoc);
    cHand->ReadNoisyFromFiles();
  }
  UpdateMask();
}
//___________________________________________________________________________________
void TMControlSPD::PrintMaskedPixels() {
  if (cHand==NULL) return;
  cHand->PrintNoisy();
}
//_____________________________________________________________________
void TMControlSPD::TransformClusterToGlobal(UInt_t mod, Float_t meanCol, Float_t meanRow) {
  const TGeoHMatrix *mT2L = AliITSgeomTGeo::GetTracking2LocalMatrix(mod);
  Int_t lay,lad,det; AliITSgeomTGeo::GetModuleId(mod,lay,lad,det);
  Int_t fNdet = (lad-1)*AliITSgeomTGeo::GetNDetectors(lay) + (det-1);
  Int_t cM = (Int_t)(meanCol);
  Int_t rM = (Int_t)(meanRow);
  Double_t NmeanCol = fZSPD[cM];
  Double_t NmeanRow = fYSPD[rM];
  if (meanCol-cM>0) NmeanCol += (meanCol-cM)*(fZSPD[cM+1]-fZSPD[cM]);
  if (meanRow-rM>0) NmeanRow += (meanRow-rM)*(fYSPD[rM+1]-fYSPD[rM]);
  NmeanCol-=fHlSPD;
  NmeanRow-=fHwSPD;
  //  printf("y,z= %f,%f\n",NmeanRow,NmeanCol);
  
  Int_t milab[10];
  for (UInt_t i=0;i<10;i++) milab[i]=-2;
  milab[3]=fNdet;
  Int_t info[3]; 
  info[0]=1; 
  info[1]=1; 
  if (mod>=80) info[2]=1;
  else         info[2]=0;
  Float_t hit[5];
  Double_t loc[3]; 
  loc[0]=NmeanRow; 
  loc[1]=0.; 
  loc[2]=NmeanCol;
  Double_t trk[3]; 
  trk[0]=0.; 
  trk[1]=0.; 
  trk[2]=0.;
  mT2L->MasterToLocal(loc,trk);
  hit[0]=trk[1];
  hit[1]=trk[2];
  hit[2]=fYpitchSPD*fYpitchSPD/12.;
  hit[3]=fZ1pitchSPD*fZ1pitchSPD/12.;
  hit[4]=1;
  
  Float_t cluglo[3];  
  AliITSRecPoint *recp = new AliITSRecPoint(milab,hit,info);
  if (!recp->GetGlobalXYZ(cluglo)) {
    printf("TMControlSPD::TransformClusterToGlobal: AliITSRecPoint::GetGlobalXYZ failed!!!\n");
  }
  delete recp;

  fLastGlobalX=cluglo[0];
  fLastGlobalY=cluglo[1];
  fLastGlobalZ=cluglo[2];
  //  printf("Cluster: %3.2f,%3.2f,%3.2f\n",cluglo[0],cluglo[1],cluglo[2]);
}
//___________________________________________________________________________________
#ifndef WITH_DATE
Int_t TMControlSPD::dateSetDataSource(const Char_t *source) {
  if (fRawReaderDateHenrik!=NULL) delete fRawReaderDateHenrik;
  fRawReaderDateHenrik = new AliRawReaderDateHenrik(source);
  if (fRawReaderDateHenrik!=NULL) return 0;
  else                            return 1;
}
#endif
//___________________________________________________________________________________
Int_t TMControlSPD::rootSetDataSource(const Char_t *source) {
  if(fRootTree) {
    delete fRootTree;
    fRootTree=NULL;
  }

  if(!(fRootFile=TFile::Open(source))) {
    //    printf("Problem accessing data source\n");
    return 2;
  }

  if(!(fRootTree=(TTree *)fRootFile->Get("RAW"))) {
    printf("Error getting RAW tree\n");
    return 1;
  }

  fRootTree->SetBranchAddress("rawevent", &fRootEvent);
  fRootEventCounter=0;

  fLocalEventNumber=0;

  return 0;
}
//___________________________________________________________________________________
Int_t TMControlSPD::rootGetEvent(void *buffer) {
  if (fRootTree==NULL) return 1;

  fRootEvent = new AliRawEvent;
  Int_t status = 0;

  switch(fRootTree->GetEntry(fRootEventCounter++)) {
  case 0:
    status=1;
    break;
  case -1:
    status=1;
    break;
  default:
    Root2Date(fRootEvent, (unsigned char *)buffer);
    break;
  }

  if (fRootEvent) delete fRootEvent;
  return status;
}
//___________________________________________________________________________________
Bool_t TMControlSPD::EventNumberAccepted(UInt_t ev) {
  // TED1
//  if (ev>2 && ev<63 && ev!=25 && ev!=45) return kTRUE;
//  else return kFALSE;

  // TDI
//  if (ev==63 || ev==65 || ev==67 || ev==69) return kTRUE;
//  else return kFALSE;

  // Alice
//  if ((ev>75 && ev<89) || (ev>96 && ev<115) || ev==127 || ev==128 || ev==130 || ev==131 || 
//      (ev>132 && ev<156) || (ev>156 && ev<166) || (ev>166 && ev<188) || (ev>188 && ev<192) ||
//      (ev>192 && ev<196) || (ev>196 && ev<210)) return kTRUE;
//  else return kFALSE;

  // TED2
//  if (ev>88 && ev<97) return kTRUE;
//  else return kFALSE;

  // Uncorrelated during Alice
//  if (ev==89 || ev==126 || ev==129 || ev==132 || ev==156 || 
//      ev==166 || ev==188 || ev==192 || ev==196) return kTRUE;
//  else return kFALSE;

  return kTRUE;
}

void TMControlSPD::SlowDownRunning(Float_t slowdownlength) {
  fSlowDownRunningTime = time(NULL);
  fSlowDownRunningLength = slowdownlength;
}
