#ifndef DspTestbeamView_HH
#define DspTestbeamView_HH

#include <iostream>
#include <fstream>
#include <sstream>

#include "TROOT.h"
#include "TApplication.h"
#include "TCanvas.h"
#include "TLatex.h"
#include "TPaveLabel.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TH3.h"
#include "TLine.h"
#include "TPolyLine.h"
#include "TBox.h"
#include "TPostScript.h"

#include "TView.h"
#include "TAxis3D.h"
#include "TPolyLine3D.h"
#include "TPolyMarker3D.h"
#include "TMarker3DBox.h"

#include "TMaterial.h"
#include "TRotMatrix.h"
#include "TNode.h"
#include "TBRIK.h"
#include "TTUBE.h"

#include "RcdRecord.hh"
#include "SubAccessor.hh"

#include "EmcEventEnergy.hh"


class DspTestbeamView 
{
   
   public:  
  
  
   DspTestbeamView() : _application("Event Display Application",0,0) , theLayout(BuildLayoutDesyJan())
   {
      gROOT->Reset();
      gROOT->SetStyle("Plain");
    
 
      //......................................................................      
      //GM stuff starts here
      
      theViewCanvas=new TCanvas("Event Display","Event Display",300,300,10*80,11*80);
    
      theLabel[0] = new TPaveLabel(0.01,0.91,0.45,0.99,"Run ... Event ...");
      theLabel[0]->SetBorderSize(0);
      theLabel[1] = new TPaveLabel(0.46,0.95,0.99,0.99,"Record header info ...");
      theLabel[1]->SetBorderSize(0);
      theLabel[2] = new TPaveLabel(0.46,0.91,0.99,0.95,"DaqEvent info ...");
      theLabel[2]->SetBorderSize(0);
    

      thePad[0] = new TPad("p0","",0.01,0.67/1.1,  0.33,0.99/1.1,38);
      thePad[1] = new TPad("p1","",0.35,0.67/1.1,  0.99,0.99/1.1,38);

      thePad[2] = new TPad("p2","",0.01,0.01/1.1,  0.33,0.65/1.1,38);
      thePad[3] = new TPad("p3","",0.35,0.01/1.1,  0.99,0.65/1.1,38);
    
      thePad[0]->Draw();
      thePad[1]->Draw();
      thePad[2]->Draw();  
      thePad[3]->Draw();
  
      theLabel[0]->Draw();
      theLabel[1]->Draw();
      theLabel[2]->Draw();
        
   }
//............................................................................
   virtual ~DspTestbeamView() 
   {
   }

//............................................................................
   void Layout(char* opt = "onlyLayout")
   {
      this->ShowLayout(); 
      theViewCanvas->Print("viewLayout.gif");  
   }
//............................................................................
   void event(const RcdRecord &r, 
              const EmcEventEnergy &energy, 
	      const double &threshold,       //threshold cut in ADC channels
	      const unsigned iRun=0,         //print out info 
	      const unsigned iEvent=0,       //print out 
	      bool doPs=false)               //dump view in eps, gif   
   {
      if(r.recordType()!=RcdHeader::event) return;

      /*
      TPostScript *pps(0);
      if(doPs) {
        pps=new TPostScript("display.ps",112);
      }
      */

      SubAccessor extracter(r);

      std::ostringstream oss;
      r.RcdHeader::print(oss);

 
      std::ostringstream oss2;
      std::vector<const DaqEvent*> w(extracter.extract<DaqEvent>());
      if(w.size()>0) w[0]->print(oss2);

  
    
      theViewCanvas->cd();
      theLabel[1]->SetLabel(oss.str().c_str());
      theLabel[2]->SetLabel(oss2.str().c_str());
      theLabel[1]->Draw();
      theLabel[2]->Draw();
    
      std::ostringstream ll; 
      ll << "Run " << iRun << " Event " << iEvent ;
      theLabel[0]->SetLabel(ll.str().c_str());
    

      this->ShowLayout();
  
      for(int x(0);x<NumOfCellsX;x++) 
      {  for(int y(0);y<NumOfCellsY;y++) 
         {  for(int z(0);z<NumOfLayers;z++) 
	    {  
	       
	       if(energy.energy(EmcPhysicalPad(x,y,z))>threshold) 
	       {  
	          TPolyMarker3D *pl = new TPolyMarker3D(1,3);
                  pl->SetPoint(0,theCell[x][y][z]->GetX(),
		                 theCell[x][y][z]->GetY(),
		                 theCell[x][y][z]->GetZ());
				 
			
        	//pl->SetPoint(0,theCell[x][y][z]->GetX(),
		 //                theCell[x][y][z]->GetZ(),
		  //               -theCell[x][y][z]->GetY());
			
			
				 
	          pl->SetMarkerColor(2);//red  
                  pl->SetMarkerStyle(8);
                  pl->SetMarkerSize(.4);
		  		  
		  TMarker3DBox *pp = new TMarker3DBox(theCell[x][y][z]->GetX(),
		                                      theCell[x][y][z]->GetY(),
		  				      theCell[x][y][z]->GetZ(),.4,.4,.2,0,0);
		  
	          thePad[0]->cd();
	          pl->Draw();
		  pp->Draw();
	    
	          thePad[1]->cd();
	          pl->Draw();
		  pp->Draw();
	    
	          thePad[2]->cd();
	          pl->Draw();
		  pp->Draw();
	    
                  thePad[3]->cd();
	          pl->Draw();
		  pp->Draw();
		  		  
               }
	    }
         }
      }  


      theViewCanvas->Update();




      if(doPs) 
      {
	 
	 std::ostringstream filename; 
         filename << "viewRun" << iRun << "Event" << iEvent << ".gif";
         theViewCanvas->Print(filename.str().c_str());
	 //theViewCanvas->Print("display.gif");
	 
	 
      }
      
   }
//............................................................................


   protected:



   void ShowLayout()
   { 
      
      thePad[0]->cd();
      thePad[0]->Clear();
      this->ShowView(1);
    
      thePad[1]->cd();
      thePad[1]->Clear();
      this->ShowView(2);
    
      thePad[2]->cd();
      thePad[2]->Clear();
      this->ShowView(3);
    
      thePad[3]->cd();
      thePad[3]->Clear();
      this->ShowView(0);
    
   }
//............................................................................
   void ShowAxis(float x0=0, float y0=0, float z0=0, float length=4)
   {
      TPolyLine3D *axisX = new TPolyLine3D();
      axisX->SetPoint(0,x0,y0,z0);
      axisX->SetPoint(1,x0+length,y0,z0);
      axisX->SetLineColor(4);//blue
      axisX->SetLineWidth(2);
    
      TPolyLine3D *axisY = new TPolyLine3D();
      axisY->SetPoint(0,x0,y0,z0);
      axisY->SetPoint(1,x0,y0+length,z0);
      axisY->SetLineColor(5);//yellow
      axisY->SetLineWidth(2);
    
      TPolyLine3D *axisZ = new TPolyLine3D();
      axisZ->SetPoint(0,x0,y0,z0);
      axisZ->SetPoint(1,x0,y0,z0+length);
      axisZ->SetLineColor(2);//red
      axisZ->SetLineWidth(2);
    
      axisX->Draw();
      axisY->Draw();
      axisZ->Draw();
   }  
//............................................................................
   void ShowView(int opt=0)
   { 
      theLayout->Draw();
      
      this->ShowAxis(-15,-15,-20,4);  
    
      int iret;
      switch(opt)
      {
         case 0:
	   gPad->GetView()->SetPerspective();
	   //gPad->GetView()->SetView(-65,127,-73,iret);
           gPad->GetView()->SetView(-335,127,-73,iret);	   
           gPad->GetView()->ZoomView(0,1.9);
	   //gPad->GetView()->ShowAxis();
           //gPad->GetView()->ZoomIn();
	   break;

	 case 1:
	   gPad->GetView()->SetParralel();
	   gPad->GetView()->SetView(90,180,0,iret);
           gPad->GetView()->ZoomView(0,1.5);
           //gPad->GetView()->Top();
	   //gPad->GetView()->ShowAxis();
           break;  

	 case 2:
	   gPad->GetView()->SetParralel();
           gPad->GetView()->SetView(0,90,-90,iret);
	   gPad->GetView()->ZoomView(0,1.5);
	   //gPad->GetView()->Side();
	   //gPad->GetView()->ShowAxis();
	   break;
	   
	 case 3:
	   gPad->GetView()->SetParralel();
	   gPad->GetView()->SetView(90,90,0,iret);
           gPad->GetView()->ZoomView(0,1.5);
	   //gPad->GetView()->Front();
           //gPad->GetView()->ShowAxis();
      }
      
      gPad->SetFillColor(17);//light grey
   
   }
//............................................................................    
   TNode* BuildLayout()
   { 

      TNode *mother,*tempNode;

      //
      int   NofWafX      = 3;
      int   NofWafY      = 3;
      int   nCellsPerWaf = 6; 
      float offsetX      = 8;
      float offsetY      = 8;
      float offsetZ      = 10;
      float x,y,z;


      //these are dummy
      TMaterial *mat;     
      TRotMatrix *rot;
      mat = new TMaterial("mat","mat",1.01,1,.0708);
      rot = new TRotMatrix("rot","rot",90,0,90,90,0,0);


      //building blocks
      TBRIK *cave = new TBRIK("cave","cave","mat",100,100,100);
      cave->SetVisibility(0);

      TBRIK *wafer = new TBRIK("wafer","wafer","mat",3,3,.1);
      wafer->SetLineColor(5);//yellow

      TBRIK *cell = new TBRIK("cell","cell","mat",.5,.5,.05);
      cell->SetLineColor(10);//white

      TBRIK *layer = new TBRIK("layer","layer","mat",12,12,1.5);
      layer->SetLineColor(15);//grey
      
      //not used
      TTUBE *hit = new TTUBE("hit","hit","mat",.2,.4,.2);
      hit->SetLineColor(1);//black


      //build geometry nodes = volumes for display 
      mother = new TNode("temp","temp","cave");

      mother->cd();
      for(int iw=0;iw<NofWafX;iw++)
      {  for(int jw=0;jw<NofWafY;jw++)   
         {  for(int k=0; k<NumOfLayers;k++) 
            {  
	       x = offsetX*(iw-1);
	       y = offsetY*(jw-1);
	       z = offsetZ*k;
	       tempNode = new TNode("temp","temp","wafer",x,y,z,"");
            }
         }   
      }
      
      mother->cd();
      for(int i=0;i<NumOfCellsX;i++)
      {  for(int j=0;j<NumOfCellsY;j++)   
         {  for(int k=0; k<NumOfLayers;k++) 
            {  
	       //theCell[i][j][k] = new TNode("temp","temp","cell",(8)*(i/6)  + i%6 -3 -8+.5,(8)*(j/6) +j%6-3-8+.5,10*k,"");
	       x = offsetX*(i/nCellsPerWaf - 1)  + i%nCellsPerWaf - wafer->GetDx() + cell->GetDx(); 
	       y = offsetY*(j/nCellsPerWaf - 1)  + j%nCellsPerWaf - wafer->GetDy() + cell->GetDy(); 
	       z = offsetZ*k;
	       theCell[i][j][k] = new TNode("temp","temp","cell",x,y,z,"");
            }
         }   
      }

      mother->cd();
      for(int k=0;k<NumOfLayers;k++)
      {  
         x = 0.;
	 y = 0.;
	 z = offsetZ*k;
         tempNode = new TNode("temp","temp","layer",x,y,z,"");
      }


      return mother;
      

   }
//............................................................................    
   TNode* BuildLayoutDesyJan()
   { 

      TNode *mother,*tempNode;

      //
      int   nBlocks         = 2;
      int   nLayersPerBlock = 10;
      float offsetBlock     = 3.;
      
      int   NofWafX      = 3;
      int   NofWafY      = 3;
      int   NskipWafY    = 1;
      int   NskipCelY    = 6;  
      
      int   nCellsPerWaf = 6;//this means 6X6 
      float offsetX      = 7;
      float offsetY      = 7;
      float offsetZ      = 3;
      
      float x,y,z;


      //these are dummy
      TMaterial *mat;     
      TRotMatrix *rot;
      mat = new TMaterial("mat","mat",1.01,1,.0708);
      rot = new TRotMatrix("rot","rot",90,0,90,90,0,0);
      //rot = new TRotMatrix("rot","rot",90,0,180,0,90,90);


      //building blocks
      TBRIK *world = new TBRIK("world","world","mat",100,100,100);
      world->SetVisibility(0);

      TBRIK *cave = new TBRIK("cave","cave","mat",100,100,100);
      cave->SetVisibility(0);

      TBRIK *wafer = new TBRIK("wafer","wafer","mat",3,3,.1);
      wafer->SetLineColor(5);//yellow

      TBRIK *cell = new TBRIK("cell","cell","mat",.5,.5,.05);
      cell->SetLineColor(10);//white
      cell->SetVisibility(0);
   

      TBRIK *layer = new TBRIK("layer","layer","mat",12,12,1.);
      layer->SetLineColor(15);//grey
      
      TBRIK *block = new TBRIK("block","block","mat",12,12,15);
      block->SetLineColor(1);//black
      
      TBRIK *chamber = new TBRIK("chamber","chamber","mat",18,18,2);
      chamber->SetLineColor(1);//black
            
      TBRIK *wafertemp = new TBRIK("wafertemp","wafertemp","mat",3,3,.1);
      wafertemp->SetLineColor(14);//grey
            
      //for display only
      TBRIK *celltemp = new TBRIK("celltemp","celltemp","mat",.5,.5,.05);
      celltemp->SetLineColor(10);//white
      //celltemp->SetVisibility(0);

      
      //not used
      TTUBE *hit = new TTUBE("hit","hit","mat",.2,.4,.2);
      hit->SetLineColor(1);//black


      //build geometry nodes = volumes for display 
      
      TNode *test = new TNode("temp","temp","world");
      
      test->cd();
      mother = new TNode("temp","temp","cave",0,0,0,"rot");

   
      //--- ATTENTION --- this is correct only for the first block --- start  >>>
      
      mother->cd();
      for(int iw=0;iw<NofWafX;iw++)
      {  for(int jw=0+NskipWafY;jw<NofWafY;jw++)   
         {  for(int k=0; k<NumOfLayers;k++) 
            {  
	       x = offsetX*(iw-1);
	       y = offsetY*(jw-1);
	       z = offsetBlock*(k/nLayersPerBlock) + offsetZ*k;
	       tempNode = new TNode("temp","temp","wafer",x,y,z,"");
            }
         }   
      }
      
      mother->cd();
      for(int i=0;i<NumOfCellsX;i++)
      {  for(int j=0+NskipCelY;j<NumOfCellsY;j++)   
         {  for(int k=0; k<NumOfLayers;k++) 
            {  
	       //theCell[i][j][k] = new TNode("temp","temp","cell",(8)*(i/6)  + i%6 -3 -8+.5,(8)*(j/6) +j%6-3-8+.5,10*k,"");
	       x = offsetX*(i/nCellsPerWaf - 1)  + i%nCellsPerWaf - wafer->GetDx() + cell->GetDx(); 
	       y = offsetY*(j/nCellsPerWaf - 1)  + j%nCellsPerWaf - wafer->GetDy() + cell->GetDy(); 
	       z = offsetBlock*(k/nLayersPerBlock) + offsetZ*k;
	       theCell[i][j][k] = new TNode("temp","temp","cell",x,y,z,"");
            }
         }   
      }

      mother->cd();
      for(int k=0;k<NumOfLayers;k++)
      {  
         x = 0.;
	 y = 0.;
	 z = offsetBlock*(k/nLayersPerBlock) + offsetZ*k;
         tempNode = new TNode("temp","temp","layer",x,y,z,"");
      }

      //------------------------------------------------------------- <<< end 

   
      mother->cd();
      for(int k=0;k<NumOfLayers;k++)
      {  
         x = 0.;
	 y = 0.;
	 z = offsetBlock*(k/nLayersPerBlock) + offsetZ*k;
         tempNode = new TNode("temp","temp","layer",x,y,z,"");
      }

      mother->cd();
      for(int iw=0;iw<NofWafX;iw++)
      {  for(int jw=0+NskipWafY;jw<NofWafY;jw++)   
         {  for(int k=0; k<NumOfLayers;k++) 
            {  
	       x = offsetX*(iw-1);
	       y = offsetY*(jw-1);
	       z = offsetBlock*(k/nLayersPerBlock) + offsetZ*k;
	       tempNode = new TNode("temp","temp","wafertemp",x,y,z,"");
            }
         }   
      }
      
      //show only the first layer of cells per block for better visibility
      mother->cd();
      for(int i=0;i<NumOfCellsX;i++)
      {  for(int j=0+NskipCelY;j<NumOfCellsY;j++)   
         {  for(int k=0; k<nBlocks;k++) 
            {  
	       x = offsetX*(i/nCellsPerWaf - 1)  + i%nCellsPerWaf - wafer->GetDx() + cell->GetDx(); 
	       y = offsetY*(j/nCellsPerWaf - 1)  + j%nCellsPerWaf - wafer->GetDy() + cell->GetDy(); 
	       z = offsetBlock*k+offsetZ*nLayersPerBlock*k;
	       tempNode = new TNode("temp","temp","celltemp",x,y,z,"");
            }
         }   
      }

      mother->cd();
      for(int k=0;k<nBlocks;k++)
      {  
         x = 0.;
	 y = 0.;
	 z = offsetBlock*k+offsetZ*nLayersPerBlock*k + block->GetDz() - layer->GetDz();
         tempNode = new TNode("temp","temp","block",x,y,z,"");
      }


      mother->cd();
      for(int k=0;k<2;k++)
      {  
         x = 0.;
	 y = 0.;
	 z = 20*k-60;
         tempNode = new TNode("temp","temp","chamber",x,y,z,"");
      }

      //return mother;
      return test;
      

   }
//............................................................................  
   
   private:
   
   TApplication _application;
   
   TCanvas *theViewCanvas;
   TNode *theLayout;
   TPad *thePad[4];
   TPaveLabel *theLabel[3];
      
   const static int NumOfCellsX = 18;
   const static int NumOfCellsY = 18;
   const static int NumOfLayers = 14;
   TNode *theCell[NumOfCellsX][NumOfCellsY][NumOfLayers];
   
//////////////////////////////////////////////////////////////////////////////
//beam comes from Z = -inf, cell numbering is 
//
//            ^y              [17,17]..... [0,17]
//            .                              . 
//            .                              .
//     x<......               [17,0] ......[0,0]
//
//
//
//
//
//So when talking to engineers, operating the table,
//writing to logbook the wafer numbering is
//
//[1] [2] [3]
//[4] [5] [6]
//[7] [8] [9]
//
//In the offline code it is wX,wY
//
//
//[3,3] [2,3] [1,3]
//[3,2] [2,2] [1,2]
//[3,1] [2,1] [1,1]
//
//and for the pads inside each wafer, pX,pY it is
//
//[6,6] . . . .  [1,6]
//                 .
//                 .
//                 .
//                 .
//[6,1] . . . .  [1,1]
// 
// with left = +x  <---attention
//     right = -x
//        up = +y
//      down = -y
//    beam comes from z=-inf
////////////////////////////////////////////////////////////////////////////// 

};

#endif
