//  Copyright (C) 2007-2010  CEA/DEN, EDF R&D, OPEN CASCADE
//
//  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
//  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
//
//  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//

//  VISU VISUGUI : GUI of VISU component
//  File   : VisuGUI_Module.h
//  Author : 
//  Module : VISU
//
#ifndef VisuGUI_Prs3dTools_HeaderFile
#define VisuGUI_Prs3dTools_HeaderFile

#include "VISUConfig.hh"
#include "VisuGUI_Tools.h"
#include "VisuGUI_ViewTools.h"
#include "VISU_ColoredPrs3dFactory.hh"
#include "VISU_PipeLine.hxx"
#include "VisuGUI_DialogRunner.h"

#include <SUIT_Desktop.h>
#include <SUIT_ResourceMgr.h>

#include <SPlot2d_ViewWindow.h>

#include <vtkRenderer.h>

namespace VISU
{
  //---------------------------------------------------------------
  template<class TPrs3d_i, class TViewer, class TDlg, int TIsDlgModal>
  void
  EditPrs3d(VisuGUI* theModule, 
            Handle(SALOME_InteractiveObject)& theIO,
            VISU::Prs3d_i* thePrs3d,
            SVTK_ViewWindow* theViewWindow)
  {
    if (TPrs3d_i* aPrs3d = dynamic_cast<TPrs3d_i*>(thePrs3d)) {
      bool isModal = TIsDlgModal;
      if( ColoredPrs3d_i* aColoredPrs3d = dynamic_cast<ColoredPrs3d_i*>(aPrs3d) )
        if( !aColoredPrs3d->IsTimeStampFixed() )
          isModal = 0;

      TDlg* aDlg = new TDlg (theModule);
      aDlg->initFromPrsObject(aPrs3d, true);
      if (runAndWait(aDlg,isModal)) {
        if (!(aDlg->storeToPrsObject(aPrs3d))) {
          delete aDlg;
          return;
        }
        try {
          aPrs3d->UpdateActors();
        } catch (std::runtime_error& exc) {
          aPrs3d->RemoveActors();

          INFOS(exc.what());
          SUIT_MessageBox::warning
            (GetDesktop(theModule), QObject::tr("WRN_VISU"),
             QObject::tr("ERR_CANT_BUILD_PRESENTATION") + ": " + QObject::tr(exc.what()) );
        }
        if (theViewWindow) {
          theViewWindow->getRenderer()->ResetCameraClippingRange();
          theViewWindow->Repaint();
        }
        // Optionally, create table and curves for cut lines
        QApplication::setOverrideCursor(Qt::WaitCursor);
        CreateCurves( theModule,
                      dynamic_cast<VISU::CutLinesBase_i*>( aPrs3d ),
                      aDlg,
                      false ); // in edition mode
        QApplication::restoreOverrideCursor();
      }
      delete aDlg;
    }
  }


  //----------------------------------------------------------------------------
  template<class TPrs3d_i, class TDlg, int TIsDlgModal>
  void
  EditPrs3d(VisuGUI* theModule,
            Handle(SALOME_InteractiveObject)& theIO,
            VISU::Prs3d_i* thePrs3d,
            SVTK_ViewWindow* theViewWindow = NULL)
  {
    SVTK_ViewWindow* aViewWindow = theViewWindow;
    if (!aViewWindow)
      // Create SVTK_ViewWindow, if it does not exist
      aViewWindow = GetViewWindow<SVTK_Viewer>(theModule);
    if (aViewWindow) {
      EditPrs3d<TPrs3d_i,SVTK_Viewer,TDlg,TIsDlgModal>(theModule, theIO, thePrs3d, aViewWindow);
    }
  }


  //---------------------------------------------------------------
  template<class TPrs3d_i>
  TPrs3d_i*
  CreatePrs3dFromFactory(VisuGUI* theModule,
                         _PTR(SObject) theTimeStamp,
                         const char* theMeshName,
                         VISU::Entity theEntity,
                         const char* theFieldName,
                         int theTimeId,
                         ColoredPrs3d_i::EPublishInStudyMode thePublishInStudyMode)
  {
    VISU::Result_var aResult;
    if (CheckResult(theModule, theTimeStamp, aResult)){
      QApplication::setOverrideCursor(Qt::WaitCursor);
      TPrs3d_i* aPrs3d = NULL;
      if(thePublishInStudyMode == VISU::ColoredPrs3d_i::EPublishUnderTimeStamp)
        aPrs3d = VISU::CreatePrs3d<TPrs3d_i>(aResult,
                                             theMeshName,
                                             theEntity,
                                             theFieldName,
                                             theTimeId);
      else
      {
        CORBA::Float anUsedMemory = 0.0;
        CORBA::Float aRequiredMemory = 0.0;
        VISU::ColoredPrs3dCache::EnlargeType anEnlargeType = 
          VISU::GetRequiredCacheMemory<TPrs3d_i>(aResult,
                                                 theMeshName,
                                                 theEntity,
                                                 theFieldName,
                                                 theTimeId,
                                                 anUsedMemory,
                                                 aRequiredMemory);

        if( anEnlargeType == VISU::ColoredPrs3dCache::IMPOSSIBLE )
        {
          size_t aMb = 1024 * 1024;
          double aFreeMemory = double(VISU_PipeLine::GetAvailableMemory(8192*aMb)) / double(aMb);

          CORBA::Float aNecessaryMemory = aRequiredMemory - aFreeMemory - anUsedMemory;
          SUIT_MessageBox::warning(GetDesktop(theModule),
                                   QObject::tr("WRN_VISU"),
                                   QObject::tr("ERR_NO_MEMORY_TO_BUILD").arg(aNecessaryMemory) );
          QApplication::restoreOverrideCursor();
          return NULL;
        }
        else
        {
          if( anEnlargeType == VISU::ColoredPrs3dCache::ENLARGE )
          {
            if(SUIT_MessageBox::information(GetDesktop(theModule),
                                      QObject::tr("WRN_VISU"),
                                      QObject::tr("WRN_EXTRA_MEMORY_REQUIRED").arg(aRequiredMemory),
                                      QObject::tr("&OK"), QObject::tr("&Cancel"),
                                      0, 1) == 1)
            {
              QApplication::restoreOverrideCursor();
              return NULL;
            }
          }
          aPrs3d = VISU::CreateHolder2GetDeviceByType<TPrs3d_i>(aResult,
                                                                theMeshName,
                                                                theEntity,
                                                                theFieldName,
                                                                theTimeId,
                                                                anEnlargeType,
                                                                aRequiredMemory);
        }
      }
      
      QApplication::restoreOverrideCursor();
      if(aPrs3d)
        return aPrs3d;
    }
    SUIT_MessageBox::warning(GetDesktop(theModule),
                             QObject::tr("WRN_VISU"),
                             QObject::tr("ERR_CANT_BUILD_PRESENTATION") );

    return NULL;
  }


  //---------------------------------------------------------------
  template<class TPrs3d_i, class TViewer, class TDlg, int IsDlgModal>
  TPrs3d_i*
  CreateAndEditPrs3d(VisuGUI* theModule,
                     _PTR(SObject) theTimeStamp,
                     ColoredPrs3d_i::EPublishInStudyMode thePublishInStudyMode)
  {
    Storable::TRestoringMap aRestoringMap = Storable::GetStorableMap(theTimeStamp);
    VISU::VISUType aType = VISU::Storable::RestoringMap2Type(aRestoringMap);
    if ( aType != TTIMESTAMP )
      return NULL;

    QString aMeshName = aRestoringMap["myMeshName"];
    QString anEntity = aRestoringMap["myEntityId"];
    QString aFieldName = aRestoringMap["myFieldName"];
    QString aTimeStampId = aRestoringMap["myTimeStampId"];

    // Create new TViewWindow instance, if it does not exist.
    typedef typename TViewer::TViewWindow TViewWindow;
    TViewWindow* aViewWindow = GetViewWindow<TViewer>(theModule);

    // Define free position for scalar bar.
    int aPos = GetFreePositionOfDefaultScalarBar(theModule, aViewWindow);
    GetResourceMgr()->setValue("VISU", "scalar_bar_position_num", aPos);

    QApplication::setOverrideCursor(Qt::WaitCursor);

    TPrs3d_i* aPrs3d =
      CreatePrs3dFromFactory<TPrs3d_i>(theModule,
                                       theTimeStamp,
                                       (const char*)aMeshName.toLatin1(),
                                       (Entity)anEntity.toInt(),
                                       (const char*)aFieldName.toLatin1(),
                                       aTimeStampId.toInt(),
                                       thePublishInStudyMode);
    
    QApplication::restoreOverrideCursor();
    if (aPrs3d) {
      SUIT_ResourceMgr* aResourceMgr = GetResourceMgr();
      int aValue = aResourceMgr->integerValue("VISU","BuildDefaultPrs3d",0);
      if(aResourceMgr->booleanValue("VISU","display_only",false)){
          theModule->OnEraseAll();
        }
      
      if (!aValue) {
        if (TDlg* aDlg = new TDlg(theModule)) { // dialog box in creation mode
          aDlg->initFromPrsObject(aPrs3d, true);
          if (runAndWait(aDlg,IsDlgModal) && (aDlg->storeToPrsObject(aPrs3d))) {
            if(aResourceMgr->booleanValue("VISU","display_only",false)){
              if(SPlot2d_Viewer* aPlot2d = GetPlot2dViewer(theModule, false)) aPlot2d->EraseAll();
            } 
            // Optionally, create table and curves for cut lines
            QApplication::setOverrideCursor(Qt::WaitCursor);
            CreateCurves( theModule,
                          dynamic_cast<VISU::CutLinesBase_i*>( aPrs3d ),
                          aDlg,
                          true ); // in creation mode
            UpdateObjBrowser(theModule,true,theTimeStamp);
            QApplication::restoreOverrideCursor();
            delete aDlg;
          } else {
            if ( theModule->application() )
              DeletePrs3d(theModule,aPrs3d);
            QApplication::restoreOverrideCursor();
            delete aDlg;
            return NULL;
          }
        }
      }
      // aViewWindow = GetViewWindow<TViewer>(theModule); IPAL 20125 dmv
      // Display created presentation.
      if (aViewWindow) {
        PublishInView(theModule, aPrs3d, aViewWindow);
        if(GetResourceMgr()->booleanValue("VISU","automatic_fit_all",false)){
          aViewWindow->onFitAll();
        }

        AddScalarBarPosition(theModule, aViewWindow, aPrs3d, aPos);
      }

      return aPrs3d;
    }

    return NULL;
  }


  //---------------------------------------------------------------
  template<class TPrs3d_i, class TViewer, class TDlg, int IsDlgModal>
  TPrs3d_i*
  CreatePrs3dInViewer(VisuGUI* theModule,
                      _PTR(SObject) theTimeStampSObj,
                      ColoredPrs3d_i::EPublishInStudyMode thePublishInStudyMode)
  {
    TPrs3d_i* aPrs = 0;
    // Create new TViewWindow instance, if it does not exist.
    typedef typename TViewer::TViewWindow TViewWindow;
    if (!GetViewWindow<TViewer>(theModule))
      return aPrs;

    aPrs = CreateAndEditPrs3d<TPrs3d_i,TViewer,TDlg,IsDlgModal>
              (theModule,theTimeStampSObj,thePublishInStudyMode);

    theModule->application()->putInfo(QObject::tr("INF_DONE"));
    return aPrs;
  }


  //----------------------------------------------------------------------------
  template<class TPrs3d_i, class TDlg, int IsDlgModal>
  TPrs3d_i*
  CreatePrs3d(VisuGUI* theModule,
              const QString& theDesiredViewerType = QString())
  {
    TPrs3d_i* aPrs = 0;
    if (CheckLock(GetCStudy(GetAppStudy(theModule)),GetDesktop(theModule)))
      return aPrs;

    _PTR(SObject) aTimeStampSObj;
    Handle(SALOME_InteractiveObject) anIO;
    ColoredPrs3d_i::EPublishInStudyMode aPublishInStudyMode;
    if (!CheckTimeStamp(theModule,aTimeStampSObj,anIO,aPublishInStudyMode))
      return aPrs;

    if(/*aPublishInStudyMode == */VISU::ColoredPrs3d_i::EPublishIndependently){
      //      CreatePrs3dInViewer<TPrs3d_i,VVTK_Viewer,TDlg,0>
      //        (theModule,aTimeStampSObj,aPublishInStudyMode);
      aPrs = CreatePrs3dInViewer<TPrs3d_i,SVTK_Viewer,TDlg,0>
                (theModule,aTimeStampSObj,aPublishInStudyMode);
      return aPrs;
    }else{
      if(theDesiredViewerType.isNull()){
        if (/*SUIT_ViewManager* aViewManager = */theModule->getApp()->activeViewManager())
          /*if (aViewManager->getType() == VVTK_Viewer::Type()){ 
            aPrs = CreatePrs3dInViewer<TPrs3d_i,VVTK_Viewer,TDlg,IsDlgModal>
                      (theModule,aTimeStampSObj,aPublishInStudyMode);
            return aPrs;
            }*/
        aPrs = CreatePrs3dInViewer<TPrs3d_i,SVTK_Viewer,TDlg,IsDlgModal>
                   (theModule,aTimeStampSObj,aPublishInStudyMode);
      }else{
        /*if(theDesiredViewerType == VVTK_Viewer::Type()) {
          aPrs = CreatePrs3dInViewer<TPrs3d_i,VVTK_Viewer,TDlg,IsDlgModal>
                     (theModule,aTimeStampSObj,aPublishInStudyMode);
                     } else {*/
          aPrs = CreatePrs3dInViewer<TPrs3d_i,SVTK_Viewer,TDlg,IsDlgModal>
                     (theModule,aTimeStampSObj,aPublishInStudyMode);
          //}
      }
    }
    return aPrs;
  }


  //----------------------------------------------------------------------------
  template<typename TInterface> 
  typename TInterface::_var_type
  GetInterface(CORBA::Object_ptr theObject)
  {
    if(!CORBA::is_nil(theObject))
      return TInterface::_narrow(theObject);
    return TInterface::_nil();
  }
  

  //----------------------------------------------------------------------------
  template<typename TServant> 
  TServant*
  GetServantInterface(CORBA::Object_ptr theObject)
  {
    if(!CORBA::is_nil(theObject)){
      PortableServer::ServantBase_var aServant = GetServant(theObject);
      return dynamic_cast<TServant*>(aServant.in());
    }
    return NULL;
  }
  

  //----------------------------------------------------------------------------
}

#endif
