/////////////////////////////////////////////////////////////////////
//  PDistributionManager Class implementation file
//
//  PDistributionManager keeps information about all distributions
//  Users can add user-defined distributions
// 
//
//                                  Author:  I. Froehlich
/////////////////////////////////////////////////////////////////////


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

#include "PDistributionManager.h"

#include "../Plugins.h"
#include "TFile.h"

PDistributionManager *gDM=0;          // global pointer 

PDistributionManager &fDistributionManager() {
    static PDistributionManager *ans = new PDistributionManager();
    return *ans;
}

PDistributionManager *makeDistributionManager() {
    return &fDistributionManager();
}

PDistributionManager::PDistributionManager() {

    collect_pointer = 0;
    makeStaticData();

    pdmutil = makeDistributionManagerUtil();
    
    pdmutil->no_warning = kTRUE;
	
    //some bugfixes .... TODO: Move this to extra plugin
    //makeStaticData()->AddDecay("eta' Dalitz", "eta'","dilepton,g",0.0009);

    std_models = new PStdModels();
    std_models->Add(pdmutil);

    pdmutil->AddGroup("plugins", "Plugins");
    SetGroup("plugins");

    batch = NULL;
    loop_start = NULL;

#include "../Plugins.cc"

    pdmutil->no_warning = kFALSE; //workaround in Add()

    from_pdecaymanager = 0;

    SetGroup("user");

    Info("PDistributionManager()", "(%s)", PRINT_CTOR);
}

int PDistributionManager::Attach(PChannel *ch) {
    //Attach the PChannel "ch" to the distribution manager
    //This enables all distributions in the PChannel
    //and fills the PChannel with life

    //before Attaching, make the data base link
    pdmutil->LinkDB(); 

    ActivateStdModels();

    return pdmutil->Attach(ch);
}

void PDistributionManager::ActivateStdModels(void) {
    pdmutil->LinkDB(); 
    if (!makeStaticData()->GetFreezeOut()) {
        pdmutil->no_warning = kTRUE;
        //remove warning, otherwise the Add() will cause warning
	//Add(makeStdModels()->GetModels());
	std_models->Add(pdmutil);

        pdmutil->no_warning = kFALSE;
	Info("Attach", "Re-iteration of std plugin done");
	pdmutil->LinkDB(); 
    }    
}

Bool_t PDistributionManager::AddPlugin(PDistributionCollection *plugin) {
    if (collect_pointer == PDISTRIBUTIONMANAGER_MAX_COLLECT) {
	Warning("AddPlugin", "PDISTRIBUTIONMANAGER_MAX_COLLECT reached");
	return kFALSE;
    }
    collect[collect_pointer] = plugin;
    collect_pointer++;

    plugin->SetEnable(0);
    if (makeDistributionManagerUtil()->Add(plugin)) {
	return kFALSE;
    }

    return kTRUE;
}

Bool_t PDistributionManager::Activate(const char *name) {
    //is model existing?
    if (!GetDistribution(name)) {
	Warning("Activate","plugin %s does not exist", name);
	return kFALSE;
    }
    //first check if model is already activated
    if (GetDistribution(name)->GetEnable() && GetDistribution(name)->GetActivated()) return kTRUE;
    
    for (int i=0; i<collect_pointer; i++) {
	if (strcmp(name,collect[i]->GetIdentifier()) == 0) {
	    //first we check the dependencies
	    Int_t pointer = 0;
	    const char *depname = NULL;
	    while ((depname=collect[i]->GetDependency(&pointer)) !=NULL) {
		//Activate(depname);
		Exec(depname);
	    }
	    if (collect[i]->Activate()) {
		Info("Exec", "Plugin <%s> activated", name);
		collect[i]->SetEnable(1);
		collect[i]->SetActivated(1);
		SetGroup("user");
		return kTRUE;
	    }
	    Warning("Activate", "plugin %s could not be activated",name);
	    return kFALSE;
	}
    }
    Warning("Activate", "plugin %s does not exist",name);
    return kFALSE;
}

#if 1
Bool_t PDistributionManager::ExecAll(const char *command) {
    //sends "command" to all enabled plugins

    for (int i=0; i<collect_pointer; i++) {
	if (collect[i]->GetEnable()) {
	    collect[i]->ExecCommand(command,0);
	}
    }
    return kTRUE;
}
#endif

Bool_t PDistributionManager::Exec(const char *command) {
    //Executes a command like "model: command"
    //If "model" is a plugin, it is activated first

    //split at ":"
    char *array2[200];
    Int_t array2_s = 200; 
    PUtils::Tokenize(command, ":", array2, &array2_s);
    
    if (array2_s > 2) {
	Warning("Exec", "Syntax error: Too many :'s");
	return kFALSE;
    } else {
	//First check for a distribution
	PDistribution *dist = GetDistribution(array2[0]);
	if (!dist) {
	    Warning("Exec", "model/plugin %s does not exist", array2[0]);
	    return kFALSE;
	}

	if (Activate(array2[0])) {
	    if (array2_s == 2) {
		dist = GetDistribution(array2[0]);
		if (dist->Exec(array2[1])) {
		    SetGroup("user");
		    return kTRUE;
		}
		SetGroup("user");
		return kFALSE;
	    } else  { //Consider also "empty" executions
		dist = GetDistribution(array2[0]);
		if (dist->Exec("")) {
		    SetGroup("user");
		    return kTRUE;
		}
		SetGroup("user");
		return kFALSE;
	    }
	    //	    return kTRUE;
	}
    }

    return kFALSE;
};

void PDistributionManager::PluginInfo(const char *info) {   
    Info("PDistributionManager", info);
};


Bool_t PDistributionManager::Startup(const char *command) {
    if (!batch) 
	batch = new PBatch;
    batch->AddCommand(command);
    return kTRUE;
};

Bool_t PDistributionManager::Startup(void) {
    if (!batch) return kFALSE;
    return batch->Execute();
};

Bool_t PDistributionManager::Unpack(const char *filename) {
    //Unpack the command list
    //The "_main" object is executed immediately

    //BUGBUG: Avoid that the same pack is used 2times
    TFile *current = gROOT->GetFile();
    new TFile(filename);

    //Unpack "_main"
    PCommandList *main = (PCommandList*)gROOT->FindObject("_main");

    if (main) {
	PBatch *priv = new PBatch();
	int level = 0;
	char *cmd;
	while (main->GetCommand(&cmd, level)) {
	    level++;
	    if (cmd) {
		priv->AddCommand(cmd);
	    }
	    if (level > MAX_COMMAND_POINTER) return kFALSE; //breakup
	}
	priv->Execute();
    }

    //Unpack "_startup"
    PCommandList *startup = (PCommandList*)gROOT->FindObject("_startup");

    if (startup) {
	int level = 0;
	char *cmd;
	while (startup->GetCommand(&cmd, level)) {
	    level++;
	    if (cmd) {
		Startup(cmd);
	    }
	    if (level > MAX_COMMAND_POINTER) return kFALSE; //breakup
	}
    }

    //Unpack first projector for event loop
    PCommandList *loop_start_cmd = 
	(PCommandList*)gROOT->FindObject("_loop");

    if (loop_start_cmd) {
	if (loop_start) {
	    Error("Unpack", "Loop command list already defined");
	    //TODO: stack?
	} else {
	    loop_start = new PProjector();
	    loop_start->SetPriority(FILTER_PRIORITY);
	    int level = 0;
	    char *cmd;
	    TObject *obj = NULL;
	    while (loop_start_cmd->GetCommand(&cmd, level, &obj)) {
		level++;
		if (cmd) {
		    if (!obj)
			loop_start->AddCommand(cmd);
		    else if (!strncmp(obj->ClassName(), "TH1", 3)) {
			Info("Unpack", "Recovered TH1 <%s>", obj->GetName());
			loop_start->AddHistogram((TH1*)obj, cmd, 0); //nofill flag set
		    } else if (!strncmp(obj->ClassName(), "TH2", 3)) {
			Info("Unpack", "Recovered TH2 <%s>", obj->GetName());
			loop_start->AddHistogram((TH2*)obj,cmd,0); //nofill flag set
		    } else if (!strncmp(obj->ClassName(), "TH3", 3)) {
			Info("Unpack", "Recovered TH3 <%s>", obj->GetName());
			loop_start->AddHistogram((TH3*)obj, cmd, 0); //nofill flag set
		    } else {
			Warning("Unpack", "Object <%s> is of type <%s>. Unsupported and ignored",
				obj->GetName(), obj->ClassName());
			loop_start->AddCommand(cmd);
		    }

		}
		if (level>MAX_COMMAND_POINTER) return kFALSE; //break
	    }	    
	}
    }


    if (current)
	current->cd();

    return kTRUE;

}

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