#include "TMDisplaying.h"
#include "TMConfig.h"
#include "TMMainFrame.h"
#include "TMControlSPD.h"
#include "TMControlMutex.h"
#include "TMScreenShot.h"
#include "TMTrigMask.h"
#include "SPDMood.h"
#include <TSystem.h>
#include <TCanvas.h>
#include <pthread.h>
#include <time.h>

#ifdef MOVIE_VER
#include "TMMovie.h"
#endif

ClassImp(TMDisplaying)

extern pthread_mutex_t gMutex;

//_____________________________________________________________________
TMDisplaying::TMDisplaying(const Char_t *frameName, const TGWindow *p, UInt_t width, UInt_t height, TMHistogramming *hist, UInt_t id, UInt_t plotNr, UInt_t cloneId, Bool_t overRide) :
  TGMainFrame(p, width, height), fFrameName(frameName),fWidth(width),fHeight(height),
  fHist(hist), fID(id), fPlotNr(plotNr), fCloneId(cloneId), 
  fAutoUpdate(kFALSE), fPleaseWait(kFALSE)
#ifdef MOVIE_VER
  ,
  fMovie(kFALSE), fNrImg(0), fImgDir(".")
#endif
{
  // overRide flag not explicitly used at the moment...
}
//_____________________________________________________________________
TMDisplaying::TMDisplaying(const Char_t *frameName, const TGWindow *p, UInt_t width, UInt_t height, TMHistogramming *hist, UInt_t id, UInt_t plotNr, UInt_t cloneId) :
  TGMainFrame(p, width, height), fFrameName(frameName),fWidth(width),fHeight(height),
  fHist(hist), fID(id), fPlotNr(plotNr), fCloneId(cloneId), 
  fAutoUpdate(kFALSE), fPleaseWait(kFALSE)
#ifdef MOVIE_VER
  ,
  fMovie(kFALSE), fNrImg(0), fImgDir(".")
#endif
{
  gClient->GetColorByName("green", green);
  gClient->GetColorByName("gray", gray);

  CreateTopFrame();
  CreateBottomFrame();

  MapSubwindows();
  Resize();
  MapWindow();

  TCanvas *canv = fTheCanvas->GetCanvas();
  fHist->Draw(canv);

//  if (TMControlSPD::Instance()->IsRunning()) {
//    fTheCanvas->Disconnect();
//  }

  Update();

}
//_____________________________________________________________________
TMDisplaying::~TMDisplaying() {
  Cleanup();
}
//_____________________________________________________________________
void TMDisplaying::SetPlotNr(UInt_t plotnr) {
  fPlotNr=plotnr;
  UpdateWindowName();
}
//_____________________________________________________________________
void TMDisplaying::UpdateWindowName() {
  TString frameName = fFrameName;
  if (fPlotNr>0) {
    frameName.Append(Form(" (obj %d)",fPlotNr));
  }
  if (fCloneId>0) {
    frameName.Append(Form(" (clone)"));
  }
  SetWindowName(frameName.Data());
}
//_____________________________________________________________________
void TMDisplaying::CreateTopFrame() {
  UpdateWindowName();
  TString canvasName = Form("%s-%d-%d",fFrameName.Data(),fPlotNr,fCloneId);
  fTheCanvas = new TRootEmbeddedCanvasHenrik(canvasName.Data(), this, fWidth-250, fHeight-120);
  AddFrame(fTheCanvas, new TGLayoutHints(kLHintsExpandX  | kLHintsExpandY,0,0,0,0));
}
//_____________________________________________________________________
void TMDisplaying::CreateBottomFrame() {
  fBottomStatus = new TGCompositeFrame(this, 10, 22, kHorizontalFrame | kFixedSize);
  AddFrame(fBottomStatus, new TGLayoutHints(kLHintsExpandX, 0,0,0,0));

  fStatusBar = new TGStatusBar(fBottomStatus, 100, 22, kHorizontalFrame | kFixedSize);
  fStatusBar->SetParts(2);
  fStatusBar->Draw3DCorner(kFALSE);
  fBottomStatus->AddFrame(fStatusBar,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));

  TGCompositeFrame *tf = new TGCompositeFrame(fBottomStatus, 10, 22, kHorizontalFrame | kFixedSize);
  fBottomStatus->AddFrame(tf, new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));

#ifdef MOVIE_VER
  fBottomMovie = new TGTextButton(tf, "MOVIE", BOTTOM_MOVIE);
  tf->AddFrame(fBottomMovie,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomMovie->Associate(this);
  fImgDir = Form("%s/tmp",getenv("SPDMOOD_SITE")); // always use the same...
#endif

  fBottomPause = new TGTextButton(tf, "PAUSE", BOTTOM_PAUSE);
  tf->AddFrame(fBottomPause,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomPause->Associate(this);
  if (fHist->GetPaused()) ToggleButton(BOTTOM_PAUSE);

  fBottomAutoReset = new TGTextButton(tf, "AU-RE", BOTTOM_AUTORESET);
  fBottomAutoReset->SetToolTipText("Auto-Reset");
  tf->AddFrame(fBottomAutoReset,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomAutoReset->Associate(this);
  if (fHist->GetAutoReset()) ToggleButton(BOTTOM_AUTORESET);

  fBottomAutoUpdate = new TGTextButton(tf, "AU-UP", BOTTOM_AUTOUPDATE);
  fBottomAutoUpdate->SetToolTipText("Auto-Update");
  tf->AddFrame(fBottomAutoUpdate,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomAutoUpdate->Associate(this);

  tf = new TGCompositeFrame(fBottomStatus, 10, 22, kHorizontalFrame | kFixedSize);
  fBottomStatus->AddFrame(tf, new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));

  fTextEventLabel1 = new TGLabel(tf, " AU-UP: Ev# % ");
  tf->AddFrame(fTextEventLabel1, new TGLayoutHints(kLHintsCenterY | kLHintsLeft,0,0,0,0));
  fTextEventMod = new TGTextEntry(tf, "1", TEXT_EVENTMOD);
  fTextEventMod->SetWidth(40);
  tf->AddFrame(fTextEventMod, new TGLayoutHints(kLHintsCenterY | kLHintsLeft,0,0,0,0));
  fTextEventLabel2 = new TGLabel(tf, " == ");
  tf->AddFrame(fTextEventLabel2, new TGLayoutHints(kLHintsCenterY | kLHintsLeft,0,0,0,0));
  fTextEventModEq = new TGTextEntry(tf, "0", TEXT_EVENTMODEQ);
  fTextEventModEq->SetWidth(40);
  tf->AddFrame(fTextEventModEq, new TGLayoutHints(kLHintsCenterY | kLHintsLeft,0,0,0,0));






  fBottomButtons = new TGCompositeFrame(this, 10, 22, kHorizontalFrame | kFixedSize);
  AddFrame(fBottomButtons, new TGLayoutHints(kLHintsExpandX | kLHintsBottom, 0,0,0,0));

  fBottomUpdate = new TGTextButton(fBottomButtons, "UPDATE", BOTTOM_UPDATE);
  fBottomButtons->AddFrame(fBottomUpdate,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomUpdate->Associate(this);
  
  fBottomReset = new TGTextButton(fBottomButtons, "RESET", BOTTOM_RESET);
  fBottomButtons->AddFrame(fBottomReset,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomReset->Associate(this);

  fBottomClone = new TGTextButton(fBottomButtons, "CLONE", BOTTOM_CLONE);
  fBottomButtons->AddFrame(fBottomClone,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomClone->Associate(this);

  fBottomKill = new TGTextButton(fBottomButtons, "KILL", BOTTOM_KILL);
  fBottomButtons->AddFrame(fBottomKill,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomKill->Associate(this);

  fBottomTrigMask = new TGTextButton(fBottomButtons, "TRIG MASK", BOTTOM_TRIGMASK);
  fBottomButtons->AddFrame(fBottomTrigMask,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomTrigMask->Associate(this);

  fBottomScreenShot = new TGTextButton(fBottomButtons, "SCREEN-SHOT", BOTTOM_SCREENSHOT);
  fBottomButtons->AddFrame(fBottomScreenShot,new TGLayoutHints(kLHintsBottom | kLHintsLeft | kLHintsExpandX,0,0,0,0));
  fBottomScreenShot->Associate(this);


}
//_____________________________________________________________________
void TMDisplaying::CloseWindow() {
  if (fPleaseWait || (fTheCanvas!=NULL && fTheCanvas->Busy())) {
    time_t stamp = time(NULL);
    TString stampMsg = Form("%s",ctime(&stamp));
    stampMsg.ReplaceAll("\n","");
    printf("Busy - Please try again... (%s)\n",stampMsg.Data());
    return;
  }
  fPleaseWait = kTRUE;
  TMMainFrame::Instance()->ProcessCloseDisplay(fID,fPlotNr,fCloneId);
  fPleaseWait = kFALSE;
}
//_____________________________________________________________________
void TMDisplaying::ProcessKill() {
  TMMainFrame::Instance()->ProcessKillDisplay(fID, fPlotNr);
}
//_____________________________________________________________________
void TMDisplaying::ProcessClone() {
  TMMainFrame::Instance()->ProcessCloneDisplay(fID, fPlotNr, fHist);
}
//_____________________________________________________________________
void TMDisplaying::ProcessUpdate() {
  Bool_t ihavelock = TMControlMutex::Instance()->DoIHaveLock();
  if (!ihavelock) {
    pthread_mutex_lock(&gMutex);
    //    printf("TMDisp::ProcessUpdate");
    TMControlMutex::Instance()->ITakeLock();
  }

  Update();

#ifdef MOVIE_VER
  if (fMovie) {
    MakeMovieShot();
  }
#endif

  if (!ihavelock) {
    TMControlMutex::Instance()->IReleaseLock();
    pthread_mutex_unlock(&gMutex);
  }
}
//_____________________________________________________________________
void TMDisplaying::Update() {
  if (fTheCanvas!=NULL) {
    TCanvas *canv = fTheCanvas->GetCanvas();
    Bool_t canvIsLocked=kFALSE;
    if (!canv->IsEditable()) {
      canvIsLocked=kTRUE;
      canv->SetEditable(kTRUE);
    }
    if (fHist->NeedRedraw()) fHist->Draw(canv);
    canv->Modified();
    canv->Update();
    if (canvIsLocked) canv->SetEditable(kFALSE);
  }

  TString msg;
  msg = Form("Events: %d",fHist->GetNrEvents());
  fStatusBar->SetText(msg.Data(),0);
  msg = Form("Last: %d",fHist->GetLastEventNumber());
  fStatusBar->SetText(msg.Data(),1);
  gSystem->ProcessEvents();
}
//_____________________________________________________________________
void TMDisplaying::UpdateAuto() {
  if (fAutoUpdate) {
    UpdateAutoAll();
  }
}
//_____________________________________________________________________
void TMDisplaying::UpdateAutoAll() {
  // get event number selection...
  UInt_t eventMod = atoi(fTextEventMod->GetText());
  UInt_t eventModEq = atoi(fTextEventModEq->GetText());
  if (eventMod==0) {
    printf("TMDisplaying::UpdateAutoAll: Event Selection Problem (changing first value to 1 !!!)\n");
    fTextEventMod->SetText("1");
    eventMod=1;
    eventModEq=0;
  }
  else if (fHist->GetLastEventNumber()%eventMod==eventModEq) {
    ProcessUpdate();
  }
}
//_____________________________________________________________________
void TMDisplaying::ProcessReset() {
  Bool_t ihavelock = TMControlMutex::Instance()->DoIHaveLock();
  if (!ihavelock) {
    pthread_mutex_lock(&gMutex);
    //    printf("TMDisp::ProcessReset");
    TMControlMutex::Instance()->ITakeLock();
  }

  fHist->Reset();
  Update();

  if (!ihavelock) {
    TMControlMutex::Instance()->IReleaseLock();
    pthread_mutex_unlock(&gMutex);
  }
}
//______________________________________________________________________
Bool_t TMDisplaying::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2) {
  //  printf("%d,%ld,%ld\n",GET_MSG(msg),parm1,parm2);
  if (fPleaseWait) {
    time_t stamp = time(NULL);
    TString stampMsg = Form("%s",ctime(&stamp));
    stampMsg.ReplaceAll("\n","");
    printf("Busy - Please try again... (Time %s)\n",stampMsg.Data());
    return kTRUE;
  }
  fPleaseWait = kTRUE;
  switch(GET_MSG(msg)) {
  case kC_COMMAND :
    switch (GET_SUBMSG(msg)) {

    case kCM_BUTTON :
      switch (parm1) {

      case BOTTOM_MOVIE :
	ToggleButton(BOTTOM_MOVIE);
	break;
      case BOTTOM_PAUSE :
	ToggleButton(BOTTOM_PAUSE);
	break;
      case BOTTOM_AUTOUPDATE :
	ToggleButton(BOTTOM_AUTOUPDATE);
	break;
      case BOTTOM_AUTORESET :
	ToggleButton(BOTTOM_AUTORESET);
	break;
      case BOTTOM_UPDATE :
	ProcessUpdate();
	break;
      case BOTTOM_RESET :
	ProcessReset();
	break;
      case BOTTOM_KILL :
	ProcessKill();
	break;
      case BOTTOM_CLONE :
	ProcessClone();
	break;
      case BOTTOM_TRIGMASK :
	ProcessTrigMask();
	break;
      case BOTTOM_SCREENSHOT :
	ProcessScreenShot();
	break;
      case SCREENSHOT2 :
	ProcessScreenShot2(TMConfig::Instance()->GETuploadCommand().Data());
	break;	

      }
    }

  }
  fPleaseWait = kFALSE;
  return kTRUE;
}
//______________________________________________________________________
void TMDisplaying::ToggleButton(Int_t id) {
  if (id == BOTTOM_AUTOUPDATE) {
    if (fBottomAutoUpdate->GetState() == kButtonUp) {
      ToggleAutoUpdateButton(kTRUE);
    }
    else {
      ToggleAutoUpdateButton(kFALSE);
    }
  }

  else if (id == BOTTOM_AUTORESET) {
    Bool_t autoreset;
    if (fBottomAutoReset->GetState() == kButtonUp) {
      ToggleAutoResetButton(kTRUE);
      fHist->SetAutoReset(kTRUE);
      autoreset=kTRUE;
    }
    else {
      ToggleAutoResetButton(kFALSE);
      fHist->SetAutoReset(kFALSE);
      autoreset=kFALSE;
    }
    TMMainFrame::Instance()->ProcessAutoResetDisplay(fID, fPlotNr, autoreset);
  }

  else if (id == BOTTOM_PAUSE) {
    Bool_t pause;
    if (fBottomPause->GetState() == kButtonUp) {
      TogglePauseButton(kTRUE);
      pause=kTRUE;
    }
    else {
      TogglePauseButton(kFALSE);
      pause=kFALSE;
    }
    TMMainFrame::Instance()->ProcessPauseDisplay(fID, fPlotNr, pause);
  }

#ifdef MOVIE_VER
  else if (id == BOTTOM_MOVIE) {
    if (fBottomMovie->GetState() == kButtonUp) {
      ToggleMovieButton(kTRUE);
    }
    else {
      ToggleMovieButton(kFALSE);
    }
  }
#endif

}

#ifdef MOVIE_VER
//______________________________________________________________________
void TMDisplaying::ProcessMovieStart() {
  fNrImg = 0;
  new TMMovie(gClient->GetRoot(), this);
}
//______________________________________________________________________
void TMDisplaying::ProcessMovieEnd() {
  TString command = Form("perl %s/bin/makeMovie.pl %s %d %s %d",
			 getenv("SPDMOOD_SITE"),
			 fImgDir.Data(),
			 fNrImg,
			 TMConfig::Instance()->GETmovieName().Data(),
			 TMConfig::Instance()->GETmovieDelay());
  printf("%s\n",command.Data());
  system(command.Data());
}
//______________________________________________________________________
void TMDisplaying::MakeMovieShot() {
  TString fileName = Form("%s/img%d.gif",fImgDir.Data(),fNrImg);
  ProcessScreenShot2(fileName.Data());
  fNrImg++;
}
//______________________________________________________________________
void TMDisplaying::ToggleMovieButton(Bool_t down) {
  if (fBottomMovie->GetState() == kButtonUp) {
    if (down) {
      ProcessMovieStart();
      fBottomMovie->AllowStayDown(kTRUE);
      fBottomMovie->SetBackgroundColor(green);
      fBottomMovie->SetState(kButtonDown);
      fMovie=kTRUE;
    }
  }
  else {
    if (!down) {
      ProcessMovieEnd();
      fBottomMovie->AllowStayDown(kFALSE);
      fBottomMovie->SetBackgroundColor(gray);
      fBottomMovie->SetState(kButtonUp);
      fMovie=kFALSE;
    }
  }
}
#endif

//______________________________________________________________________
void TMDisplaying::ToggleAutoUpdateButton(Bool_t down) {
  if (fBottomAutoUpdate->GetState() == kButtonUp) {
    if (down) {
      fBottomAutoUpdate->AllowStayDown(kTRUE);
      fBottomAutoUpdate->SetBackgroundColor(green);
      fBottomAutoUpdate->SetState(kButtonDown);
      fAutoUpdate=kTRUE;
    }
  }
  else {
    if (!down) {
      fBottomAutoUpdate->AllowStayDown(kFALSE);
      fBottomAutoUpdate->SetBackgroundColor(gray);
      fBottomAutoUpdate->SetState(kButtonUp);
      fAutoUpdate=kFALSE;
    }
  }
}
//______________________________________________________________________
void TMDisplaying::ToggleAutoResetButton(Bool_t down) {
  if (fBottomAutoReset->GetState() == kButtonUp) {
    if (down) {
      fBottomAutoReset->AllowStayDown(kTRUE);
      fBottomAutoReset->SetBackgroundColor(green);
      fBottomAutoReset->SetState(kButtonDown);
    }
  }
  else {
    if (!down) {
      fBottomAutoReset->AllowStayDown(kFALSE);
      fBottomAutoReset->SetBackgroundColor(gray);
      fBottomAutoReset->SetState(kButtonUp);
    }
  }
}
//______________________________________________________________________
void TMDisplaying::TogglePauseButton(Bool_t down) {
  if (fBottomPause->GetState() == kButtonUp) {
    if (down) {
      fBottomPause->AllowStayDown(kTRUE);
      fBottomPause->SetBackgroundColor(green);
      fBottomPause->SetState(kButtonDown);
    }
  }
  else {
    if (!down) {
      fBottomPause->AllowStayDown(kFALSE);
      fBottomPause->SetBackgroundColor(gray);
      fBottomPause->SetState(kButtonUp);
    }
  }
}
//______________________________________________________________________
void TMDisplaying::ProcessTrigMask() {
  new TMTrigMask(gClient->GetRoot(), this, fHist, TRIGMASK2);
}
//______________________________________________________________________
void TMDisplaying::ProcessScreenShot() {
  ULong_t runNb = TMControlSPD::Instance()->GetRunNb();
  new TMScreenShot(gClient->GetRoot(), this, SCREENSHOT2, runNb, GetWindowName());
}
//______________________________________________________________________
void TMDisplaying::ProcessScreenShot2(const Char_t *localFile) {
  Bool_t ihavelock = TMControlMutex::Instance()->DoIHaveLock();
  if (!ihavelock) {
    pthread_mutex_lock(&gMutex);
    //    printf("TMDisp::ProcessScreenSh2");
    TMControlMutex::Instance()->ITakeLock();
  }

  if (fTheCanvas==NULL) return;
  TCanvas *canv = fTheCanvas->GetCanvas();
  printf("Saving image '%s'...\n",localFile);
  canv->SaveAs(localFile);
  printf("Done!\n");

  if (!ihavelock) {
    TMControlMutex::Instance()->IReleaseLock();
    pthread_mutex_unlock(&gMutex);
  }
}
//______________________________________________________________________
void TMDisplaying::ProcessScreenShot2default(const Char_t *localDir, const Char_t *extension) {
  if (fTheCanvas==NULL) return;
  TCanvas *canv = fTheCanvas->GetCanvas();
  ULong_t runNb = TMControlSPD::Instance()->GetRunNb();
  TString localFile = Form("%s/image_%d_%s.%s",localDir,runNb,GetWindowName(),extension);
  localFile.ReplaceAll(' ','_');
  printf("Saving image '%s'...\n",localFile.Data());
  canv->SaveAs(localFile.Data());
  printf("Done!\n");
}
//______________________________________________________________________
void TMDisplaying::ProcessStartRun() {
  //  fTheCanvas->Disconnect();
}
//______________________________________________________________________
void TMDisplaying::ProcessEndRun() {
  //  fTheCanvas->Connect();
}
