//#############################################################################################################################################################
//
// filter.c # by Emiliano Mocchiutti (2005/11/25)
//
//#############################################################################################################################################################
//
// Template for the event selection using the EventViewer. The function must be called "filter" while the filename where the function is defined can be anyone.
//
//#############################################################################################################################################################
//
// The idea of the event selection is the following: 
// 1) you must know which kind of data the EventViewer program is using (for example tracker level0, level1 or level2 data?)
// 2) depending on the available data you can define your selection.
// 3) information about data used can be found in the structure "level" which contains the following variables:
//    typedef struct Levels {
//        Int_t calo;            // if equal to 0 calorimeter level 0 , if equal to 1 calorimeter level 1 data.
//        Int_t calol2;          // for the moment this is always 0
//        Int_t tof;             // tof/trigger level 1 or level 0 data
//        Int_t track;           // tracker level 1 or level 0 data
//        Int_t track2;          // if set to one there are tracker level2 data
//        Int_t s4;              // S4 level 1 or level0 data
//        Int_t ac;              // AC level 1 or level0 data  
//        Int_t nd;              // always 0 for the moment
//    } level;
//    evno is the event number to be processed.
//    All data coming from yoda are stored in the tree called "otr", tree "ttr" contains only level2 tracker data.
// 4) to learn how to change things look at examples below.
// 5) to stop the eventviewer this function must return 1 as value, when returning 0 means go on searching.
// 6) is it possible to combine information from different detectors.
//

int filter(Int_t evno, TTree *otr, TTree *ttr, Levels & level){
    //
    // example n. 1
    // select events where the energy deposit in S4 is greater than 0.7 MIP
    //
    Bool_t S4 = true;
    //
    // check the data level
    //
    if ( level.s4 == 0 ) {
	S4 = false;
	//
	// determine in which branch we can find S4 data in the tree otr.
	//
	pamela::S4::S4Event  *s4 = 0;
	otr->SetBranchAddress("S4.Event", &s4);
	otr->GetEntry(evno);
	//
	// if we have level0 data we must calibrate the data to make a selection in MIP.
	//	
	Float_t s4data = ((float)s4->S4_DATA -32.) *  0.29;    
	//
	// if the condition is satisfied S4 is true.
	//
	if ( s4data>0.7 ) S4 = true;
    };

    //
    // example n. 2
    // select events with one or more tracks
    //
    Bool_t TRACKER = true;
    //
    // check we have tracker LEVEL2 data
    //
    if ( level.track2 == 1 ){
	TRACKER = false;
	//
	// access tracker level2 data, store variables in the structure trk.
	//
	struct Tracklev2 trk;
	settrklev2(ttr,trk);
	//
	// get entry, here we are assuming we have syncronized data.
	//
	ttr->GetEntry(evno);
	//
	if ( trk.ntrk > 0 ){
	    //
	    TRACKER = true;
	    //
	    //  example of how to calculate rigidity from deflection and select negative particles with rigidity less than 1 GV:
	    //
	    //	    Float_t rig = 0.;
	    //
	    //      notice that in the structure trk columns and rows of matrixes are inverted respect to the fortran style al[0][4] is deflection for the first track 
	    //      al[1][4] would be deflection for the second track, etc.
	    //
	    //      if ( trk.al[0][4] != 0. ) rig = 1./trk.al[0][4];
	    //      if ( abs(rig) < 1. ) TRACKER = true;
	};
    };

    //
    // example n. 3
    // select events with 6 hist in the X-view of the tracker and 6 hit in the Y-view of the tracker
    //
    Bool_t TRACKER2 = true;
    //
    if ( level.track == 0 ){
	TRACKER2 = false;
	Int_t fnclx = 0;
	Int_t fncly = 0;
	pamela::tracker::TrackerEvent *trk = 0;    
	otr->SetBranchAddress("Tracker.Event", &trk);    
	otr->GetEntry(evno);    
	for (Int_t l = 0; l<12; l++){	
	    Int_t planeno = trk->DSPnumber[l]-1;	
	    if ( planeno < 0 || planeno > 11 ) planeno = 0;
	    if ( planeno >= 0 ) {
		if ( (planeno+1)%2 ){
		    for (Int_t m = 0; m<3; m++){
			if ( trk->signcluster[l][m] != 0. ){
			    fncly++;
			};
		    };	       
		} else {
		    for (Int_t m = 0; m<3; m++){
			if ( trk->signcluster[l][m] != 0. ){
			    fnclx++;
			};
		    };
		};
	    };    
	};
	if ( fnclx == 6 &&  fncly == 6 ) TRACKER2 = true;
    };
    
    //
    // example n. 4
    // select events with qtot greater than 100 and nstrip greater than 100 in the calorimeter (interacting particles)
    //
    Bool_t CALO = true;
    //
    // check if we have calorimeter level1 data
    //
    if ( level.calo == 1 ){
	CALO = false;
	CalorimeterLevel1 *calo = new CalorimeterLevel1();
	otr->SetBranchAddress("CaloLevel1.Event", &calo);
	otr->GetEntry(evno);
	if ( calo->qtot > 100 && calo->nstrip > 100) CALO = true;
    };

    //
    // example n. 5
    // select calorimeter selftrigger events
    //
    Bool_t TRIGGER = true;
    if ( level.tof == 0 || level.tof == 1 ){
	//	
	Bool_t TRIGGER = false;
	//
	// define where to find in the tree otr the Trigger.Event branch
	//
	pamela::trigger::TriggerEvent  *trig = 0;
	otr->SetBranchAddress("Trigger.Event", &trig);
	//
	// get the entry number "evno" passed by the main EventViewer program
	//
	otr->GetEntry(evno);  
	//
	// check the first element of the variable patterntrig which tell us if this one is a calorimeter trigger
	//
	if ( trig->patterntrig[0] ) {
	    //
	    // set the boolean variable TRIGGER to true. Instead of setting this variable it is possible to return(1) here.
	    //
	    TRIGGER = true;
	};
	//
	// example if one want to select S4/pulser triggers
	//
	//if ( trig->patterntrig[1] & (1<<0) ) TRIGGER = true;
    };

    //
    // example n. 6
    // select events with AC hits
    //
    Bool_t AC = true;
    //
    // in the case of level0 data
    //
    if ( level.ac == 0){
	AC = false;
	pamela::anticounter::AnticounterEvent  *ace = 0;
	otr->SetBranchAddress("Anticounter.Event", &ace);
	otr->GetEntry(evno);
	Int_t hitmapA = 0;
	Int_t hitmapB = 0;
	//
	// hitmap variable contain the information
	//
	hitmapA = ace->hitmap[0];
	hitmapB = ace->hitmap[1];
	if ( hitmapA || hitmapB ) AC = true;
    };
    //
    // in the case of level1 data
    //
    if ( level.ac == 1){
	AC = false;
	AnticounterLevel1 *ace = new AnticounterLevel1();
	otr->SetBranchAddress("AcLevel1.Event", &ace);
	otr->GetEntry(evno);
	Int_t hitmapA = 0;
	Int_t hitmapB = 0;
	hitmapA = ace->hitmap[0];
	hitmapB = ace->hitmap[1];
	if ( hitmapA || hitmapB ) AC = true;
    };

    //
    // example n. 7
    // select events in which we have at least one AC hit outside the trigger time window (we need level1 data)
    //
    Bool_t AC2 = true;
    if ( level.ac == 1){
	AC2 = false;
	AnticounterLevel1 *ace = new AnticounterLevel1();
	otr->SetBranchAddress("AcLevel1.Event", &ace);
	otr->GetEntry(evno);
	Int_t hitstatusA = 0;
	Int_t hitstatusB = 0;
	Int_t hitmapA = 0;
	Int_t hitmapB = 0;
	hitmapA = ace->hitmap[0];
	hitmapB = ace->hitmap[1];
	hitstatusA = ace->hitstatus[0];
	hitstatusB = ace->hitstatus[1];
	Int_t deltaA = hitstatusA - hitmapA;
	Int_t deltaB = hitstatusB - hitmapB;
	if ( deltaA || deltaB ) AC2 = true;
    };


    //
    // example n. 8
    // select events with one or more detected neutrons:
    //
    Bool_t ND = true;
    if ( level.nd == 0){
	ND = false;
	Int_t tmpSize;    
	Int_t nTrig = 0;
	pamela::neutron::NeutronEvent  *ne = 0;
	pamela::neutron::NeutronRecord *nr = 0;
	otr->SetBranchAddress("Neutron.Event", &ne);
	otr->GetEntry(evno);
	tmpSize = ne->Records->GetEntries();
	for (Int_t j = 0; j < tmpSize; j++){
	    nr = (pamela::neutron::NeutronRecord*)ne->Records->At(j);	
	    nTrig        += (int)nr->trigPhysics;
	};    
	if ( nTrig > 0 ) ND = true;
    };

    //
    // Here we can use the boolean variables and decide if the event passed the selecion or not.
    // 
    // if the event pass the selection return one, zero otherwise.
    //

    //
    // Some examples:
    //

    // A - select only calorimeter selftrigger events 
    //
    // if ( TRIGGER ) return(1);

    // B - select calorimeter self-trigger events with at least one fitted track:
    //
    // if ( TRIGGER && TRACKER ) return(1);

    // C - select events with at least one track (default behaviour so it is uncommented)
    //
    if ( TRACKER ) return(1);    

    // D - select interacting events in the calorimeter
    //
    //    if  ( CALO ) return(1);


    // E - select events with hit in the anticounters
    //
    //    if ( AC ) return(1);

    // F - select events with energy release in S4 greater than 0.7 MIPs, at least one track, no hit in the anticounters and at least one neutron detected:
    //
    // if ( S4 && TRACKER && !AC && ND ) return(1);

    //
    // if nothing match, return 0.
    //
    return(0);
};
