/////////////////////////////////////////////////////////////////////
//
// Resonance mass sampling from a 
// complex breit-wigner propagator
// for each daughter decay channel, a list of
// interference channel can be set up
// This includes the complex amplitude for the given
// decay channel as well as the interference terms
// The interference terms can be other particle models,
// decay models and even exchange terms itself
//
// Such, by removing the standard propagator (setting the amplitude to 0)
// and adding other exchange terms, the production
// of a single particle (with known target daugters) can be rewritten
// in forms of koherent feynman sums
//
//                                  Author: Froehlich
/////////////////////////////////////////////////////////////////////


using namespace std;
#include <sstream>
#include <iostream>
#include <iomanip>

#include "PComplexBreitWigner.h"


ClassImp(PComplexBreitWigner)

PComplexBreitWigner::PComplexBreitWigner() {
};

PComplexBreitWigner::PComplexBreitWigner(const Char_t *id, const Char_t *de, Int_t key) :
    PBreitWigner(id, de, key) {

    readModesDone   = 0;
    readModelsDone  = 0;
    updateAmplitude = 0;
    mr = makeStaticData()->GetParticleMassByKey(key);
};

PDistribution* PComplexBreitWigner::Clone(const char *) const {
    return new PComplexBreitWigner((const PComplexBreitWigner &)* this);
};

Bool_t PComplexBreitWigner::SampleMass(Double_t *mass, Int_t *didx) {
    // Resonance mass sampling from a relativistic
    // Breit-Wigner 

    if (didx) 
	didx_option = didx[0];
    else
	didx_option = -1;
    mass[0] = this->GetRandom();
    return kTRUE;
};

Double_t PComplexBreitWigner::GetWeight(Double_t *mass, Int_t *didx) {
    return GetAmplitude(mass, didx).Rho2();
};


void PComplexBreitWigner::ReadModes(void) {
    if (readModesDone) return;
    
    //on the first call, loop over decay modes
    Int_t listkey = -1;

    num_decaychannels = 0;
    while (makeDataBase()->MakeListIterator(primary_key, "pnmodes", "link", &listkey)) {
	
	int_index[num_decaychannels] = makeStaticData()->GetDecayIdxByKey(listkey);
	num_terms[num_decaychannels] = 0;
	//By default loacl amplitude is (1,0)
	//Do not forget term "0" is always the local term
	int_phase[num_decaychannels][0] = 0;
	int_ampl[num_decaychannels][0]  = 1;
	
	num_decaychannels++;

	if (num_decaychannels == COMPLEX_MAX_DECAYCHANNELS) {
	    Warning("ReadModes", "COMPLEX_MAX_DECAYCHANNELS reached");
	    listkey=-1;
	}
    } //end iterator
    readModesDone = 1;
}

void PComplexBreitWigner::AddAmplitude(int idx, double ampl, double phase) {
    ReadModes();

    //loop over modes and try to find the idx

    int found_idx = -1;
    for (int i=0; i<num_decaychannels; i++) 
	if (int_index[i] == idx) 
	    found_idx = i;
    if (found_idx < 0) {
	Warning("AddAmplitude:", "idx %i is not a valid decay index for particle %i", idx, is_pid);
	return;
    }

    int_phase[found_idx][0] = phase;
    int_ampl[found_idx][0]  = ampl;
};

void PComplexBreitWigner::AddInterference(int idx, int key, int didx, double ampl, double phase) {
    // Adds a complex interference to the decay index "idx"
    // The "idx" must be a valid decay for the particle which is assigned to the "PComplexBreitWigner"
    // model. "key" is the data base entry wihc is used for the mixing (e.g. another complex BW)
    // "didx" is the target decay index used with the "key" model to get the correct final state
    // "ampl" and "phase" is the complex amplitude given in polar coordinates
    ReadModes();

    //loop over modes and try to find the idx

    int found_idx = -1;
    for (int i=0; i<num_decaychannels; i++) 
	if (int_index[i] == idx) 
	    found_idx = i;
    if (found_idx < 0) {
	Warning("AddInterference", "idx %i is not a valid decay index for particle %i", idx, is_pid);
	return;
    }

    if (num_terms[found_idx] == COMPLEX_MAX_TERMS) {
	Warning("AddInterference", "COMPLEX_MAX_TERMS reached");
	return;
    }

    num_terms[found_idx]++;

    int_didx[found_idx][num_terms[found_idx]]  = didx;
    int_key[found_idx][num_terms[found_idx]]   = key;
    int_phase[found_idx][num_terms[found_idx]] = phase;
    int_ampl[found_idx][num_terms[found_idx]]  = ampl;
};

Double_t PComplexBreitWigner::EvalPar(const Double_t *x, const Double_t *params) {
    if (params) {
	draw_option = (int)params[0];
	didx_option = (int)params[1];

	if (updateAmplitude) {
	    int found_idx = -1;	    
	    //now look for didx
	    for (int i=0; i<num_decaychannels; i++) 
		if (int_index[i] == didx_option) 
		    found_idx = i;
	    if (found_idx >= 0) {
		int_phase[found_idx][1] = params[3];
		int_ampl[found_idx][1]  = params[2];}
	}
    }
    return Eval(x[0]);
};
 
Double_t PComplexBreitWigner::Eval(Double_t x, Double_t, Double_t, Double_t) const {
    Double_t res;
    Double_t my_x[11];
    Int_t my_didx_option[11];
    my_x[0] = x;
    my_didx_option[0] = didx_option;

    if (draw_option == 0) {
	return ((PChannelModel*)this)->GetWeight(my_x, my_didx_option);
	//return res;
    }
    if (draw_option == 1) {
	((PChannelModel*)this)->GetWidth(x, &res, didx_option);
	return res;
    }
    if (draw_option == 2) {
	((PChannelModel*)this)->GetBR(x, &res);
	return res;
    }
    if (draw_option == 3) {
	return ((PChannelModel*)this)->GetAmplitude(my_x, my_didx_option).Re();
    }
    if (draw_option == 4) {
	return ((PChannelModel*)this)->GetAmplitude(my_x, my_didx_option).Im();
    }
    return 0;
};

void PComplexBreitWigner::ReadModels(void) {
    if (readModelsDone) return;

    //loop over decay modes
    for (int i=0; i<num_decaychannels; i++) {
	//Now loop over possible interference terms
	for (int j=1; j<=num_terms[i]; j++) {
	    TObject *t_result;
	    if (makeDataBase()->GetParamTObj (int_key[i][j], "model", &t_result))
		p[i][j] = (PChannelModel*)t_result;
	    else {
		p[i][j] = NULL;	
		Warning("ReadModels", "No term model found: this will not work");
	    }
	    p[i][j] = (PChannelModel*)t_result;
	}
    }
    readModelsDone = 1;
};

TComplex PComplexBreitWigner::GetAmplitudeLocal(Double_t *mass, Int_t num) {
    
    int didx_local = int_index[num];
    double m = mass[0],
	m2 = m*m, 	
	mm = mr*mr-m2;

    global_weight_scaling = makeDynamicData()->GetParticleScalingFactor(is_pid);

    double wmt = 1.;

    if (!GetWidth(m, &width)) return -1;
 

    double partial_width;
    if (didx_local >= 0) {
	if (!GetWidth(m, &partial_width, didx_local)) return -1;
	//if (partial_width > width*1.1) {
	//}
    } else 
	partial_width = width;

    TComplex denom(mm, m*width);
    
    TComplex numerator(m*sqrt(partial_width*global_weight_scaling*wmt), 0);
    
    numerator /= denom;
    TComplex ampl(int_ampl[num][0], int_phase[num][0], kTRUE); //local amplitude
    numerator *= ampl;
    
    
    //Now loop over possible interference terms

    TComplex interference(0, 0);
    for (int i=1; i<=num_terms[num]; i++) {
	TComplex interference_term(int_ampl[num][i], int_phase[num][i], kTRUE);

	if (p[num][i]) {
	    interference_term *= p[num][i]->GetAmplitude(mass, &int_didx[num][i]);
	} else {
	    Warning("GetAmplitudeLocal", "No model found");
	}
	interference+=interference_term;
    }

    if (num_terms[num])
	return numerator+interference;
    return numerator;
};

TComplex PComplexBreitWigner::GetAmplitude(Double_t *mass, Int_t *didx) {
// relativistic Breit-Wigner distribution function for particle "key"
    ReadModes();
    ReadModels();
    double weight  = 0;
    int didx_local = -1;
    if (didx) didx_local = didx[0];

    //loop over decay modes
    for (int i=0; i<num_decaychannels; i++) {
	if (didx_local < 0)
	    weight += GetAmplitudeLocal(mass, i).Rho();
	else if (didx_local == int_index[i])
	    return GetAmplitudeLocal(mass, i);
    }
    TComplex ampl(weight, 0);
    return ampl;
};


void PComplexBreitWigner::Print(const Option_t *) const {
    //loop over decay modes
    for (int i=0; i<num_decaychannels; i++) {
	//Now loop over possible interference terms
	cout << "Num:" << i << " Didx: " << int_index[i] << endl; 
	for (int j=1; j<=num_terms[i]; j++) {
	    cout << " Term: " << j << endl; 
	}
    }
}
 PComplexBreitWigner.cc:1
 PComplexBreitWigner.cc:2
 PComplexBreitWigner.cc:3
 PComplexBreitWigner.cc:4
 PComplexBreitWigner.cc:5
 PComplexBreitWigner.cc:6
 PComplexBreitWigner.cc:7
 PComplexBreitWigner.cc:8
 PComplexBreitWigner.cc:9
 PComplexBreitWigner.cc:10
 PComplexBreitWigner.cc:11
 PComplexBreitWigner.cc:12
 PComplexBreitWigner.cc:13
 PComplexBreitWigner.cc:14
 PComplexBreitWigner.cc:15
 PComplexBreitWigner.cc:16
 PComplexBreitWigner.cc:17
 PComplexBreitWigner.cc:18
 PComplexBreitWigner.cc:19
 PComplexBreitWigner.cc:20
 PComplexBreitWigner.cc:21
 PComplexBreitWigner.cc:22
 PComplexBreitWigner.cc:23
 PComplexBreitWigner.cc:24
 PComplexBreitWigner.cc:25
 PComplexBreitWigner.cc:26
 PComplexBreitWigner.cc:27
 PComplexBreitWigner.cc:28
 PComplexBreitWigner.cc:29
 PComplexBreitWigner.cc:30
 PComplexBreitWigner.cc:31
 PComplexBreitWigner.cc:32
 PComplexBreitWigner.cc:33
 PComplexBreitWigner.cc:34
 PComplexBreitWigner.cc:35
 PComplexBreitWigner.cc:36
 PComplexBreitWigner.cc:37
 PComplexBreitWigner.cc:38
 PComplexBreitWigner.cc:39
 PComplexBreitWigner.cc:40
 PComplexBreitWigner.cc:41
 PComplexBreitWigner.cc:42
 PComplexBreitWigner.cc:43
 PComplexBreitWigner.cc:44
 PComplexBreitWigner.cc:45
 PComplexBreitWigner.cc:46
 PComplexBreitWigner.cc:47
 PComplexBreitWigner.cc:48
 PComplexBreitWigner.cc:49
 PComplexBreitWigner.cc:50
 PComplexBreitWigner.cc:51
 PComplexBreitWigner.cc:52
 PComplexBreitWigner.cc:53
 PComplexBreitWigner.cc:54
 PComplexBreitWigner.cc:55
 PComplexBreitWigner.cc:56
 PComplexBreitWigner.cc:57
 PComplexBreitWigner.cc:58
 PComplexBreitWigner.cc:59
 PComplexBreitWigner.cc:60
 PComplexBreitWigner.cc:61
 PComplexBreitWigner.cc:62
 PComplexBreitWigner.cc:63
 PComplexBreitWigner.cc:64
 PComplexBreitWigner.cc:65
 PComplexBreitWigner.cc:66
 PComplexBreitWigner.cc:67
 PComplexBreitWigner.cc:68
 PComplexBreitWigner.cc:69
 PComplexBreitWigner.cc:70
 PComplexBreitWigner.cc:71
 PComplexBreitWigner.cc:72
 PComplexBreitWigner.cc:73
 PComplexBreitWigner.cc:74
 PComplexBreitWigner.cc:75
 PComplexBreitWigner.cc:76
 PComplexBreitWigner.cc:77
 PComplexBreitWigner.cc:78
 PComplexBreitWigner.cc:79
 PComplexBreitWigner.cc:80
 PComplexBreitWigner.cc:81
 PComplexBreitWigner.cc:82
 PComplexBreitWigner.cc:83
 PComplexBreitWigner.cc:84
 PComplexBreitWigner.cc:85
 PComplexBreitWigner.cc:86
 PComplexBreitWigner.cc:87
 PComplexBreitWigner.cc:88
 PComplexBreitWigner.cc:89
 PComplexBreitWigner.cc:90
 PComplexBreitWigner.cc:91
 PComplexBreitWigner.cc:92
 PComplexBreitWigner.cc:93
 PComplexBreitWigner.cc:94
 PComplexBreitWigner.cc:95
 PComplexBreitWigner.cc:96
 PComplexBreitWigner.cc:97
 PComplexBreitWigner.cc:98
 PComplexBreitWigner.cc:99
 PComplexBreitWigner.cc:100
 PComplexBreitWigner.cc:101
 PComplexBreitWigner.cc:102
 PComplexBreitWigner.cc:103
 PComplexBreitWigner.cc:104
 PComplexBreitWigner.cc:105
 PComplexBreitWigner.cc:106
 PComplexBreitWigner.cc:107
 PComplexBreitWigner.cc:108
 PComplexBreitWigner.cc:109
 PComplexBreitWigner.cc:110
 PComplexBreitWigner.cc:111
 PComplexBreitWigner.cc:112
 PComplexBreitWigner.cc:113
 PComplexBreitWigner.cc:114
 PComplexBreitWigner.cc:115
 PComplexBreitWigner.cc:116
 PComplexBreitWigner.cc:117
 PComplexBreitWigner.cc:118
 PComplexBreitWigner.cc:119
 PComplexBreitWigner.cc:120
 PComplexBreitWigner.cc:121
 PComplexBreitWigner.cc:122
 PComplexBreitWigner.cc:123
 PComplexBreitWigner.cc:124
 PComplexBreitWigner.cc:125
 PComplexBreitWigner.cc:126
 PComplexBreitWigner.cc:127
 PComplexBreitWigner.cc:128
 PComplexBreitWigner.cc:129
 PComplexBreitWigner.cc:130
 PComplexBreitWigner.cc:131
 PComplexBreitWigner.cc:132
 PComplexBreitWigner.cc:133
 PComplexBreitWigner.cc:134
 PComplexBreitWigner.cc:135
 PComplexBreitWigner.cc:136
 PComplexBreitWigner.cc:137
 PComplexBreitWigner.cc:138
 PComplexBreitWigner.cc:139
 PComplexBreitWigner.cc:140
 PComplexBreitWigner.cc:141
 PComplexBreitWigner.cc:142
 PComplexBreitWigner.cc:143
 PComplexBreitWigner.cc:144
 PComplexBreitWigner.cc:145
 PComplexBreitWigner.cc:146
 PComplexBreitWigner.cc:147
 PComplexBreitWigner.cc:148
 PComplexBreitWigner.cc:149
 PComplexBreitWigner.cc:150
 PComplexBreitWigner.cc:151
 PComplexBreitWigner.cc:152
 PComplexBreitWigner.cc:153
 PComplexBreitWigner.cc:154
 PComplexBreitWigner.cc:155
 PComplexBreitWigner.cc:156
 PComplexBreitWigner.cc:157
 PComplexBreitWigner.cc:158
 PComplexBreitWigner.cc:159
 PComplexBreitWigner.cc:160
 PComplexBreitWigner.cc:161
 PComplexBreitWigner.cc:162
 PComplexBreitWigner.cc:163
 PComplexBreitWigner.cc:164
 PComplexBreitWigner.cc:165
 PComplexBreitWigner.cc:166
 PComplexBreitWigner.cc:167
 PComplexBreitWigner.cc:168
 PComplexBreitWigner.cc:169
 PComplexBreitWigner.cc:170
 PComplexBreitWigner.cc:171
 PComplexBreitWigner.cc:172
 PComplexBreitWigner.cc:173
 PComplexBreitWigner.cc:174
 PComplexBreitWigner.cc:175
 PComplexBreitWigner.cc:176
 PComplexBreitWigner.cc:177
 PComplexBreitWigner.cc:178
 PComplexBreitWigner.cc:179
 PComplexBreitWigner.cc:180
 PComplexBreitWigner.cc:181
 PComplexBreitWigner.cc:182
 PComplexBreitWigner.cc:183
 PComplexBreitWigner.cc:184
 PComplexBreitWigner.cc:185
 PComplexBreitWigner.cc:186
 PComplexBreitWigner.cc:187
 PComplexBreitWigner.cc:188
 PComplexBreitWigner.cc:189
 PComplexBreitWigner.cc:190
 PComplexBreitWigner.cc:191
 PComplexBreitWigner.cc:192
 PComplexBreitWigner.cc:193
 PComplexBreitWigner.cc:194
 PComplexBreitWigner.cc:195
 PComplexBreitWigner.cc:196
 PComplexBreitWigner.cc:197
 PComplexBreitWigner.cc:198
 PComplexBreitWigner.cc:199
 PComplexBreitWigner.cc:200
 PComplexBreitWigner.cc:201
 PComplexBreitWigner.cc:202
 PComplexBreitWigner.cc:203
 PComplexBreitWigner.cc:204
 PComplexBreitWigner.cc:205
 PComplexBreitWigner.cc:206
 PComplexBreitWigner.cc:207
 PComplexBreitWigner.cc:208
 PComplexBreitWigner.cc:209
 PComplexBreitWigner.cc:210
 PComplexBreitWigner.cc:211
 PComplexBreitWigner.cc:212
 PComplexBreitWigner.cc:213
 PComplexBreitWigner.cc:214
 PComplexBreitWigner.cc:215
 PComplexBreitWigner.cc:216
 PComplexBreitWigner.cc:217
 PComplexBreitWigner.cc:218
 PComplexBreitWigner.cc:219
 PComplexBreitWigner.cc:220
 PComplexBreitWigner.cc:221
 PComplexBreitWigner.cc:222
 PComplexBreitWigner.cc:223
 PComplexBreitWigner.cc:224
 PComplexBreitWigner.cc:225
 PComplexBreitWigner.cc:226
 PComplexBreitWigner.cc:227
 PComplexBreitWigner.cc:228
 PComplexBreitWigner.cc:229
 PComplexBreitWigner.cc:230
 PComplexBreitWigner.cc:231
 PComplexBreitWigner.cc:232
 PComplexBreitWigner.cc:233
 PComplexBreitWigner.cc:234
 PComplexBreitWigner.cc:235
 PComplexBreitWigner.cc:236
 PComplexBreitWigner.cc:237
 PComplexBreitWigner.cc:238
 PComplexBreitWigner.cc:239
 PComplexBreitWigner.cc:240
 PComplexBreitWigner.cc:241
 PComplexBreitWigner.cc:242
 PComplexBreitWigner.cc:243
 PComplexBreitWigner.cc:244
 PComplexBreitWigner.cc:245
 PComplexBreitWigner.cc:246
 PComplexBreitWigner.cc:247
 PComplexBreitWigner.cc:248
 PComplexBreitWigner.cc:249
 PComplexBreitWigner.cc:250
 PComplexBreitWigner.cc:251
 PComplexBreitWigner.cc:252
 PComplexBreitWigner.cc:253
 PComplexBreitWigner.cc:254
 PComplexBreitWigner.cc:255
 PComplexBreitWigner.cc:256
 PComplexBreitWigner.cc:257
 PComplexBreitWigner.cc:258
 PComplexBreitWigner.cc:259
 PComplexBreitWigner.cc:260
 PComplexBreitWigner.cc:261
 PComplexBreitWigner.cc:262
 PComplexBreitWigner.cc:263
 PComplexBreitWigner.cc:264
 PComplexBreitWigner.cc:265
 PComplexBreitWigner.cc:266
 PComplexBreitWigner.cc:267
 PComplexBreitWigner.cc:268
 PComplexBreitWigner.cc:269
 PComplexBreitWigner.cc:270
 PComplexBreitWigner.cc:271
 PComplexBreitWigner.cc:272
 PComplexBreitWigner.cc:273
 PComplexBreitWigner.cc:274
 PComplexBreitWigner.cc:275
 PComplexBreitWigner.cc:276
 PComplexBreitWigner.cc:277
 PComplexBreitWigner.cc:278
 PComplexBreitWigner.cc:279
 PComplexBreitWigner.cc:280
 PComplexBreitWigner.cc:281
 PComplexBreitWigner.cc:282
 PComplexBreitWigner.cc:283
 PComplexBreitWigner.cc:284
 PComplexBreitWigner.cc:285
 PComplexBreitWigner.cc:286