#include "PPlutoBulkDecay.h"
#include "PDynamicData.h"
#include "PChannel.h"
#include "PDistributionManager.h"
PPlutoBulkDecay::PPlutoBulkDecay() {
    makeStdData();
    didx = makeDataBase()->GetParamInt("didx");
    stackchannel = makeDataBase()->GetParamTObj("stackchannel");
    fPriority = DECAY_PRIORITY;
}
bool PPlutoBulkDecay::Modify(PParticle ** stack, int *decay_done, int * num, int stacksize) {
    
    
    
    const int maxnp = 7; 
    Int_t st_i1, st_i3, k; 
    Int_t size_ini = *num;  
    Int_t child_ids[maxnp+1];
    PParticle *cur_p, *work[maxnp+2];
    
    
    
    st_i1 = size_ini-1;
    
    
    st_i3 = size_ini;
    while (st_i1 > -1) {
	cur_p = stack[st_i1];  
	
	
	
	if (cur_p->IsActive() && 
	    makeDynamicData()->GetParticleLife(cur_p->ID()) 
	    < tauMax && !decay_done[st_i1]) {
 	    
 	    
	    
	    Int_t channel_idx = 
		makeDynamicData()->PickDecayChannel(cur_p->ID(), cur_p->M(), child_ids);	    
	    
	    if (channel_idx>-1) { 
		Int_t np = child_ids[0];   
		if (np > 0) { 
		    
		    TObject * ch;
		    PChannel* d_ch;
		    
		    if (!makeDataBase()->GetParamTObj (didx, channel_idx , stackchannel, &ch)) {
			Info("Modify", "(%s) Making new channel for didx %i", PRINT_AUTO_ALLOC, channel_idx);
			if (np > maxnp) {
			    printf("PPlutoBulkDecay::Modify(): np=%d > maxnp=%d\n", np, maxnp);
			    np = maxnp;
			}
			for (k=1; k<=np; k++) {
			    work[k] = new PParticle(child_ids[k]);
			}
			work[0] = new PParticle(cur_p->ID());
			Int_t sourceIdSave = cur_p->GetSourceId();  
			Int_t parentIdSave = cur_p->GetParentId();  
			PParticle **local = new PParticle*[np+1];
			for(int i=0; i<=np; i++) local[i] = work[i]; 
			d_ch = new PChannel(local, np, 1, 1, 0); 
			makeDistributionManager()->Attach(d_ch);
			d_ch->SetPrintTentative(0);
			d_ch->Init();
			work[0]->SetSourceId(sourceIdSave);           
			work[0]->SetParentId(parentIdSave);
			makeDataBase()->SetParamTObj(makeDataBase()->GetEntryInt("didx", channel_idx) , 
						     "stackchannel", d_ch);	
			
		    }
		    if (makeDataBase()->GetParamTObj(didx, channel_idx, stackchannel, &ch)) {
			d_ch = (PChannel*)ch;
			d_ch->Reset(); 
			(d_ch->GetParticles()[0]) = cur_p;
			work[0] = cur_p;
			
			for (k=1; k<=np; k++) {
			    work[k] = (d_ch->GetParticles()[k]);  
			    work[k]->SetActive();
			    work[k]->SetIndex(st_i3+1+k);
			    work[k]->SetParent(work[0]);
			    decay_done[st_i3+k-1]=0;
			}
			for (k=1; k<=np; k++) {
			    
			    if (k!=np) {
				work[k]->SetSibling(work[k+1]);
			    } else {
				work[k]->SetSibling(work[1]);
			    }
			}
			
			
		    } else {
			Fatal("Modify", "Unable to get PChannel");
			return kFALSE;
		    }
#if 0
		    
		    cout << "dumping stack" << endl;
		    for (int t=0;t<st_i3+np;t++) {
			cout << t << ":" << stack[t] << ":"<< stack[t]->GetSibling() << endl;
			stack[t]->Print();
		    }
#endif
		    
		    
		    (d_ch->GetParticles()[0])->SetParent(work[0]->GetParent());
		    
		    d_ch->SetPrintTentative(0);
 		    d_ch->Init();
		    d_ch->PrintNew();
		    d_ch->SetPrintTentative(1);
		    Int_t error_count = 0;
		    if (error_count < 100) {
			if (d_ch->decay()) {
			    error_count++;
			}
		    } else {
			Warning("Modify", "Decay not possible, giving up");
		    }
		    work[0]->SetDecayModeIndex(channel_idx, 1); 
		    
		    decay_done[st_i1] = 1;  
		    
		    
		    for(int k=1; k<=np; k++) {
			*stack[st_i3+k-1] = *work[k];
		    }
		    for(int k=1; k<=np; k++) {
			stack[st_i3+k-1]->SetParent(cur_p);
			stack[st_i3+k-1]->SetActive();
			
			if (k!=np) {
			    stack[st_i3+k-1]->SetSibling(stack[st_i3+k]);
			}
			else {
			    stack[st_i3+k-1]->SetSibling(stack[st_i3]);
			}
		    }
		    st_i3 += np;
		    if (recursiveMode)
			st_i1 = st_i3;
		    else
			st_i1 = size_ini-1;
		} 
	    } 
	    if(st_i3>(stacksize-maxnp))   {  
		printf("PPlutoBulkDecay::decayAll: st_i3=%d > stacksize%i\n", st_i3, stacksize);
	    }
	
	} 
	
	st_i1--;
    }
    *num = st_i3;  
	    
    return kTRUE;
}
ClassImp(PPlutoBulkDecay)