//  Modified $ROOTSYS/tutorials/hsimple.C example.
//
//   This example demonstrates:
//
// - all features of $ROOTSYS/tutorials/hsimple.C example +
// - how to create an interpreted class with signals, e.g. Hsimple.
//   Activated signals will report about dynamic state of
//   histogram processing.
// - how to use signals of TTimer class for "multithread" processing.
//
//*******************************************************************
//
//  1. Run ROOT
//  2. Type .L rqsimple.C  (or rqsimple.C++)
//  3. Type rqsimple()
//
//*******************************************************************

#include <TROOT.h>
#include <TTimer.h>
#include <TFile.h>
#include <TH1.h>
#include <TH2.h>
#include <TCanvas.h>
#include <TProfile.h>
#include <TNtuple.h>
#include <TRandom.h>
#include <TBenchmark.h>
#include <TFrame.h>
#include <RQ_OBJECT.h>

//////////////////////////////////////////////////////////////////////
class Hsimple {

RQ_OBJECT("Hsimple")  // for classes not derived from TQObject
                      // RQ_OBJECT macro should be used
private:
   TH1F       *fHpx;       // This is the px distribution
   TH2F       *fHpxpy;     // py vs px
   TProfile   *fHprof;     // Profile of pz versus px"
   TNtuple    *fNtuple;    // Demo ntuple
   Int_t       fEvent;

   enum { kUPDATE = 1000, kFillLimit = 250000 };

public:
   Hsimple();
   ~Hsimple();

   void  Draw(Option_t *opt = "") { fHpx->Draw(opt); }
   void  Fill();
   void  Reset();
   void  Emptied() { Emit("Emptied()"); }  //*SIGNAL*
   void  Filled()  { Emit("Filled()"); }   //*SIGNAL*
   void  Updated() { Emit("Updated()"); }  //*SIGNAL*
   TObject *GetObject(Int_t idx) const;
};

//___________________________________________________________________
Hsimple::Hsimple()
{
   // Constructor.

   // Create some histograms, a profile histogram and an fNtuple
   fHpx    = new TH1F("hpx","This is the px distribution",100,-4,4);
   fHpxpy  = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4);
   fHprof  = new TProfile("hprof","Profile of pz versus px",
                           100,-4,4,0,20);
   fNtuple = new TNtuple("ntuple","Demo fNtuple",
                         "px:py:pz:random:i");
   fHpx->SetFillColor(16);
}

//___________________________________________________________________
Hsimple::~Hsimple()
{
   // Destructor.

   delete fHpx;
   delete fHpxpy;
   delete fHprof;
   delete fNtuple;
}
//___________________________________________________________________
TObject *Hsimple::GetObject(Int_t idx) const
{
   // Returns the desired histogram or ntuple object.

   switch(idx) {
   case 0:
      return fHpx;
      break;
   case 1:
      return fHpxpy;
   case 2:
      return fHprof;
   case 3:
      return fNtuple;
   default:
      return fHpx;
   }
}

//___________________________________________________________________
void Hsimple::Reset()
{
   // Resets all hists, emits signal Reset().

   fHpx->Reset();
   fHpxpy->Reset();
   fHprof->Reset();
   fNtuple->Reset();
   gRandom->SetSeed();
   fEvent=0;
   Emptied();
}

//___________________________________________________________________
void Hsimple::Fill()
{
   // Fill histograms randomly.
   //
   // Dynamic state of Hsimple is indicated by signals:
   //
   // o "Emptied()"      - enitted whenever Hsimple is reseted
   // o "Updated(Int_t)" - emitted after each update cycle
   //                      consisting of kUPDATE events.
   // o "Filled(Int_t)"  - emitted when fill limit is reached.

   Float_t px, py, pz;

   while(1) {
      gRandom->Rannor(px,py);
      pz = px*px + py*py;
      Float_t random = gRandom->Rndm(1);
      fHpx->Fill(px);
      fHpxpy->Fill(px,py);
      fHprof->Fill(px,pz);
      fNtuple->Fill(px,py,pz,random,fEvent);
      fEvent++;
      if ((fEvent%kUPDATE) == 0) {
         Updated(); // emit Updated signal
         break;
      }
   }
   if (fEvent > kFillLimit) Filled();   // emit Filled signal
}


TTimer *timer = 0;

//___________________________________________________________________
void rqsimple()
{
   // Books histograms and starts filling thread.
   //
   //  The dynamic state of the Hsimple object is reported by
   //  the following signals:
   //
   // o "Emptied()"      - emitted whenever histos are reseted
   // o "Updated(Int_t)" - emitted after each update cycle
   //                      consisting of kUPDATE events.
   // o "Filled(Int_t)"  - emitted when fill limit is reached.
   //

   // Create a new canvas.
   TCanvas *c1 = new TCanvas("fCanvas",
                             "Hsimple Example with Signals Handling",
                             200,10,700,500);
   c1->SetFillColor(42);
   c1->GetFrame()->SetFillColor(21);
   c1->GetFrame()->SetBorderSize(6);
   c1->GetFrame()->SetBorderMode(-1);

   // Create a new ROOT binary machine independent file.
   // Note that this file may contain any kind of ROOT objects,
   // histograms, pictures, graphics objects, detector geometries,
   // tracks, events, etc..
   // This file is now becoming the current directory.

   TFile *hfile = (TFile*)gROOT->FindObject("hsimplem.root");
   if (hfile) hfile->Close();
   hfile = new TFile("hsimplem.root","RECREATE",
                     "Demo ROOT file with histograms");

   Hsimple *simple = new Hsimple();
   simple->Draw();

   if (timer)
      TQObject::Disconnect(timer);  // disconnect everything
   else
      timer = new TTimer(100);   // 100 msec timeout

   // connect TTimer::Timeout signal to simple->Fill()
   timer->Connect("Timeout()", "Hsimple", simple, "Fill()");

   // connect TTimer::TurnOn signal to simple->Reset()
   timer->Connect("TurnOn()", "Hsimple", simple, "Reset()");

   // connect to benchmark facility
   timer->Connect("TurnOff()", "TBenchmark",
                  gBenchmark, "Show(=\"hsimplem\")");

   // connect to turn-off the timer
   simple->Connect("Filled()", "TTimer", timer, "TurnOff()");

   // write to file when simple is filled
   simple->Connect("Filled()", "TFile", hfile, "Write()");

   // connect Hsimple::Updated signal to c1->Modified(),c1->Update()
   simple->Connect("Updated()", "TCanvas", c1, "Modified()");
   simple->Connect("Updated()", "TCanvas", c1, "Update()");

   gBenchmark->Reset();
   gBenchmark->Start("hsimplem");
   timer->TurnOn();
}


