//  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 CONVERTOR :
//  File   : VISU_Convertor.hxx
//  Author : Alexey PETROV
//  Module : VISU
//
#ifndef VISU_MeshValue_HeaderFile
#define VISU_MeshValue_HeaderFile

/*! 
  \file VISU_MeshValue.hxx
  \brief The file contains declarations for basic interfaces that defines mesh value of mesh elements
*/

#include "VISU_Convertor.hxx"
#include "VISU_ConvertorDef_impl.hxx"

#include "MED_SliceArray.hxx"
#include "MED_Vector.hxx"

namespace VISU
{
  //---------------------------------------------------------------
  //! Define a base class for the container to get access to data assigned to mesh
  class VISU_CONVERTOR_EXPORT TMeshValueBase
  {
  public:
    //! To intitilize the data strucutre
    void
    Init(vtkIdType theNbElem,
         vtkIdType theNbGauss,
         vtkIdType theNbComp);

    //! Gets memory size used by the instance (bytes).
    virtual
    unsigned long int
    GetMemorySize() const = 0;

    //! Gets number of mesh elements where the data assigned to.
    vtkIdType
    GetNbElem() const;

    //! Gets number of components of corresponding MED FIELD.
    vtkIdType
    GetNbComp() const;

    //! Gets number of Gauss Points.
    vtkIdType
    GetNbGauss() const;

    size_t
    size() const;

  protected:
    vtkIdType myNbElem; //!< Defines number of mesh elements where the data assigned to
    vtkIdType myNbComp; //!< Keeps number of components of corresponding MED FIELD
    vtkIdType myNbGauss; //!< Defines number of Gauss Points
    vtkIdType myStep; //!< Internal variable
  };
  typedef MED::SharedPtr<TMeshValueBase> PMeshValue;


  //---------------------------------------------------------------
  //! Define a container to get access to data assigned to mesh
  template<class TValueType>
  class VISU_CONVERTOR_EXPORT TTMeshValue: public virtual TMeshValueBase
  {
  public:
    typedef MED::TSlice<TValueType> TValueSlice;
    typedef MED::TCSlice<TValueType> TCValueSlice;
    
    typedef TVector<TCValueSlice> TCValueSliceArr;
    typedef TVector<TValueSlice> TValueSliceArr;

    virtual
    const TValueType*
    GetPointer() const = 0;

    virtual
    TValueType*
    GetPointer() = 0;

    //! To get assigned values first by Gauss Points and then by components (constant version)
    TCValueSliceArr
    GetGaussValueSliceArr(vtkIdType theElemId) const
    {
      TCValueSliceArr aValueSliceArr(this->myNbGauss);
      vtkIdType anId = theElemId * this->myStep;
      for(vtkIdType aGaussId = 0; aGaussId < this->myNbGauss; aGaussId++){
        aValueSliceArr[aGaussId] =
          TCValueSlice(this->GetPointer(), 
                       this->size(),
                       std::slice(anId, this->myNbComp, 1));
        anId += this->myNbComp;
      }
      return aValueSliceArr;
    }

    //! To get assigned values first by Gauss Points and then by components
    TValueSliceArr 
    GetGaussValueSliceArr(vtkIdType theElemId)
    {
      TValueSliceArr aValueSliceArr(this->myNbGauss);
      vtkIdType anId = theElemId * this->myStep;
      for(vtkIdType aGaussId = 0; aGaussId < this->myNbGauss; aGaussId++){
        aValueSliceArr[aGaussId] =
          TValueSlice(this->GetPointer(), 
                      this->size(),
                      std::slice(anId, this->myNbComp, 1));
        anId += this->myNbComp;
      }
      return aValueSliceArr;
    }

    //! To get assigned values first by components and then by Gauss Points (constant version)
    TCValueSliceArr
    GetCompValueSliceArr(vtkIdType theElemId) const
    {
      TCValueSliceArr aValueSliceArr(this->myNbComp);
      vtkIdType anId = theElemId * this->myStep;
      for(vtkIdType aCompId = 0; aCompId < this->myNbComp; aCompId++){
        aValueSliceArr[aCompId] =
          TCValueSlice(this->GetPointer(), 
                       this->size(),
                       std::slice(anId, this->myNbGauss, this->myNbComp));
        anId += 1;
      }
      return aValueSliceArr;
    }

    //! To get assigned values first by components and then by Gauss Points
    TValueSliceArr 
    GetCompValueSliceArr(vtkIdType theElemId)
    {
      TValueSliceArr aValueSliceArr(this->myNbComp);
      vtkIdType anId = theElemId * this->myStep;
      for(vtkIdType aCompId = 0; aCompId < this->myNbComp; aCompId++){
        aValueSliceArr[aCompId] =
          TValueSlice(this->GetPointer(), 
                      this->size(),
                      std::slice(anId, this->myNbGauss, this->myNbComp));
        anId += 1;
      }
      return aValueSliceArr;
    }

    //! Gets memory size used by the instance (bytes).
    virtual
    unsigned long int
    GetMemorySize() const
    {
      return this->size() * sizeof(TValueType);
    }
  };
  

  //---------------------------------------------------------------
  //! Define a container to get access to data assigned to mesh
  template<class TValueType, class TContainerType>
  class TTMeshValueHolder: public virtual TTMeshValue<TValueType>
  {
  public:
    //! To initilize the class instance
    void
    Init(vtkIdType theNbElem,
         vtkIdType theNbGauss,
         vtkIdType theNbComp,
         const TContainerType& theContainer)
    {
      TMeshValueBase::Init(theNbElem, theNbGauss, theNbComp);
      myContainer = theContainer;
    }

  protected:
    mutable TContainerType myContainer; //!< Keeps the mesh values container itself
  };


  //---------------------------------------------------------------
  // Initilize corresponding vtkDataSetAttributes for TValForTime
  void 
  GetTimeStampOnProfile(const PUnstructuredGrid& theSource,
                        const PFieldImpl& theField, 
                        const PValForTimeImpl& theValForTime,
                        const VISU::TEntity& theEntity);


  //---------------------------------------------------------------
  // Initilize corresponding vtkDataSetAttributes for TValForTime
  void 
  GetTimeStampOnGaussMesh(const PPolyData& theSource,
                          const PFieldImpl& theField, 
                          const PValForTimeImpl& theValForTime);

  void 
  InitMed2VisuArray(std::vector<int>& anArray, EGeometry aEGeom);


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

#endif
