//  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
//

//  File   : VISU_MedConvertor.hxx
//  Author : Alexey PETROV
//  Module : VISU
//
#ifndef VISU_MedConvertor_HeaderFile
#define VISU_MedConvertor_HeaderFile

#include "VISUConvertor.hxx"
#include "VISU_Convertor_impl.hxx"
#include "VISU_Structures_impl.hxx"
#include "VISU_PointCoords.hxx"
#include "VISU_MeshValue.hxx"

#include "MED_Wrapper.hxx"
#include "MED_Common.hxx"
#include "MED_Structures.hxx"
#include "MED_GaussUtils.hxx"

#include <boost/thread/mutex.hpp>

namespace VISU
{
  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDCoordHolder: TCoordHolder<MED::PNodeCoord>
  {
    virtual
    const TCoord*
    GetPointer() const
    {
      return &(*myCoord)[0];
    }

    virtual
    TCoord*
    GetPointer()
    {
      return &(*myCoord)[0];
    }
  };


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDGaussCoordHolder: TCoordHolderBase
  {
    MED::PGaussCoord myGaussCoord;

    //! To initilize the instance
    void
    Init(const MED::PGaussCoord& theGaussCoord)
    {
      MED::TInt aNbGauss = theGaussCoord->GetNbGauss();
      MED::TInt aNbElem = theGaussCoord->GetNbElem();
      MED::TInt aDim = theGaussCoord->GetDim();
      MED::TInt aNbCells = aNbElem * aNbGauss;
      TCoordHolderBase::Init(aNbCells, aDim);
      myGaussCoord = theGaussCoord;
    }

    //! Get slice of coordinates for defined node (const version)
    virtual
    TCCoordSlice
    GetCoordSlice(vtkIdType theNodeId) const
    {
      MED::TInt anElemId = theNodeId / myGaussCoord->GetNbGauss();
      MED::TCCoordSliceArr aCoordSliceArr = myGaussCoord->GetCoordSliceArr(anElemId);
      MED::TInt aGaussId = theNodeId % myGaussCoord->GetNbGauss();
      return aCoordSliceArr[aGaussId];
    }

    //! Get slice of coordinates for defined node
    virtual
    TCoordSlice 
    GetCoordSlice(vtkIdType theNodeId)
    {
      MED::TInt anElemId = theNodeId / myGaussCoord->GetNbGauss();
      MED::TCoordSliceArr aCoordSliceArr = myGaussCoord->GetCoordSliceArr(anElemId);
      MED::TInt aGaussId = theNodeId % myGaussCoord->GetNbGauss();
      return aCoordSliceArr[aGaussId];
    }

    virtual
    unsigned char*
    GetValuePtr()
    {
      return myGaussCoord->GetValuePtr();
    }
  };


  //---------------------------------------------------------------
  template<class TValueType>
  struct VISU_CONVERTOR_EXPORT TTMEDMeshValue: TTMeshValueHolder<TValueType, 
                                           MED::SharedPtr<MED::TTMeshValue<MED::TVector<TValueType> > > >
  {
    virtual
    const TValueType*
    GetPointer() const
    {
      return this->myContainer->GetPointer();
    }

    virtual
    TValueType*
    GetPointer()
    {
      return this->myContainer->GetPointer();
    }
  };


  //---------------------------------------------------------------
  typedef std::map<vtkIdType, vtkIdType> TObj2VTKID;

  class TMEDNamedPointCoords: public virtual TNamedPointCoords
  {
    MED::EBooleen myIsElemNum; //!< Keeps whether the numeration exists or not
    MED::PElemNum myElemNum; //!< Keeps objects numeration
    mutable TObj2VTKID myObj2VTKID; //!< Keeps mapping from object number to VTK one

    MED::EVersion myVersion;
    MED::PString myElemNames; //!< Keeps whether the names exists or not
    MED::EBooleen myIsElemNames; //!< Keeps objects names

  public:
    TMEDNamedPointCoords():
      myIsElemNum(MED::eFAUX),
      myIsElemNames(MED::eFAUX)
    {}

    void
    Init(const MED::PNodeInfo& theNodeInfo,
         MED::EVersion theVersion);

    void
    Init(const MED::PGrilleInfo& theGrilleInfo);

    //! Get object number for node by its VTK one
    virtual
    vtkIdType
    GetObjID(vtkIdType theID) const;

    //! Get VTK number for node by its object one
    virtual
    vtkIdType
    GetVTKID(vtkIdType theID) const;

    //! Get name of node by its object number
    virtual
    std::string 
    GetNodeName(vtkIdType theObjID) const;

    //! Gets memory size used by the instance (bytes).
    virtual
    unsigned long int
    GetMemorySize();
  };
  typedef MED::SharedPtr<TMEDNamedPointCoords> PMEDNamedPointCoords;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDMesh: virtual TMeshImpl
  {
    MED::PMeshInfo myMeshInfo;
    MED::TEntityInfo myEntityInfo;
  };
  typedef MED::SharedPtr<TMEDMesh> PMEDMesh;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDSubProfile: virtual TSubProfileImpl
  {
    MED::EGeometrieElement myMGeom;

    TMEDSubProfile():
      myIsElemNum(MED::eFAUX)
    {}

    MED::EBooleen myIsElemNum;
    MED::PElemNum myElemNum;

    virtual 
    vtkIdType 
    GetElemObjID(vtkIdType theID) const;
    
    //! Reimplement the TSubProfileImpl::GetElemVTKID
    virtual 
    vtkIdType 
    GetElemVTKID(vtkIdType theID) const;

    //! Gets memory size used by the instance (bytes).
    virtual
    unsigned long int
    GetMemorySize();
  };
  typedef MED::SharedPtr<TMEDSubProfile> PMEDSubProfile;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDProfile: virtual TProfileImpl
  {};
  typedef MED::SharedPtr<TMEDProfile> PMEDProfile;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDGauss: virtual TGaussImpl
  {
    MED::PGaussInfo myGaussInfo;

    //! To define a way to implement more detail comparision of the TGaussSubMesh instances
    virtual
    void
    LessThan(const PGaussImpl& theGauss,
             bool& theResult) const;
  };
  typedef MED::SharedPtr<TMEDGauss> PMEDGauss;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDGaussSubMesh: virtual TGaussSubMeshImpl
  {
    TMEDGaussSubMesh():
      myIsElemNum(MED::eFAUX)
    {}

    MED::EBooleen myIsElemNum;
    MED::PElemNum myElemNum;

    virtual
    TGaussPointID
    GetObjID(vtkIdType theID) const;
    
    virtual
    vtkIdType
    GetVTKID( const TGaussPointID& theID ) const;  

    //! Gets memory size used by the instance (bytes).
    virtual
    unsigned long int
    GetMemorySize();
  };
  typedef MED::SharedPtr<TMEDGaussSubMesh> PMEDGaussSubMesh;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDGaussMesh: virtual TGaussMeshImpl
  {};
  typedef MED::SharedPtr<TMEDGaussMesh> PMEDGaussMesh;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDSubMesh: virtual TSubMeshImpl
  {
    TMEDSubMesh():
      myIsElemNum(MED::eFAUX),
      myIsElemNames(MED::eFAUX)
    {}

    MED::EBooleen myIsElemNum;
    MED::PElemNum myElemNum;

    MED::EVersion myVersion;
    MED::PString myElemNames;
    MED::EBooleen myIsElemNames;

    void
    Init(const MED::PElemInfo& theElemInfo,
         MED::EVersion theVersion);

    void
    Init(const MED::PGrilleInfo& theGrilleInfo);

    virtual 
    vtkIdType 
    GetElemObjID(vtkIdType theID) const;

    virtual
    std::string 
    GetElemName(vtkIdType theObjID) const;

    //! Gets memory size used by the instance (bytes).
    virtual
    unsigned long int
    GetMemorySize();
  };
  typedef MED::SharedPtr<TMEDSubMesh> PMEDSubMesh;


  //---------------------------------------------------------------
  typedef std::map<vtkIdType,vtkIdType> TFamilyID2CellsSize;

  typedef std::map<vtkIdType,vtkIdType> TElemID2FamilyID;
  typedef std::map<MED::EGeometrieElement,TElemID2FamilyID> TGeom2ElemID2FamilyID;

  struct VISU_CONVERTOR_EXPORT TMEDMeshOnEntity: virtual TMeshOnEntityImpl
  {
    TFamilyID2CellsSize myFamilyID2CellsSize;
    TGeom2ElemID2FamilyID myGeom2ElemID2FamilyID;
    MED::TGeom2Size myGeom2Size;
  };
  typedef MED::SharedPtr<TMEDMeshOnEntity> PMEDMeshOnEntity;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDFamily: virtual TFamilyImpl
  {};
  typedef MED::SharedPtr<TMEDFamily> PMEDFamily;
  

  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDGroup: virtual TGroupImpl
  {};
  typedef MED::SharedPtr<TMEDGroup> PMEDGroup;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDField: virtual TFieldImpl
  {};
  typedef MED::SharedPtr<TMEDField> PMEDField;


  //---------------------------------------------------------------
  struct VISU_CONVERTOR_EXPORT TMEDValForTime: virtual TValForTimeImpl
  {};
  typedef MED::SharedPtr<TMEDValForTime> PMEDValForTime;

}

class VISU_MedConvertor: public VISU_Convertor_impl
{  
  VISU_MedConvertor();
  VISU_MedConvertor(const VISU_MedConvertor&);
  
  bool myIsEntitiesDone;
  bool myIsFieldsDone;
  bool myIsGroupsDone;
  bool myIsMinMaxDone;

public:
  VISU_MedConvertor(const std::string& theFileName, MED::PWrapper theMed);

  virtual
  VISU_Convertor* 
  BuildEntities();

  virtual
  VISU_Convertor* 
  BuildFields();

  virtual
  VISU_Convertor* 
  BuildMinMax();

  virtual
  VISU_Convertor* 
  BuildGroups();

protected:
  MED::PWrapper myMed; // mpv : bug 13568: one med per converter

  virtual
  int
  LoadMeshOnEntity(VISU::PMeshImpl theMesh,
                   VISU::PMeshOnEntityImpl theMeshOnEntity);
  
  virtual
  int
  LoadFamilyOnEntity(VISU::PMeshImpl theMesh,
                     VISU::PMeshOnEntityImpl theMeshOnEntity, 
                     VISU::PFamilyImpl theFamily);

  virtual
  int
  LoadMeshOnGroup(VISU::PMeshImpl theMesh, 
                  const VISU::TFamilySet& theFamilySet);
  
  virtual
  int
  LoadValForTimeOnMesh(VISU::PMeshImpl theMesh, 
                       VISU::PMeshOnEntityImpl theMeshOnEntity, 
                       VISU::PFieldImpl theField, 
                       VISU::PValForTimeImpl theValForTime);
  
  virtual 
  int
  LoadValForTimeOnGaussPts(VISU::PMeshImpl theMesh, 
                           VISU::PMeshOnEntityImpl theMeshOnEntity, 
                           VISU::PFieldImpl theField, 
                           VISU::PValForTimeImpl theValForTime);

  int
  LoadPoints(const MED::PWrapper& theMed,
             const VISU::PMEDMesh theMesh);
  
  int
  LoadPointsOnFamily(const MED::PWrapper& theMed,
                     const VISU::PMEDMesh theMesh, 
                     const VISU::PMEDFamily theFamily);
  
  int
  LoadCellsOnEntity(const MED::PWrapper& theMed,
                    const VISU::PMEDMesh theMesh,
                    const VISU::PMEDMeshOnEntity theMeshOnEntity);
  
  int
  LoadCellsOnFamily(const MED::PWrapper& theMed,
                    const VISU::PMEDMesh theMesh,
                    const VISU::PMEDMeshOnEntity theMeshOnEntity,
                    const VISU::PMEDFamily theFamily);
  
  int
  LoadValForTimeOnMesh(const MED::PWrapper& theMed,
                       VISU::PMEDMesh theMesh,
                       VISU::PMEDMeshOnEntity theMeshOnEntity,
                       VISU::PMEDField theField, 
                       VISU::PMEDValForTime theValForTime);
  
  int
  LoadValForTimeOnGaussPts(const MED::PWrapper& theMed,
                           VISU::PMEDMesh theMesh,
                           VISU::PMEDMeshOnEntity theMeshOnEntity,
                           VISU::PMEDField theField, 
                           VISU::PMEDValForTime theValForTime);
};

#endif
