    // @(#)root/eg:$Name:  $:$Id: TGenerator.cxx,v 1.7 2002/01/24 11:39:27 rdm Exp $
    // Author: Ola Nordmann   21/09/95

    /*************************************************************************
     * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
     * All rights reserved.                                                  *
     *                                                                       *
     * For the licensing terms see $ROOTSYS/LICENSE.                         *
     * For the list of contributors see $ROOTSYS/README/CREDITS.             *
     *************************************************************************/

    //////////////////////////////////////////////////////////////////////////
    //                                                                      //
    // TGenerator                                                            //
    //                                                                      //
    // Is an abstact base class, that defines the interface of ROOT and the //
    // various event generators. Every event generator should inherit from  //
    // TGenerator or its subclasses.                                         //
    //                                                                      //
    // Every class inherited from TGenerator knows already the interface to  //
    // the /HEPEVT/ common block. So in the event creation of the various   //
    // generators, the /HEPEVT/ common block should be filled               //
    // The ImportParticles method then parses the result from the event        //
    // generators into a TClonesArray of TParticle objects.                   //
    //                                                                      //
    //////////////////////////////////////////////////////////////////////////

    #include "TROOT.h"
    #include "TGenerator.h"
    #include "TDatabasePDG.h"
    #include "TParticlePDG.h"
    #include "TParticle.h"
    #include "TObjArray.h"
    #include "Hepevt.h"
    #include "TVirtualPad.h"
    #include "TView.h"
    #include "TText.h"
    #include "TPaveText.h"
    #include "TClonesArray.h"
    #include "Riostream.h"

    ClassImp(TGenerator)

    //______________________________________________________________________________
     TGenerator::TGenerator(const char *name,const char *title): TNamed(name,title)
    {
    //
    //  Event generator default constructor
    //

      //  Initialize particles table
       TDatabasePDG::Instance();
       //TDatabasePDG *pdg = TDatabasePDG::Instance();
       //if (!pdg->ParticleList()) pdg->Init();

       fPtCut        = 0;
       fShowNeutrons = kTRUE;
       fParticles    =  new TObjArray(10000);
    }

    //______________________________________________________________________________
     TGenerator::~TGenerator()
    {
    //
    //  Event generator default destructor
    //

       //do nothing
       if (fParticles) {
          fParticles->Delete();
          delete fParticles;
          fParticles = 0;
       }
    }

    //______________________________________________________________________________
     TObjArray* TGenerator::ImportParticles(Option_t *option)
    {
    //
    //  Default primary creation method. It reads the /HEPEVT/ common block which
    //  has been filled by the GenerateEvent method. If the event generator does
    //  not use the HEPEVT common block, This routine has to be overloaded by
    //  the subclasses.
    //  The default action is to store only the stable particles (ISTHEP = 1)
    //  This can be demanded explicitly by setting the option = "Final"
    //  If the option = "All", all the particles are stored.
    //
      fParticles->Clear();
      Int_t numpart = HEPEVT.nhep;
      if (!strcmp(option,"") || !strcmp(option,"Final")) {
        for (Int_t i = 0; i<numpart; i++) {
          if (HEPEVT.isthep[i] == 1) {
    //
    //  Use the common block values for the TParticle constructor
    //
            TParticle *p = new TParticle(
                                       HEPEVT.idhep[i],
                                       HEPEVT.isthep[i],
                                       HEPEVT.jmohep[i][0]-1,
                                       HEPEVT.jmohep[i][1]-1,
                                       HEPEVT.jdahep[i][0]-1,
                                       HEPEVT.jdahep[i][1]-1,

                                       HEPEVT.phep[i][0],
                                       HEPEVT.phep[i][1],
                                       HEPEVT.phep[i][2],
                                       HEPEVT.phep[i][3],
                                       HEPEVT.vhep[i][0],
                                       HEPEVT.vhep[i][1],
                                       HEPEVT.vhep[i][2],
                                       HEPEVT.vhep[i][3]);
            fParticles->Add(p);
            }
         }
      }
      else if (!strcmp(option,"All")) {
        for (Int_t i = 0; i<numpart; i++) {
          TParticle *p = new TParticle(
                                       HEPEVT.idhep[i],
                                       HEPEVT.isthep[i],
                                       HEPEVT.jmohep[i][0]-1,
                                       HEPEVT.jmohep[i][1]-1,
                                       HEPEVT.jdahep[i][0]-1,
                                       HEPEVT.jdahep[i][1]-1,

                                       HEPEVT.phep[i][0],
                                       HEPEVT.phep[i][1],
                                       HEPEVT.phep[i][2],
                                       HEPEVT.phep[i][3],
                                       HEPEVT.vhep[i][0],
                                       HEPEVT.vhep[i][1],
                                       HEPEVT.vhep[i][2],
                                       HEPEVT.vhep[i][3]);
          fParticles->Add(p);
        }
      }
      return fParticles;
    }

    //______________________________________________________________________________
     Int_t TGenerator::ImportParticles(TClonesArray *particles, Option_t *option)
    {
    //
    //  Default primary creation method. It reads the /HEPEVT/ common block which
    //  has been filled by the GenerateEvent method. If the event generator does
    //  not use the HEPEVT common block, This routine has to be overloaded by
    //  the subclasses.
    //  The function loops on the generated particles and store them in
    //  the TClonesArray pointed by the argument particles.
    //  The default action is to store only the stable particles (ISTHEP = 1)
    //  This can be demanded explicitly by setting the option = "Final"
    //  If the option = "All", all the particles are stored.
    //
      if (particles == 0) return 0;
      TClonesArray &Particles = *particles;
      Particles.Clear();
      Int_t numpart = HEPEVT.nhep;
      if (!strcmp(option,"") || !strcmp(option,"Final")) {
        for (Int_t i = 0; i<numpart; i++) {
          if (HEPEVT.isthep[i] == 1) {
    //
    //  Use the common block values for the TParticle constructor
    //
            new(Particles[i]) TParticle(
                                       HEPEVT.idhep[i],
                                       HEPEVT.isthep[i],
                                       HEPEVT.jmohep[i][0]-1,
                                       HEPEVT.jmohep[i][1]-1,
                                       HEPEVT.jdahep[i][0]-1,
                                       HEPEVT.jdahep[i][1]-1,

                                       HEPEVT.phep[i][0],
                                       HEPEVT.phep[i][1],
                                       HEPEVT.phep[i][2],
                                       HEPEVT.phep[i][3],
                                       HEPEVT.vhep[i][0],
                                       HEPEVT.vhep[i][1],
                                       HEPEVT.vhep[i][2],
                                       HEPEVT.vhep[i][3]);
            }
         }
      }
      else if (!strcmp(option,"All")) {
        for (Int_t i = 0; i<numpart; i++) {
          new(Particles[i]) TParticle(
                                       HEPEVT.idhep[i],
                                       HEPEVT.isthep[i],
                                       HEPEVT.jmohep[i][0]-1,
                                       HEPEVT.jmohep[i][1]-1,
                                       HEPEVT.jdahep[i][0]-1,
                                       HEPEVT.jdahep[i][1]-1,

                                       HEPEVT.phep[i][0],
                                       HEPEVT.phep[i][1],
                                       HEPEVT.phep[i][2],
                                       HEPEVT.phep[i][3],
                                       HEPEVT.vhep[i][0],
                                       HEPEVT.vhep[i][1],
                                       HEPEVT.vhep[i][2],
                                       HEPEVT.vhep[i][3]);
        }
      }
      return numpart;
    }

    //______________________________________________________________________________
     void TGenerator::Browse(TBrowser *)
    {
        Draw();
        gPad->Update();
    }

    //______________________________________________________________________________
     Int_t TGenerator::DistancetoPrimitive(Int_t px, Int_t py)
    {
    //*-*-*-*-*-*-*-*Compute distance from point px,py to objects in event*-*-*-*
    //*-*            =====================================================
    //*-*

       const Int_t big = 9999;
       const Int_t inview = 0;
       Int_t dist = big;
       if (px > 50 && py > 50) dist = inview;
       return dist;
    }

    //______________________________________________________________________________
     void TGenerator::Draw(Option_t *option)
    {
    //
    //  Insert one event in the pad list
    //

      // Create a default canvas if a canvas does not exist
       if (!gPad) {
          if (!gROOT->GetMakeDefCanvas()) return;
          (gROOT->GetMakeDefCanvas())();
          gPad->GetVirtCanvas()->SetFillColor(13);
       }

       static Float_t rbox = 1000;
       Float_t rmin[3],rmax[3];
       TView *view = gPad->GetView();
       if (!strstr(option,"same")) {
          if (view) { view->GetRange(rmin,rmax); rbox = rmax[2];}
          gPad->Clear();
       }

       AppendPad(option);

       view = gPad->GetView();
       //    compute 3D view
       if (view) {
          view->GetRange(rmin,rmax);
          rbox = rmax[2];
       } else {
          view = new TView(1);
          view->SetRange(-rbox,-rbox,-rbox, rbox,rbox,rbox );
       }
       const Int_t kColorProton    = 4;
       const Int_t kColorNeutron   = 5;
       const Int_t kColorAntiProton= 3;
       const Int_t kColorPionPlus  = 6;
       const Int_t kColorPionMinus = 2;
       const Int_t kColorKaons     = 7;
       const Int_t kColorElectrons = 0;
       const Int_t kColorGamma     = 18;

       Int_t NProtons    = 0;
       Int_t NNeutrons   = 0;
       Int_t NAntiProtons= 0;
       Int_t NPionPlus   = 0;
       Int_t NPionMinus  = 0;
       Int_t NKaons      = 0;
       Int_t NElectrons  = 0;
       Int_t NGammas     = 0;

       Int_t ntracks = fParticles->GetEntriesFast();
       Int_t i,lwidth,color,lstyle;
       TParticlePDG *ap;
       TParticle *p;
       const char *name;
       Double_t etot,vx,vy,vz;
       Int_t ninvol = 0;
       for (i=0;i<ntracks;i++) {
          p = (TParticle*)fParticles->UncheckedAt(i);
          if(!p) continue;
          ap = (TParticlePDG*)p->GetPDG();
          vx = p->Vx();
          vy = p->Vy();
          vz = p->Vz();
          if  (vx*vx+vy*vy+vz*vz > rbox*rbox) continue;
          Float_t pt = p->Pt();
          if (pt < fPtCut) continue;
          etot = p->Energy();
          if (etot > 0.1) lwidth = Int_t(6*TMath::Log10(etot));
          else lwidth = 1;
          if (lwidth < 1) lwidth = 1;
          lstyle = 1;
          color = 0;
          name = ap->GetName();
          if (!strcmp(name,"n"))     { if (!fShowNeutrons) continue;
                                       color = kColorNeutron;    NNeutrons++;}
          if (!strcmp(name,"p"))     { color = kColorProton;     NProtons++;}
          if (!strcmp(name,"p bar")) { color = kColorAntiProton; NAntiProtons++;}
          if (!strcmp(name,"pi+"))   { color = kColorPionPlus;   NPionPlus++;}
          if (!strcmp(name,"pi-"))   { color = kColorPionMinus;  NPionMinus++;}
          if (!strcmp(name,"e+"))    { color = kColorElectrons;  NElectrons++;}
          if (!strcmp(name,"e-"))    { color = kColorElectrons;  NElectrons++;}
          if (!strcmp(name,"gamma")) { color = kColorGamma;      NGammas++; lstyle = 3; }
          if ( strstr(name,"K"))     { color = kColorKaons;      NKaons++;}
          p->SetLineColor(color);
          p->SetLineStyle(lstyle);
          p->SetLineWidth(lwidth);
          p->AppendPad();
          ninvol++;
       }

       // event title
       TPaveText *pt = new TPaveText(-0.94,0.85,-0.25,0.98,"br");
       pt->AddText((char*)GetName());
       pt->AddText((char*)GetTitle());
       pt->SetFillColor(42);
       pt->Draw();

       // Annotate color codes
       Int_t tcolor = 5;
       if (gPad->GetFillColor() == 10) tcolor = 4;
       TText *text = new TText(-0.95,-0.47,"Particles");
       text->SetTextAlign(12);
       text->SetTextSize(0.025);
       text->SetTextColor(tcolor);
       text->Draw();
       text->SetTextColor(kColorGamma);      text->DrawText(-0.95,-0.52,"(on screen)");
       text->SetTextColor(kColorGamma);      text->DrawText(-0.95,-0.57,"Gamma");
       text->SetTextColor(kColorProton);     text->DrawText(-0.95,-0.62,"Proton");
       text->SetTextColor(kColorNeutron);    text->DrawText(-0.95,-0.67,"Neutron");
       text->SetTextColor(kColorAntiProton); text->DrawText(-0.95,-0.72,"AntiProton");
       text->SetTextColor(kColorPionPlus);   text->DrawText(-0.95,-0.77,"Pion +");
       text->SetTextColor(kColorPionMinus);  text->DrawText(-0.95,-0.82,"Pion -");
       text->SetTextColor(kColorKaons);      text->DrawText(-0.95,-0.87,"Kaons");
       text->SetTextColor(kColorElectrons);  text->DrawText(-0.95,-0.92,"Electrons,etc.");

       text->SetTextColor(tcolor);
       text->SetTextAlign(32);
       char tcount[32];
       sprintf(tcount,"%d",ntracks);      text->DrawText(-0.55,-0.47,tcount);
       sprintf(tcount,"%d",ninvol);       text->DrawText(-0.55,-0.52,tcount);
       sprintf(tcount,"%d",NGammas);      text->DrawText(-0.55,-0.57,tcount);
       sprintf(tcount,"%d",NProtons);     text->DrawText(-0.55,-0.62,tcount);
       sprintf(tcount,"%d",NNeutrons);    text->DrawText(-0.55,-0.67,tcount);
       sprintf(tcount,"%d",NAntiProtons); text->DrawText(-0.55,-0.72,tcount);
       sprintf(tcount,"%d",NPionPlus);    text->DrawText(-0.55,-0.77,tcount);
       sprintf(tcount,"%d",NPionMinus);   text->DrawText(-0.55,-0.82,tcount);
       sprintf(tcount,"%d",NKaons);       text->DrawText(-0.55,-0.87,tcount);
       sprintf(tcount,"%d",NElectrons);   text->DrawText(-0.55,-0.92,tcount);

       sprintf(tcount,"Protons/Pions= %4f",Float_t(NProtons)/Float_t(NPionPlus+NPionMinus));
       text->SetTextAlign(12);
       text->DrawText(-0.45,-0.92,tcount);
       sprintf(tcount,"Kaons/Pions= %4f",Float_t(NKaons)/Float_t(NPionPlus+NPionMinus));
       text->DrawText(0.30,-0.92,tcount);
    }

    //______________________________________________________________________________
     void TGenerator::ExecuteEvent(Int_t event, Int_t px, Int_t py)
    {
    //*-*-*-*-*-*-*-*-*-*-*Execute action corresponding to one event*-*-*-*
    //*-*                  =========================================

       if (gPad->GetView()) {
          gPad->GetView()->ExecuteRotateView(event, px, py);
          return;
       }
    }

    //______________________________________________________________________________
     TParticle *TGenerator::GetParticle(Int_t i) const
    {
    //
    //  Returns pointer to primary number i;
    //

       if (!fParticles) return 0;
       Int_t n = fParticles->GetLast();
       if (i < 0 || i > n) return 0;
       return (TParticle*)fParticles->UncheckedAt(i);
    }

    //______________________________________________________________________________
     void TGenerator::Paint(Option_t *)
    {
    //
    //  Paint one event
    //

    }

    //______________________________________________________________________________
     void TGenerator::SetPtCut(Float_t ptcut)
    {
    //
    //  Set Pt threshold below which primaries are not drawn
    //
       fPtCut = ptcut;
       Draw();
       gPad->Update();
    }

    //______________________________________________________________________________
     void TGenerator::SetViewRadius(Float_t rbox)
    {
    //
    //  Set lower and upper values of the view range
    //
       SetViewRange(-rbox,-rbox,-rbox,rbox,rbox,rbox);
    }

    //______________________________________________________________________________
     void TGenerator::SetViewRange(Float_t xmin, Float_t ymin, Float_t zmin, Float_t xmax, Float_t ymax, Float_t zmax)
    {
    //
    //  Set lower and upper values of the view range
    //
       TView *view = gPad->GetView();
       if (!view) return;
       view->SetRange(xmin,ymin,zmin,xmax,ymax,zmax);

       Draw();
       gPad->Update();
    }

    //______________________________________________________________________________
     void TGenerator::ShowNeutrons(Bool_t show)
    {
    //
    //  Set flag to display or not neutrons
    //
       fShowNeutrons = show;
       Draw();
       gPad->Update();
    }