text: // -*- C++ -*-
  //
  // Package:     Core
  // Class  :     FWLegoViewBase
  //
  // Implementation:
  //     <Notes on implementation>
  //
  // Original Author:  Chris Jones
  //         Created:  Thu Feb 21 11:22:41 EST 2008
  //
  
  // system include files
  #include <functional>
  
  #include "TAxis.h"
  #include "TH2.h"
  
  #include "TGLViewer.h"
  #include "TGLLightSet.h"
  #include "TGLPerspectiveCamera.h"
  #include "TGLOrthoCamera.h"
  #include "TEveManager.h"
  #include "TEveElement.h"
  #include "TEveScene.h"
  #include "TEveCalo.h"
  #include "TEveTrans.h"
  #include "TEveScene.h"
  #include "TEveCaloLegoOverlay.h"
  
  // user include files
  #include "Fireworks/Core/interface/FWGLEventHandler.h"
  #include "Fireworks/Core/interface/FWConfiguration.h"
  #include "Fireworks/Core/interface/FWLegoViewBase.h"
  #include "Fireworks/Core/interface/FWViewEnergyScale.h"
  #include "Fireworks/Core/interface/FWViewContext.h"
  #include "Fireworks/Core/interface/CmsShowViewPopup.h"
  #include "Fireworks/Core/interface/fw3dlego_xbins.h"
  
  //
  // constants, enums and typedefs
  //
  
  //
  // static data member definitions
  //
  
  //
  // constructors and destructor
  //
  FWLegoViewBase::FWLegoViewBase(TEveWindowSlot* iParent, FWViewType::EType typeId)
      : FWEveView(iParent, typeId),
        m_lego(nullptr),
        m_overlay(nullptr),
        m_autoRebin(this, "Auto rebin on zoom-out", false),
        m_pixelsPerBin(this, "Pixels per bin", 10., 1., 20.),
        m_projectionMode(this, "Projection", 0l, 0l, 2l),
        m_cell2DMode(this, "Cell2DMode", 1l, 1l, 2l),
        m_drawValuesIn2D(this, "Draw Cell2D threshold (pixels)", 40l, 16l, 1200l),
        m_showOverlay(this, "Draw scales", true) {
    viewerGL()->SetCurrentCamera(TGLViewer::kCameraOrthoXOY);
    viewerGL()->GetLightSet()->SetUseSpecular(false);
  
    m_projectionMode.addEntry(0, "Auto");
    m_projectionMode.addEntry(1, "3D");
    m_projectionMode.addEntry(2, "2D");
  
    m_cell2DMode.addEntry(1, "Plain");
    m_cell2DMode.addEntry(2, "Outline");
    if (typeId == FWViewType::kLegoHF)
      m_cell2DMode.set(2);  // different default for HF view
  
    m_autoRebin.changed_.connect(std::bind(&FWLegoViewBase::setAutoRebin, this));
    m_pixelsPerBin.changed_.connect(std::bind(&FWLegoViewBase::setPixelsPerBin, this));
    m_drawValuesIn2D.changed_.connect(std::bind(&FWLegoViewBase::setFontSizein2D, this));
    m_showOverlay.changed_.connect(std::bind(&FWLegoViewBase::showOverlay, this));
    m_projectionMode.changed_.connect(std::bind(&FWLegoViewBase::setProjectionMode, this));
    m_cell2DMode.changed_.connect(std::bind(&FWLegoViewBase::setCell2DMode, this));
  }
  
  FWLegoViewBase::~FWLegoViewBase() {
    viewerGL()->RemoveOverlayElement(m_overlay);
    m_lego->Destroy();
  }
  
  TEveCaloViz* FWLegoViewBase::getEveCalo() const { return static_cast<TEveCaloViz*>(m_lego); }
  
  void FWLegoViewBase::setContext(const fireworks::Context& ctx) {
    FWEveView::setContext(ctx);
  
    TEveCaloData* data;
    if (typeId() == FWViewType::kLego) {
      data = static_cast<TEveCaloData*>(ctx.getCaloData());
    } else if (typeId() == FWViewType::kLegoHF) {
      data = static_cast<TEveCaloData*>(ctx.getCaloDataHF());
    } else {
      // create empty data locally instead of context
      TEveCaloDataHist* hdata = new TEveCaloDataHist();
      hdata->IncDenyDestroy();
  
      Bool_t status = TH1::AddDirectoryStatus();
      TH1::AddDirectory(kFALSE);  //Keeps histogram from going into memory
      TH2F* dummy =
          new TH2F("background", "background", fw3dlego::xbins_n - 1, fw3dlego::xbins, 72, -1 * TMath::Pi(), TMath::Pi());
  
      TH1::AddDirectory(status);
      Int_t sliceIndex = hdata->AddHistogram(dummy);
      (hdata)->RefSliceInfo(sliceIndex).Setup("background", 0., 0);
      data = hdata;
    }
  
    data->GetEtaBins()->SetNdivisions(710);
    data->GetPhiBins()->SetNdivisions(510);
    data->GetEtaBins()->SetTitleFont(120);
    data->GetEtaBins()->SetTitle("h");
    data->GetPhiBins()->SetTitleFont(120);
    data->GetPhiBins()->SetTitle("f");
    data->GetEtaBins()->SetLabelSize(0.02);
    data->GetEtaBins()->SetTitleSize(0.03);
  
    m_lego = new TEveCaloLego(data);
    m_lego->Set2DMode((TEveCaloLego::E2DMode_e)m_cell2DMode.value());
    m_lego->SetDrawNumberCellPixels(m_drawValuesIn2D.value());
    m_lego->SetAutoRebin(m_autoRebin.value());
    m_lego->SetPixelsPerBin(m_pixelsPerBin.value());
  
    m_lego->InitMainTrans();
    m_lego->RefMainTrans().SetScale(TMath::TwoPi(), TMath::TwoPi(), TMath::Pi());
    m_lego->SetScaleAbs(true);
  
    // set flat in 2D
    m_lego->SetHasFixedHeightIn2DMode(true);
    m_lego->SetFixedHeightValIn2DMode(0.001);
    eventScene()->AddElement(m_lego);
  
    TEveLegoEventHandler* eh = dynamic_cast<TEveLegoEventHandler*>(viewerGL()->GetEventHandler());
    if (eh)
      eh->SetLego(m_lego);
  
    m_overlay = new TEveCaloLegoOverlay();
    m_overlay->SetCaloLego(m_lego);
    m_overlay->SetShowPlane(kFALSE);
    m_overlay->SetScalePosition(0.8, 0.6);
    m_overlay->SetShowScales(true);  //temporary
    viewerGL()->AddOverlayElement(m_overlay);
  }
  
  void FWLegoViewBase::setAutoRebin() {
    m_lego->SetAutoRebin(m_autoRebin.value());
    m_lego->ElementChanged(kTRUE, kTRUE);
  }
  
  void FWLegoViewBase::setPixelsPerBin() {
    m_lego->SetPixelsPerBin((Int_t)(m_pixelsPerBin.value()));
    m_lego->ElementChanged(kTRUE, kTRUE);
  }
  
  void FWLegoViewBase::showOverlay() {
    if (m_overlay)
      m_overlay->SetShowScales(m_showOverlay.value());
    viewerGL()->Changed();
    gEve->Redraw3D();
  }
  
  //_______________________________________________________________________________
  
  void FWLegoViewBase::setFrom(const FWConfiguration& iFrom) {
    FWEveView::setFrom(iFrom);
  
    // cell 2D style
    if (iFrom.version() < 5) {
      const FWConfiguration* value = iFrom.valueForKey("Cell2DMode");
      if (value != nullptr) {
        int mode;
        std::istringstream s(value->value());
        s >> mode;
        m_cell2DMode.set(mode);
      }
    }
  
    // view controller parameters, changed name in version 4
    if (iFrom.version() < 4) {
      bool xb; /* double xd;
        {
           std::istringstream s(iFrom.valueForKey("Lego auto scale")->value());
           s >> xb; m_energyScaleMode.set(xb ? FWEveView::kAutoScale : FWEveView::kFixedScale);
        }
        {
           std::istringstream s(iFrom.valueForKey("Lego scale GeV)")->value());
           s >> xd; m_energyMaxAbsVal.set(xd);
           }*/
      {
        std::istringstream s(iFrom.valueForKey("Show scales")->value());
        s >> xb;
        m_showOverlay.set(xb);
      }
      {
        std::istringstream s(iFrom.valueForKey("Show scales")->value());
        s >> xb;
        m_showOverlay.set(xb);
      }
      {
        std::istringstream s(iFrom.valueForKey("Auto rebin on zoom")->value());
        s >> xb;
        m_autoRebin.set(xb);
      }
    }
  
    //
    // camera restore
  
    if (iFrom.version() > 1) {
      bool topView = true;
      std::string stateName("topView");
      stateName += typeName();
      assert(nullptr != iFrom.valueForKey(stateName));
      std::istringstream s(iFrom.valueForKey(stateName)->value());
      s >> topView;
  
      if (topView) {
        viewerGL()->SetCurrentCamera(TGLViewer::kCameraOrthoXOY);
        TGLOrthoCamera* camera = dynamic_cast<TGLOrthoCamera*>(&(viewerGL()->RefCamera(TGLViewer::kCameraOrthoXOY)));
        setFromOrthoCamera(camera, iFrom);
      } else {
        viewerGL()->SetCurrentCamera(TGLViewer::kCameraPerspXOY);
        TGLPerspectiveCamera* camera =
            dynamic_cast<TGLPerspectiveCamera*>(&(viewerGL()->RefCamera(TGLViewer::kCameraPerspXOY)));
        setFromPerspectiveCamera(camera, typeName(), iFrom);
      }
    } else {
      // reset camera if version not supported
      viewerGL()->ResetCamerasAfterNextUpdate();
    }
  }
  
  void FWLegoViewBase::addTo(FWConfiguration& iTo) const {
    FWEveView::addTo(iTo);
  
    bool topView = viewerGL()->CurrentCamera().IsOrthographic();
    std::ostringstream s;
    s << topView;
    std::string name = "topView";
    iTo.addKeyValue(name + typeName(), FWConfiguration(s.str()));
  
    if (topView) {
      TGLOrthoCamera* camera = dynamic_cast<TGLOrthoCamera*>(&(viewerGL()->RefCamera(TGLViewer::kCameraOrthoXOY)));
      addToOrthoCamera(camera, iTo);
    } else {
      TGLPerspectiveCamera* camera =
          dynamic_cast<TGLPerspectiveCamera*>(&(viewerGL()->RefCamera(TGLViewer::kCameraPerspXOY)));
      addToPerspectiveCamera(camera, typeName(), iTo);
    }
  }
  
  void FWLegoViewBase::setFontSizein2D() {
    m_lego->SetDrawNumberCellPixels(m_drawValuesIn2D.value());
    m_lego->ElementChanged(kTRUE, kTRUE);
  }
  
  void FWLegoViewBase::setProjectionMode() {
    m_lego->SetProjection((TEveCaloLego::EProjection_e)m_projectionMode.value());
    m_lego->ElementChanged();
    viewerGL()->Changed();
    gEve->Redraw3D();
  }
  
  void FWLegoViewBase::setCell2DMode() {
    m_lego->Set2DMode((TEveCaloLego::E2DMode_e)m_cell2DMode.value());
    m_lego->ElementChanged();
    viewerGL()->Changed();
    gEve->Redraw3D();
  }
  
  void FWLegoViewBase::populateController(ViewerParameterGUI& gui) const {
    FWEveView::populateController(gui);
  
    gui.requestTab("Style").separator().addParam(&m_projectionMode).addParam(&m_cell2DMode).addParam(&m_drawValuesIn2D);
  
    gui.requestTab("Scales").separator().addParam(&m_showOverlay);
  
    gui.requestTab("Rebin").addParam(&m_autoRebin).addParam(&m_pixelsPerBin);
  }
  