#include "Utilities/Configuration/interface/Architecture.h"
#undef HEP_SHORT_NAMES
#include "Visualisation/CustomTkEvent/interface/TwigTk2DSimTracks.h"
#include <iostream>
#include "Visualisation/CustomTracker/interface/TkSceneUpdate.h"
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoSeparator.h>
//
#include <Inventor/nodes/SoMaterial.h>
#include "Inventor/SbLinear.h"
#include <Inventor/nodes/SoTranslation.h>
#include <Inventor/nodes/SoTransform.h>
#include <Inventor/nodes/SoRotation.h>
#include <Inventor/nodes/SoIndexedLineSet.h>
#include <Inventor/nodes/SoResetTransform.h>
#include "Ig_Extensions/IgOpenInventor/interface/IgSoG4Trap.h"
#include "Ig_Extensions/IgOpenInventor/interface/IgSoCube.h"

#include "Tracker/TkLayout/interface/FullTracker.h"
#include "Tracker/TkLayout/interface/CmsTracker.h"
#include "ClassReuse/GeomVector/interface/GlobalPoint.h"
#include "CommonDet/DetGeometry/interface/TkRotation.h"
#include "CommonDet/DetGeometry/interface/Surface.h"
#include "CommonDet/DetGeometry/interface/ActiveMediaShape.h"
#include "CommonDet/DetLayout/interface/DetLayer.h"
#include "CommonDet/BasicDet/interface/DetUnit.h"
#include "CommonDet/BasicDet/interface/Enumerators.h"
#include "CommonDet/BasicDet/interface/Det.h"
#include "CommonDet/BasicDet/interface/DetType.h"

#include <map>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoIndexedLineSet.h>

//
#include "Ig_Extensions/IgOpenInventor/interface/IgSoSimpleTrajectory.h"

#include "TrackerReco/TkEvent/interface/TkSimTrack.h" 
#include "TrackerReco/TkEvent/interface/TkSimEventFromCarf.h"
#include "CommonDet/DetUtilities/interface/MultipleFilter.h"
#include "TrackerReco/TkTrackSelection/interface/SimTrackEfficiencyFilter.h"

#include "CommonDet/BasicDet/interface/SimHit.h" 
#include "CommonDet/BasicDet/interface/DetUnit.h"
#include "CommonDet/DetUtilities/interface/OpenFilter.h"
#include "CommonDet/PatternPrimitives/interface/Vertex.h"
#include "CommonDet/BasicDet/interface/DetType.h"
#include "ClassReuse/GeomVector/interface/GlobalVector.h"
#include <qstring.h>

#include <set>
using namespace std;

const float PT_MIN_TO_DRAW    = 1.0;

const int   MAX_HITS_ON_TRACK = 1000;   

void TwigTk2DSimTracks::createRotation( const DetUnit* det, SbVec3f& axis, float& angle )
{
    // Extract the coeff of the rotation matrix with a projection on the basis vectors
    TkRotation< float > rot = det->surface().rotation();
    Basic3DVector< float > nx( 1., 0., 0. ); // x basis vector
    Basic3DVector< float > ny( 0., 1., 0. ); // y basis vector
    Basic3DVector< float > nz( 0., 0., 1. ); // z basis vector
    Basic3DVector< float > px = rot * nx; // Rxx Ryx Rzx
    Basic3DVector< float > py = rot * ny; // Rxy Ryy Rzy
    Basic3DVector< float > pz = rot * nz; // Rxz Ryz Rzz
    /* the rotation matrix is
     *  Rxx Rxy Rxz
     *  Ryx Ryy Ryz
     *  Rzx Rzy Rzz
     */
    // SbMatrix in row major order. The 4th dimension is set empiricly set to the identity
    SbMatrix sbm( px.x(), py.x(), pz.x(), 0,
                  px.y(), py.y(), pz.y(), 0,
                  px.z(), py.z(), pz.z(), 0,
                  0,      0,      0, 1 );
    SbRotation sbr( sbm );
    float x, y, z;
    sbr.getValue( axis, angle );
    axis.getValue( x, y, z );
}

void TwigTk2DSimTracks::addWafer( SoSeparator* separator, const DetUnit* det )
{
float vertexPositions[8][3] =
 {
   { 0.0, 0.0, 0.0 },    
   { 0.0, 0.0, 0.0 },  
   { 0.0, 0.0, 0.0 },
   { 0.0, 0.0, 0.0 },

   { 0.0, 0.0, 0.0 },
   { 0.0, 0.0, 0.0 },
   { 0.0, 0.0, 0.0 },
   { 0.0, 0.0, 0.0 }, 
 };
  
 int32_t indicesL[30] =
 {
    0, 1,  2,  3,  SO_END_LINE_INDEX, //bottom
    0, 4,  5,  1,  SO_END_LINE_INDEX,
    1, 2,  6,  5,  SO_END_LINE_INDEX,
    3, 2,  6,  7,  SO_END_LINE_INDEX,
    0, 3,  7,  4,  SO_END_LINE_INDEX,
    4, 5,  6,  7,  SO_END_LINE_INDEX, //top
  };
    // position of the wafer's center
    float posx = det->surface().position().x() / 100.0;  // cm -> m
    float posy = det->surface().position().y() / 100.0;  // cm -> m
    float posz = det->surface().position().z() / 100.0;  // cm -> m
    
    SoResetTransform *resetTransform = new SoResetTransform();
    separator->addChild(resetTransform);

   
    // Translation of the wafer
    SoTranslation* theTranslation = new SoTranslation();
    theTranslation->translation.setValue( posx, posy, posz );
    separator->addChild( theTranslation );

    float angle;
    SbVec3f axis;
    createRotation( det, axis, angle );
    SoRotation* theRotation = new SoRotation();
    theRotation->rotation.setValue( axis, angle );
    separator->addChild( theRotation );
    
    SoMaterialBinding *myBinding = new SoMaterialBinding;
   	myBinding->value = SoMaterialBinding::PER_FACE;

   	separator->addChild(myBinding);
	
        // Representation of the wafers as G4Boxes or G4Traps
    const vector< float > par = det->type().shape().parameters();
    if( par.size() == 3 )
    { // Rectangular
        float length = det->type().shape().length() / 100.0; // cm -> m
        float width = det->type().shape().width() / 100.0;   // cm -> m
        float thickness = det->type().shape().thickness() / 100.0;  // cm -> m

       IgSoCube* theCube   = new IgSoCube();
	//cout <<" cube "<<theCube<<endl;
	//tkPickedModuleMap[theCube]= det;
        theCube->width     = width;
        theCube->length    = length;
        theCube->thickness = thickness;

        separator->addChild( theCube );
   }
    else if( par.size() == 4 )
    { // Trapezoidal
        float hbotedge=par[0]/100.0; // cm -> m
        float htopedge=par[1]/100.0; // cm -> m
        float hapothem=par[3]/100.0; // cm -> m
        float hthickness=par[2]/100.0; // cm -> m

     IgSoG4Trap *theG4Trap   = new IgSoG4Trap();
	//cout <<" trap "<<theG4Trap<<endl;
	//tkPickedModuleMap[theG4Trap]= det;
        // see IgSoG4Trap.h and ActiveMediaTrapezoid.h for explanations
        theG4Trap->pDz = hthickness;
        theG4Trap->pDy1= hapothem;
        theG4Trap->pDy2= hapothem;
        theG4Trap->pDx1= hbotedge;
        theG4Trap->pDx2= htopedge;
        theG4Trap->pDx3= hbotedge;
        theG4Trap->pDx4= htopedge;
        theG4Trap->pAlp1= 0.0;
        theG4Trap->pAlp2= 0.0;
        separator->addChild(theG4Trap);

	vertexPositions[0][0] =hbotedge; 
        vertexPositions[1][0] =-hbotedge;
        vertexPositions[2][0] =-hbotedge;
        vertexPositions[3][0] =hbotedge;

	vertexPositions[0][1] = hapothem;
        vertexPositions[1][1] = hapothem;
        vertexPositions[2][1] = -hapothem;
        vertexPositions[3][1] = -hapothem;

        vertexPositions[0][2] = -hthickness;
        vertexPositions[1][2] = -hthickness;
        vertexPositions[2][2] = -hthickness;
        vertexPositions[3][2] = -hthickness;

        vertexPositions[4][0] =htopedge;
        vertexPositions[5][0] =-htopedge;
        vertexPositions[6][0] =-htopedge;
        vertexPositions[7][0] =htopedge;

        vertexPositions[4][1] = hapothem;
        vertexPositions[5][1] = hapothem;
        vertexPositions[6][1] = -hapothem;
        vertexPositions[7][1] = -hapothem;

        vertexPositions[4][2] = hthickness;
        vertexPositions[5][2] = hthickness;
        vertexPositions[6][2] = hthickness;
        vertexPositions[7][2] = hthickness;

        // Define coordinates for vertices
   	SoCoordinate3 *myCoords = new SoCoordinate3;
   	myCoords->point.setValues(0, 8, vertexPositions);
   	separator->addChild(myCoords);

	SoIndexedLineSet *myLineSet = new SoIndexedLineSet;
	myLineSet->coordIndex.setValues(0, 30, indicesL);
	separator->addChild(myLineSet);
   }
}
void TwigTk2DSimTracks::updateSet(bool del_add,CrossedDetUnitSet cdu)
{
  

 /*  if(!del_add){
     
    if(MatrixSeparator[clr_dsk][ring]){
       root->removeChild(MatrixSeparator[clr_dsk][ring]); 
       MatrixSeparator[clr_dsk][ring]->unref();
     }
     else{
       cout << "ring number "<< clr_dsk <<" " << ring << "not found"<<endl;
     }
  }else{*/
      SoSeparator* del = new SoSeparator();
    
     getIvNode()->addChild(del);
     //del->ref();
     
     
     CrossedDetUnitSet::iterator cross; 
     
    for (cross = cdu.begin(); cross != cdu.end(); ++cross) {
	
        addWafer(del,*cross); 
    }

  //}
  
}
void TwigTk2DSimTracks::drawMe()
{


    inherited::drawMe();

typedef set<const DetUnit *,less<const DetUnit *> > CrossedDetUnitSet;
CrossedDetUnitSet crossedDetUnitSet;
CrossedDetUnitSet::iterator cross; 

    check();
    if( theCurrentEvent != 0 )
    {
	// Define materials and add each to it's own seperator
	// ---------------------------------------------------

	SoSeparator* electronSoSeparator = new SoSeparator();
	SoSeparator*     muonSoSeparator = new SoSeparator();
	SoSeparator*   pionSoSeparator   = new SoSeparator();
	SoSeparator*   othersSoSeparator = new SoSeparator();

	getIvNode()->addChild( electronSoSeparator );
	getIvNode()->addChild( muonSoSeparator );
	getIvNode()->addChild( pionSoSeparator );
	getIvNode()->addChild( othersSoSeparator );

	SoMaterial *electronSoMaterial = new SoMaterial;                   
	SoMaterial *muonSoMaterial = new SoMaterial;                       
	SoMaterial *pionSoMaterial = new SoMaterial;                     
	SoMaterial *othersSoMaterial = new SoMaterial;                     

        electronSoMaterial->ambientColor.setValue   (0.000, 0.000, 0.000); 
        electronSoMaterial->diffuseColor.setValue   (0.000, 1.000, 0.000);  
        electronSoMaterial->specularColor.setValue  (0.000, 0.000, 0.000); 
        electronSoMaterial->shininess = 0.0;
        electronSoMaterial->transparency = 0.0;

        // set basic (null) defaults for all materials

        muonSoMaterial->ambientColor.setValue   (0.000, 0.000, 0.000); 
        muonSoMaterial->diffuseColor.setValue   (1.000, 0.000, 0.000);  
        muonSoMaterial->specularColor.setValue  (0.000, 0.000, 0.000); 
        muonSoMaterial->shininess = 0.0;
        muonSoMaterial->transparency = 0.0;

        pionSoMaterial->ambientColor.setValue   (0.000, 0.000, 0.000); 
        pionSoMaterial->diffuseColor.setValue   (0.000, 0.000, 1.000);  
        pionSoMaterial->specularColor.setValue  (0.000, 0.000, 0.000); 
        pionSoMaterial->shininess = 0.0;
        pionSoMaterial->transparency = 0.0;

        othersSoMaterial->ambientColor.setValue   (0.000, 0.000, 0.000); 
        othersSoMaterial->diffuseColor.setValue   (0.000, 1.000, 1.000);  
        othersSoMaterial->specularColor.setValue  (0.000, 0.000, 0.000); 
        othersSoMaterial->shininess = 0.0;
        othersSoMaterial->transparency = 0.0;

        // set emissive colours for all materials

	electronSoMaterial->emissiveColor.setValue     (0.000, 1.000, 0.000); 
	muonSoMaterial->emissiveColor.setValue         (1.000, 0.000, 0.000); 
	pionSoMaterial->emissiveColor.setValue         (0.000, 0.000, 1.000); 
	othersSoMaterial->emissiveColor.setValue       (0.000, 1.000, 1.000); 

	electronSoSeparator->addChild( electronSoMaterial );
	muonSoSeparator->addChild( muonSoMaterial );
	pionSoSeparator->addChild( pionSoMaterial );
	othersSoSeparator->addChild( othersSoMaterial );

	TkSimEventFromCarf simev( theCurrentEvent );

	vector< const TkSimTrack* > simTracks = simev.tracks( OpenFilter < TkSimTrack > ());

	cout<<endl<<"TwigTk2DSimTracks::drawMe> Total number of sim tracks = " << simTracks.size() << endl;
        cout<<      "TwigTk2DSimTracks::drawMe> Minimum pt to be drawn     = " << PT_MIN_TO_DRAW   << endl;

	
	for( vector< const TkSimTrack* >::iterator isim = simTracks.begin();
	     isim != simTracks.end(); isim++ )
	{
	    float pt = (*isim)->momentumAtVertex().perp();	    

            if ( pt > PT_MIN_TO_DRAW )
	    {		

		// Points to be used to draw the trajectory 
       
		int nOnTrack = 0;          
		float xOnTrack[MAX_HITS_ON_TRACK];
		float yOnTrack[MAX_HITS_ON_TRACK];
		float zOnTrack[MAX_HITS_ON_TRACK];
		float tOnTrack[MAX_HITS_ON_TRACK];

		// Points to be used to draw SimHit markers
       
		int nMarker = 0;          
		float xMarker[MAX_HITS_ON_TRACK];
		float yMarker[MAX_HITS_ON_TRACK];
		float zMarker[MAX_HITS_ON_TRACK];
	    
		// Add SimTrack starting point to trajectory
                 
		tOnTrack[nOnTrack] = -1.E10;  // ensure it is the earliest (=first) point 

		xOnTrack[nOnTrack] = (*isim)->vertex()->position().x() / 100.0;  // cm -> m  
		yOnTrack[nOnTrack] = (*isim)->vertex()->position().y() / 100.0;  // cm -> m  
		zOnTrack[nOnTrack] = (*isim)->vertex()->position().z() / 100.0;  // cm -> m 
		nOnTrack++;
	   	    	      
		// Loop on SimHits of the TkSimTrack

		TkSimTrack::SimHitContainer simHits = (*isim)->hits();
		int nSimHits = simHits.size(); 	    

                int ipart  = 0;  // Pythia particle code (not used: bug in genparticle??) 
                int nGpart = 0;  // GEANT  particle code 
                
		for( TkSimTrack::SimHitContainer::const_iterator iSimHit = simHits.begin();
		     iSimHit != simHits.end(); iSimHit++ )
		{
		    if ( nOnTrack >= MAX_HITS_ON_TRACK ) {
			cout << "TwigTk2DSimTracks::drawMe> --------------------------------" << endl;
			cout << "TwigTk2DSimTracks::drawMe> Error !!! Too many hits on track" << endl;
			cout << "TwigTk2DSimTracks::drawMe> --------------------------------" << endl;
			return;
		    }
		
		    if(nGpart == 0 ) 
                        nGpart = ( *iSimHit )->particleType();  // Obtain ID from first hit
		    //cout << "Part ID" << nGpart << endl;
		    
		    
		    // Add a marker at SimHit location
		    xMarker[nMarker] = (*iSimHit)->globalPosition().x() / 100.0;   // cm -> m
		    yMarker[nMarker] = (*iSimHit)->globalPosition().y() / 100.0;   // cm -> m
		    zMarker[nMarker] = (*iSimHit)->globalPosition().z() / 100.0;   // cm -> m
		    nMarker++;
          		
		    const DetUnit& detector = (*iSimHit)->det();
		    GlobalPoint gEntryPoint = detector.toGlobal((*iSimHit)->entryPoint());
		    GlobalPoint gExitPoint  = detector.toGlobal((*iSimHit)->exitPoint());  
		    
	 crossedDetUnitSet.insert(&detector);
	 	          
           cout << detector.type().module() <<endl;     
		    
		    
		    const float epsilon = 1.E-10;  // slight time offset to ensure points are correctly ordered
              
		    // Add entry point to trajectory
                 
		    //  tOnTrack[nOnTrack] = (*iSimHit)->tof() * (1.0 - epsilon);
		    //  xOnTrack[nOnTrack] = gEntryPoint.x() / 100.0;  // cm -> m
		    //  yOnTrack[nOnTrack] = gEntryPoint.y() / 100.0;  // cm -> m
		    //  zOnTrack[nOnTrack] = gEntryPoint.z() / 100.0;  // cm -> m
		    //  nOnTrack++;

		    // Add SimHit point to trajectory
                
		    tOnTrack[nOnTrack] = (*iSimHit)->tof();   
		    xOnTrack[nOnTrack] = (*iSimHit)->globalPosition().x() / 100.0;  // cm -> m
		    yOnTrack[nOnTrack] = (*iSimHit)->globalPosition().y() / 100.0;  // cm -> m
		    zOnTrack[nOnTrack] = (*iSimHit)->globalPosition().z() / 100.0;  // cm -> m
		    nOnTrack++;

		    // Add exit point to trajectory
                 
		    //  tOnTrack[nOnTrack] = (*iSimHit)->tof() * (1.0 + epsilon);
		    //  xOnTrack[nOnTrack] = gExitPoint.x() / 100.0;  // cm -> m
		    //  yOnTrack[nOnTrack] = gExitPoint.y() / 100.0;  // cm -> m
		    //  zOnTrack[nOnTrack] = gExitPoint.z() / 100.0;  // cm -> m
		    //  snOnTrack++;                             
		}
		
		//  	      cout << "nOnTrack, nMarker =" << nOnTrack << "  " << nMarker << endl;
	    
		if( nOnTrack > 2 ) {        
                          
		    IgSoSimpleTrajectory* _trajectory = new IgSoSimpleTrajectory;
		    SbVec3f xyzPoint;
              
		    int iHit = 0;       
		    for( iHit = 0; iHit < nOnTrack; iHit++ ) {
			xyzPoint.setValue( xOnTrack[iHit], yOnTrack[iHit], zOnTrack[iHit] );
			_trajectory->xyzControlPoints.set1Value( iHit, xyzPoint );
		    }

		    for( iHit = 0; iHit < nMarker; iHit++ ) {
			xyzPoint.setValue( xMarker[iHit], yMarker[iHit], zMarker[iHit] );
			_trajectory->xyzMarkerPoints.set1Value( iHit, xyzPoint );
		    }

		    _trajectory->setName(QString ("TkSimTrack:%1:%2:%3")
					     .arg (ipart)
					     .arg (nGpart)
					     .arg (pt)
					     .latin1 ());

		    if(      ipart == 11 || ipart == -11 || nGpart == 11 || nGpart == -11 )   // electron
		    {
  		        _trajectory->pointSize.setValue( 4.0 );    
			_trajectory->lineWidth.setValue( 2.0 ); // in pixels
			electronSoSeparator->addChild( _trajectory );
		    }
		    else if( ipart == 13 || ipart == -13 || nGpart == 13 || nGpart == -13 )   // muon
		    {   
  		        _trajectory->pointSize.setValue( 4.0 );    
			_trajectory->lineWidth.setValue( 2.0 ); // in pixels
			muonSoSeparator->addChild( _trajectory );
		    
		    }
		    else if( ipart ==211 || ipart ==-211 || nGpart == 211 || nGpart == -211 ) // pion
		    {
  		        _trajectory->pointSize.setValue( 2.0 );    
			_trajectory->lineWidth.setValue( 1.0 ); // in pixels
			pionSoSeparator->addChild( _trajectory );
		    }
		    else // others
		    {
  		        _trajectory->pointSize.setValue( 2.0 );    
			_trajectory->lineWidth.setValue( 1.0 ); // in pixels
			othersSoSeparator->addChild( _trajectory );
		    }
		}
	    }
	}
    }
   updateSet(true,crossedDetUnitSet); 
    
}

 
 


















