#ifndef _PCHANNEL_H_
#define _PCHANNEL_H_
#include "TArrayI.h"
#include "TF1.h"
#include "TF2.h"
#include "PParticle.h"
#include "PDistribution.h"
#include "PStdData.h"
#include "PBulkInterface.h"
#include "PProjector.h"
#define MAX_DISTRIBUTIONS 10
#define MAX_NUM_NOT_FINALIZED 5
#define MAX_BULKDECAY 5
#define STATUS_OK          0
#define STATUS_EMPTY_EVENT 80
#define STATUS_PSEUDO_EMPTY_EVENT 81
#define STATUS_REDO_CHAIN  82
#define STATUS_NOT_DECAYED 99
class PChannel : public TObject {
  
 public:
    PChannel(PParticle **, int nt=2, int mf=0, int af=0, int bf=0);
    
    PChannel(int idx, PParticle **particles=NULL, int mf=0, int af=0, int bf=0);
    
    PChannel(int idx, PParticle &parent, int mf=0, int af=0, int bf=0);
    
    ~PChannel() {
	
	if (ipid.GetArray()) 
	    ipid.~TArrayI();
	
	if (ptcls && ptcls_extern>=0) {
	    for(int i=ptcls_extern; i<=n; i++)
		if (ptcls[i]) delete ptcls[i];
	    if (ptcls) delete [] ptcls;
	}
    }
    Bool_t Init();
    
    
    Bool_t Reset();
    
    Bool_t SetDaughters();
    void SetSourceId(Int_t mysourceid) {
	sourceid = mysourceid;
    }
    int Decay();
    
    
    
    
    int decay() {
	
	return Decay();
    }; 
    PParticle **GetParticles() {
	
	return ptcls;
    }
    int *GetPids() {
	
	return ipid.GetArray();
    }   
    int GetNumPar() {  
	
	return n; 
    }
    
    
    int SetDistribution(PDistribution *distribution);
    
    int CheckSiblings(PParticle *p, PDistribution *dist, int flag); 
    double GetBT() {
	PParticle *beam   = ptcls[0]->GetScattering(0);
	PParticle *target = ptcls[0]->GetScattering(1);
	
	if (beam) {
	    return (beam->KE() > target->KE()? beam->KE(): target->KE());
	}
	else return ptcls[0]->Rapidity();
    }
    
    PChannel *GetQuasi(void) {
	return quasi_pchannel;
    };
    void ClearQuasi(void) {
	quasi_pchannel = NULL;
    };
    int GetParentSize() { 
	
	return 1 + (ipid[0]>=1000); 
    }   
    static void SetGlobalWeight(double w) { 
	globalWeight = w; 
    } 
    static double GetGlobalWeight() { 
	return globalWeight; 
    }
    int GetDMIndex() { 
	
	return DMIndex; 
    }
    void GetMessage();
    
    void Print(const Option_t *delme="") const;
    void PrintReaction(Int_t check_key = 1) const;
    void PrintNew();
    
    void PrintReport() const; 
    void CheckDecayKey() const;
    char const *GetName(void) const ;
    
    
    
    
    void SetPrintTentative(bool t){ 
	
	print_tentative = t;
    };
    void DisableHelicityAngle() {
	cout << "DisableHelicityAngle() is obsolete -> use DistributionManager" << endl;
    };
    
    int GetNumNotFinalized() {
	return num_not_finalized;
    };
    PDistribution *GetDistributionNotFinalized(int i) {
	return distribution_not_finalized[i];
    };
    
    Bool_t AddBulk(PBulkInterface *mybulk);
    Bool_t AddPrologueBulk(PBulkInterface *mybulk); 
    Bool_t Do(const char *command) {
	return GetCurrentProjector()->AddCommand(command);
    }
    Bool_t Do(TH1F *f, const char *command, Int_t flag=1) {
	return GetCurrentProjector()->AddHistogram(f,command,flag);
    }
    Bool_t Do(TH2F *f, const char *command, Int_t flag=1) {
	return GetCurrentProjector()->AddHistogram(f,command,flag);
    }
    Bool_t Do(TH3F *f, const char *command, Int_t flag=1) {
	return GetCurrentProjector()->AddHistogram(f,command,flag);
    }
 private:
    int n, status, DMIndex;
    
    
    int thSrc, tcSrc, dlSrc, sourceid;
    Double_t weight_sum;   
    int decay_key;                       
    TString decay_string; 
    TString decay_string2; 
    
    PDistribution *dist[MAX_DISTRIBUTIONS];
    Double_t dist_weight[MAX_DISTRIBUTIONS];
    Double_t dist_weight_sum[MAX_DISTRIBUTIONS];
    Double_t dist_counter[MAX_DISTRIBUTIONS];
    Int_t distribution_position;
    bool init_done, thermal_disable_didx;
    bool print_tentative;
    Long_t fEnablePattern;
    int bid,tid;
    PParticle *spectator, *participant, *quasi_composite;
    PChannel *quasi_pchannel;
    
    TArrayI ipid;
    
    static double globalWeight;
    
    double *event_impact_param , *event_plane;  
    double *weight_version;  
    double *events;   
    PParticle ** ptcls, *parent, *orig_parent, *grandparent, *grandgrandparent;
    
    int ptcls_extern;
    
    double ecm, w, emin; 
    double e_cm;  
    void IsReaction();
    
    void IdChannel();
    
    
    void ThermalSampling();
    
    Int_t ReadFileInput();
    
    void MakeDilepton();
    
    int Genbod(int);
    
    
    
    int num_not_finalized;
    PDistribution *distribution_not_finalized[MAX_NUM_NOT_FINALIZED];
    int bulkdecay_pos, pro_bulkdecay_pos;
    
    PBulkInterface *bulk[MAX_BULKDECAY];
    PBulkInterface *pro_bulk[MAX_BULKDECAY];
    PProjector *current_projector;
    PProjector *GetCurrentProjector(void) {
	if (!bulkdecay_pos) {
	    current_projector = new PProjector();
	    AddBulk(current_projector);
	} else {
	    if ((strcmp("PProjector",bulk[bulkdecay_pos-1] -> GetName())==0)) {
		if ((bulk[bulkdecay_pos-1] -> GetPriority() > FILTER_PRIORITY) ||
		    ((PProjector *)bulk[bulkdecay_pos-1])->IsFileOpen()) {
		    current_projector = (PProjector *)bulk[bulkdecay_pos-1];
		} else {
		    current_projector = new PProjector();
		    AddBulk(current_projector);
		}
	    } else {		
		current_projector = new PProjector();
		AddBulk(current_projector);
	    }
	}
	return current_projector;
    }
    
    ClassDef(PChannel,0) 
};
#endif // _PCHANNEL_H_