#include "CDFMonitoringModule.h"

#include <CDFMonitoringFwk/TConsumerInfo.h>
#include <CDFMonitoringFwk/ConsumerExport.h>

#include <MessageService/MsgService.h>
#include <JobControl/JobCModuleRegistry.h>
#include <JobControl/JobCResult.h>

#include <HistMan/HistMan.h>

#include <TROOT.h>
#include <TFolder.h>

// for spew()
#include <DataUtil/GetRecords.h>
#include <RawData/RawRecord.h>
#include <string>
#include <vector>

#include <TStyle.h>

using namespace std;

CVSID("$Id: CDFMonitoringModule.cxx,v 1.8 2007/01/29 23:00:37 gmieg Exp $");
JOBMODULE(CDFMonitoringModule,"CDFMonitoring","Talk to the CDFMonitoringFwk");


const int CDFMonitoringModule::default_port = 9050;
const char* CDFMonitoringModule::default_folder = "Monitoring";
const int CDFMonitoringModule::default_refresh = 1;

class CDFMonitoringModuleImp {
    ConsumerExport fConsExp;
    TConsumerInfo fConsInfo;
    const char* fPath;
    int fCount, fRefreshPeriod;

    map<string,TObject*> fObjectMap;


public:
    CDFMonitoringModuleImp(int port, const char* name, int refresh);
    ~CDFMonitoringModuleImp();

    // Push objects to the ConsumerExport if refresh period has
    // passed.
    void Update();	

    // Add the given object to be monitored at the given path.
    // TFolders will be recursively traversed and will have all
    // objects added.
    void AddObject(TObject* o, string path=""); 
};

CDFMonitoringModuleImp::CDFMonitoringModuleImp(int port, const char* name,
					       int refresh)
    : fConsExp(port)
    , fConsInfo(name,0)
    , fPath(name)
    , fCount(0)
    , fRefreshPeriod(refresh)
{
}
CDFMonitoringModuleImp::~CDFMonitoringModuleImp()
{
}

void CDFMonitoringModuleImp::AddObject(TObject* o, string path)
{
    TFolder* f = dynamic_cast<TFolder*>(o);

    if (f) {			// it's a folder

	if (string("private") == f->GetName()) {
	    MSG("BD",Msg::kVerbose) << "skipping private folder\n";
	    return;
	}

	TCollection* sf = f->GetListOfFolders();
	if (!sf) return;		// empty

	if (path != "") path += "/";
	path += f->GetName();

	MSG("BD",Msg::kVerbose)
	    << "iterating on folder \"" << f->GetName() << "\"\n";

	TIter it(sf->MakeIterator());
	TObject* obj=0;
	while ( (obj=it()) ) this->AddObject(obj,path);
	return;
    }

    // not a folder

    string objpath = path;
    if (objpath != "") objpath += "/";
    objpath += o->GetName();
    TObject* other = fObjectMap[objpath];

    if (! other) {		// haven't seen it yet
	fObjectMap[objpath] = o;
	fConsInfo.addObject(o->GetName(), path.c_str(), 0, o);
	MSG("BD",Msg::kDebug)
	    << "adding object \"" << o->GetName() << "\" of type \"" <<
	    o->Class_Name() << "\" to \""
	    << path << "\" and saving  at \"" << objpath << "\"\n";
	return;
    }
    if (other != o) {	// exists but differs
	MSG("BD",Msg::kWarning)
	    << "pre-existing object at " << objpath << endl;
	return;
    }
    return;			// already added and is same
}

void CDFMonitoringModuleImp::Update()
{
    if (fCount < fRefreshPeriod && fCount % fRefreshPeriod) return;
    MSG("BD",Msg::kVerbose)
	<< "refreshing at " << fCount << " with period " << fRefreshPeriod << endl;

    HistMan hm(fPath);

    TFolder& f = hm.BaseFolder();
    TFolder* folder = dynamic_cast<TFolder*>(f.FindObject(fPath));
    if (!folder) {
	MSG("BD",Msg::kWarning)
	    << "Failed to find folder " << fPath << endl;
    }

    this->AddObject(folder);

    fConsExp.send(&fConsInfo);
}



//-------------------------//



CDFMonitoringModule::CDFMonitoringModule()
    : fImp(0)
{
    fImp = new CDFMonitoringModuleImp(9050,"Monitoring",1);
}
CDFMonitoringModule::~CDFMonitoringModule()
{
    if (fImp) delete fImp; fImp=0;
}

void CDFMonitoringModule::BeginJob()
{
    return;

    int port = default_port, refresh = default_refresh;
    const char* folder = default_folder;

    Registry& cfg = this->GetConfig();
    cfg.Get("port",port);
    cfg.Get("refresh",refresh);
    cfg.Get("folder",folder);

    if (fImp) delete fImp;
    fImp = new CDFMonitoringModuleImp(port,folder,refresh);
    MSG("BD",Msg::kDebug) << "Created connection to port " << port
			  << " using path \"" << folder << "\"\n";

}
void CDFMonitoringModule::EndJob()
{
    MSG("BD",Msg::kDebug)
	<< "EndJob" << endl;
    if (fImp) delete fImp; fImp = 0;
}

void CDFMonitoringModule::BeginFile()
{
    MSG("BD",Msg::kInfo)
	<< "Begin file" << endl;
}

void CDFMonitoringModule::EndFile()
{
    MSG("BD",Msg::kInfo)
	<< "End file" << endl;
}
#if 0
static void spew(const MomNavigator* mom)
{
    vector<const RawRecord*> rrv = DataUtil::GetRecords<const RawRecord>(mom);
    for (size_t ind=0; ind<rrv.size(); ++ind) {
	const RawRecord* rr = rrv[ind];
        string stream_name = rr->GetTempTags().GetCharString("stream");
	cerr << rr->GetTempTags() << endl;
    }
}
#endif
JobCResult CDFMonitoringModule::Ana(const MomNavigator */*mom*/)
{
  gStyle->SetAxisColor(1, "xyz");
gStyle->SetCanvasColor(0);
gStyle->SetFrameFillColor(0);
gStyle->SetFrameLineColor(1);
gStyle->SetHistFillColor(0);
gStyle->SetHistLineColor(1);
gStyle->SetPadColor(1);
gStyle->SetStatColor(0);
gStyle->SetStatTextColor(1);
gStyle->SetTitleColor(1);
gStyle->SetTitleTextColor(1);
gStyle->SetLabelColor(1,"xyz");
 gStyle->SetTitleOffset(1.2,"y"); 
gStyle->SetOptStat(1110);
gROOT->ForceStyle();


    if (!fImp) {
	MSG("BD",Msg::kError)
	    << "No implementation! Ana() called w/out a BeginJob()\n";
	return JobCResult::kError;
    }
    fImp->Update();
    //spew(mom);
    return JobCResult::kAOK;
}
const Registry& CDFMonitoringModule::DefaultConfig() const
{
    static Registry cfg;
    if (cfg.Size() == 0) {
	cfg.Set("port",default_port);
	cfg.Set("refresh",default_refresh);
	cfg.Set("folder",default_folder);
    }
    return cfg;
}
