/* ======================================================================== *\
!
! *
! * This file is part of MARS, the MAGIC Analysis and Reconstruction
! * Software. It is distributed to you in the hope that it can be a useful
! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
! * It is distributed WITHOUT ANY WARRANTY.
! *
! * Permission to use, copy, modify and distribute this software and its
! * documentation for any purpose is hereby granted without fee,
! * provided that the above copyright notice appear in all copies and
! * that both that copyright notice and this permission notice appear
! * in supporting documentation. It is provided "as is" without express
! * or implied warranty.
! *
!
!
!   Author(s): Harald Kornmayer 1/2001 (harald@mppmu.mpg.de)
!   Author(s): Thomas Bretz  12/2000 (tbretz@uni-sw.gwdg.de)
!
!   Copyright: MAGIC Software Development, 2000-2001
!
!
\* ======================================================================== */

#include "MGFadcDisp.h"

#include <stdlib.h>
#include <iostream.h>

#include <TGButton.h>      // TGPictureButton
#include <TGLabel.h>       // TGLabel
#include <TGTab.h>         // TGTab
#include <TGListBox.h>     // TGListBox
#include <TGSlider.h>      // TGVSlider
#include <TRootEmbeddedCanvas.h>      // TRootEmbeddedCanvas
#include <TCanvas.h>
#include <TGTextEntry.h>   
#include <TGMsgBox.h>
#include <TG3DLine.h>      // TGHorizontal3DLine
                           // use TGSplitter instead for root<3.00


#include "MParList.h"
#include "MRawRunHeader.h"
#include "MRawEvtHeader.h"
#include "MTime.h"
#include "MRawEvtData.h"
#include "MRawCrateArray.h"
#include "MReadTree.h"
#include "MRawEvtPixelIter.h"

ClassImp(MGFadcDisp)


MGFadcDisp::MGFadcDisp(char *filename, char *treename, 
		       const TGWindow *p, const TGWindow *main, 
		       UInt_t w, UInt_t h ) 
        : TGTransientFrame(p, main, w, h )  
{
  //   default constructor 

  //   first connect the file with this Object

    pList = new MParList();

  fRunHeader = new MRawRunHeader();
  pList->AddToList(fRunHeader);

  fEvtHeader = new MRawEvtHeader();
  pList->AddToList(fEvtHeader);
  fEvtTime   = new MTime();
  pList->AddToList(fEvtTime);
  fEvtData   = new MRawEvtData();
  pList->AddToList(fEvtData);
  fEvtCrate  = new MRawCrateArray();
  pList->AddToList(fEvtCrate);

  
  fReadTree  =  new MReadTree ( treename, filename ) ;
  fReadTree->PreProcess( pList ) ; 

  //
  //   the top part of the window
  //
  fFrameTop = new TGVerticalFrame (this, 300, 100 ) ; 

  fTop1 = new TGHorizontalFrame (fFrameTop, 300, 100 ) ;
  
  fLabelFile = new TGLabel(fTop1, new TGString("File:") );
  fTop1->AddFrame( fLabelFile, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10)) ; 

  fNameFile = new TGLabel(fTop1, new TGString( filename ) );
  fTop1->AddFrame( fNameFile, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10)) ; 

  fLabelTree = new TGLabel(fTop1, new TGString("Tree:") );
  fTop1->AddFrame( fLabelTree, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10)) ; 

  fNameTree = new TGLabel(fTop1, new TGString( treename ) );
  fTop1->AddFrame( fNameTree, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10)) ;

  fFrameTop->AddFrame(fTop1,new TGLayoutHints (kLHintsTop ) ) ; 

  fTop2 = new TGHorizontalFrame (fFrameTop, 300, 100 ) ;
  
  fButtonPrevEvt = new TGTextButton (fTop2, "<< Previous Event", M_PREVEVT ) ;
  fButtonPrevEvt->Associate(this) ; 
  fTop2->AddFrame (fButtonPrevEvt, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10  ) ) ; 
  
  fLabelEvtNr = new TGLabel(fTop2, new TGString("Event: ") );
  fTop2->AddFrame( fLabelEvtNr, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10)) ; 

  fTxtEvtNr = new TGTextEntry(fTop2, fTxtBufEvtNr = new TGTextBuffer(100), M_EVTNUMBER);
  fTxtEvtNr->Resize(60, fTxtEvtNr->GetDefaultHeight());
  fTxtEvtNr->Associate(this) ; 
  fTop2->AddFrame(fTxtEvtNr, new TGLayoutHints(kLHintsTop | kLHintsLeft,
                                                       5, 5, 5, 5)); 

  char wortdummy[100] ; 
  sprintf (wortdummy, "out of %d Events", fReadTree->GetEntries() ) ; 
  fLabelTotNr = new TGLabel(fTop2, new TGString( wortdummy ) );
  fTop2->AddFrame( fLabelTotNr, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10)) ; 
  
  fButtonNextEvt = new TGTextButton (fTop2, "Next Event >>", M_NEXTEVT ) ; 
  fButtonNextEvt->Associate(this) ; 
  fTop2->AddFrame (fButtonNextEvt, new TGLayoutHints (kLHintsLeft, 10, 10, 10, 10  ) ) ; 

  
  fFrameTop->AddFrame(fTop2,new TGLayoutHints ( kLHintsCenterX ) ) ; 

  

  AddFrame(fFrameTop, new TGLayoutHints (kLHintsTop | kLHintsCenterX ) ) ;   
  
  //   a line between top and mid frame

  fLineSep1 = new TGHorizontal3DLine(this) ; 
  AddFrame(fLineSep1, new TGLayoutHints(kLHintsTop | kLHintsExpandX) );

  //
  //   the middle part of the window
  //
  
  fFrameMid = new TGHorizontalFrame (this, 300, 100 ) ; 
  
  //   the left part is the control tab enviroment
  
  fTabControl = new TGTab(fFrameMid, 300, 300);
  TGCompositeFrame *tControl = fTabControl->AddTab("PixelList");     
  tControl->ChangeOptions ( kHorizontalFrame ) ; 


  fPixelList = new TGListBox(tControl, M_PIXELLIST ) ; 
  fPixelList->Associate(this) ; 
  tControl->AddFrame(fPixelList, new TGLayoutHints(kLHintsExpandY | kLHintsLeft, 5, 5, 5, 5 ) ) ; 
  fPixelList->Resize(80, 230 ) ;

  fMid1 = new TGVerticalFrame (tControl, 300, 100 ) ; 
  
  
  fButtonPrevPix = new TGTextButton (fMid1, "<< Prev Pixel", 9999 ) ; 
  fMid1->AddFrame(fButtonPrevPix, new TGLayoutHints(kLHintsRight) ) ; 

  fPixSlider = new TGVSlider (fMid1, 200, kSlider1 | kScaleBoth, 9999 );
  fPixSlider->Associate(this);
  fPixSlider->SetRange(0, 576);
  fMid1->AddFrame(fPixSlider, new TGLayoutHints(kLHintsCenterX | kLHintsExpandY));
  
  fButtonNextPix = new TGTextButton (fMid1, "Next Pixel >>", 9999 ) ; 
  fMid1->AddFrame(fButtonNextPix, new TGLayoutHints(kLHintsRight) ) ; 

  tControl->AddFrame(fMid1, new TGLayoutHints(kLHintsRight | kLHintsExpandY, 5, 5, 5, 5)) ; 
  
  fFrameMid-> AddFrame(fTabControl, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY, 10, 10, 10 ,10 ) );  

  //   the right part is the display tab enviroment
  
  fTabDisplay = new TGTab(fFrameMid, 300, 300);
  TGCompositeFrame *tDisplay = fTabDisplay->AddTab("Digital Scope");     

  fECanDigScope = new TRootEmbeddedCanvas("fECanDigScope", tDisplay, 400, 400 ) ;
  tDisplay->AddFrame( fECanDigScope, new TGLayoutHints ( kLHintsCenterX | kLHintsCenterY | kLHintsExpandX | kLHintsExpandY ) ) ; 

  fCan = fECanDigScope->GetCanvas() ;
        

  fFrameMid-> AddFrame(fTabDisplay, new TGLayoutHints(kLHintsTop | kLHintsLeft | kLHintsExpandY | kLHintsExpandX  , 10, 10, 10 ,10 ) );  
  
  
  AddFrame(fFrameMid, new TGLayoutHints (kLHintsExpandY | kLHintsExpandX ) ) ;   

  //   a line between mid and low frame
  
  fLineSep2 = new TGHorizontal3DLine(this) ; 
  AddFrame(fLineSep2, new TGLayoutHints(kLHintsTop | kLHintsExpandX) );

   //   the low part of the window
  //
  fFrameLow = new TGHorizontalFrame (this, 300, 100 ) ; 
 
  
  fButtonPrint = new TGTextButton(fFrameLow, "Print", M_PRINT) ; 
  fButtonPrint->Associate(this) ; 
  fFrameLow->AddFrame( fButtonPrint, new TGLayoutHints(kLHintsLeft , 10, 10, 10, 10 ) )  ; 

  fButtonClose = new TGTextButton(fFrameLow, "Close", M_CLOSE) ; 
  fButtonClose->Associate(this) ; 
  fFrameLow->AddFrame( fButtonClose, new TGLayoutHints(kLHintsLeft, 10, 10, 10, 10 ) )  ; 

 
  AddFrame(fFrameLow, new TGLayoutHints (kLHintsTop ) ) ;   

  //
  //   Map the window, set up the layout, etc. 
  //
  SetWMSizeHints(450, 400, 1000, 1000, 10, 10 ) ;      // set the smallest and biggest size of the Main frame

  MapSubwindows();
  
  Layout();
  
  SetWindowName("FadcDisplay");
  SetIconName("FadcDisp");
  
  MapWindow();

  //
  //   fReadTree the first event and update the window
  //
  fReadTree->GetEvent() ; 
  CreatePixelList() ; 
  UpdateEventCounter() ; 

}


MGFadcDisp::~MGFadcDisp()
{
  // close the file 

  fReadTree->PostProcess() ; 

  delete  fRunHeader ; 
  delete  fEvtHeader ;
  delete  fEvtTime   ;
  delete  fEvtData ; 
  delete  fEvtCrate  ; 

  delete  pList ;

  delete  fReadTree ; 

  //   destruct the graphical members  

  delete  fButtonPrint ; 
  delete  fButtonClose ; 
 
  //  delete  fCan ; 
  delete  fECanDigScope ; 
  delete  fTabDisplay ; 
 
  delete  fPixSlider ; 
  delete  fButtonPrevPix ; 
  delete  fButtonNextPix ; 
  delete  fMid1 ; 
  delete  fPixelList; 
  delete  fTabControl  ; 
 
  delete  fLabelEvtNr ; 
  delete  fLabelTotNr ; 
  //delete  fTxtBufEvtNr ; 
  delete  fTxtEvtNr ; 
  delete  fButtonNextEvt ; 
  delete  fButtonPrevEvt ; 
  delete  fLabelTree ; 
  delete  fNameTree ; 
  delete  fNameFile ; 
  delete  fLabelFile ; 
  delete  fTop2 ; 
  delete  fTop1 ; 
  
  delete  fFrameLow ; 
  delete  fLineSep2 ; 
  delete  fFrameMid ; 
  delete  fLineSep1 ; 
  delete  fFrameTop ; 
}


void MGFadcDisp::CloseWindow()
{
   // Got close message for this MainFrame. Calls parent CloseWindow()
   // (which destroys the window) and terminate the application.
   // The close message is generated by the window manager when its close
   // window menu item is selected.

    delete this ;
}
       

void MGFadcDisp::CreatePixelList(Int_t lastsel)
{
    //
    //   after a new event is read in one has to update
    //   the list of pixels in the fPixelList (TGListBox)
    //

    //
    //   put the selection of the last event in memory
    //
    MRawEvtPixelIter pixel(fEvtData);
    while (pixel.Next())
    {
        char wortdummy[100] ;
        sprintf(wortdummy, "%d", pixel.GetPixelId());
        fPixelList->AddEntry(wortdummy, pixel.GetPixelId());
    }

    fPixelList->MapSubwindows();
    fPixelList->Layout();

    //
    // check if the pixel from last event also occurs in this event
    //
    fCan->Clear() ;
    fCan->cd() ;

    if (lastsel<0 || !pixel.Jump(lastsel))
    {
        pixel.Reset();
        lastsel=pixel.GetPixelId();

    }

    char wortdummy[100] ;
    sprintf(wortdummy, "GRAPH%d", lastsel);
    fEvtData->Draw(wortdummy);
    fPixelList->Select(lastsel, kTRUE);

    fCan->Modified();
    fCan->Update();
}

void MGFadcDisp::UpdateEventCounter() 
{
  //     Update the event counter 
  
  char wortdummy[256] ; 
    
  sprintf (wortdummy, "%d", fReadTree->GetEventNum() )  ; 
  
  fTxtEvtNr->SetText(wortdummy) ; 
}

void MGFadcDisp::ReadinEvent(UInt_t iEvt)
{
    Int_t buttons = 4;
    Int_t retval = 0 ;

    //  first check if the new event is in the range of possible events
  
    if ( iEvt >= fReadTree->GetEntries() )
    {
        new TGMsgBox(fClient->GetRoot(), this,
                     "WARNING!",
                     "The event number is out of range!!!",
                     kMBIconExclamation, buttons, &retval);
    }
    else
    {
        const Int_t lastsel = fPixelList->GetSelected();

        fPixelList->RemoveEntries(0, fEvtData->GetNumPixels());

        fReadTree->SetEventNum(iEvt);
        fReadTree->GetEvent();

        CreatePixelList(lastsel);
    }

    UpdateEventCounter();
}

Bool_t MGFadcDisp::ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2) 
{
  //------------------------------------------------------------------
  //
  //    ProcessMessage(Long_t msg, Long_t parm1, Long_t parm2)
  //
  // Processes information from all GUI items.
  // Selecting an item usually generates an event with 4 parameters.
  // The first two are packed into msg (first and second bytes).
  // The other two are parm1 and parm2.
  //
  //------------------------------------------------------------------
  char wortdummy[256] ; 
  Int_t   buttons = 4, retval = 0 ;

  switch(GET_MSG(msg)) 
    {
    case kC_COMMAND:
    
      switch(GET_SUBMSG(msg)) 
	{
	  
	case kCM_BUTTON:
	  
	  switch (parm1)
	    {
	    case M_PREVEVT:
	      ReadinEvent(fReadTree->GetEventNum()-1 ) ; 
	      break; 
	      
	    case M_NEXTEVT:
	      ReadinEvent(fReadTree->GetEventNum()+1 ) ; 
	      break; 


	    case M_PRINT:
	      new TGMsgBox(fClient->GetRoot(), this,
			   "INFORMATION!",
			   "Your are invited to program that!!",
			   kMBIconExclamation, buttons, &retval); 
	      
              break ;

	    case M_CLOSE:
	      CloseWindow() ; 
	      break; 

	    }
	  
	case kCM_LISTBOX:
	  switch (parm1) 
	    {
	    case M_PIXELLIST:
	      sprintf(wortdummy, "GRAPH%d", fPixelList->GetSelected());

	      fCan->Clear() ;
	      fCan->cd() ; 

	      fEvtData->Draw(wortdummy) ; 
	      
	      fCan->Modified() ; 
	      fCan->Update() ; 
	      break; 
	    }
	  break; 
	  
	}
    
    case kC_TEXTENTRY:
      
      switch(GET_SUBMSG(msg)) 
	{
	case kTE_TEXTCHANGED:
            break ;

        case kTE_ENTER:
            {
                const char *txt = fTxtEvtNr->GetText();
                ReadinEvent(atoi(txt));
            }
	  break; 
	}
      break; 
      
    default:
      break;     
    }

  return kTRUE ; 
}
