/*=========================================================================

   Program:   ParaView
   Module:    hdf5Reader.h

   Copyright (c) 2005,2006 Sandia Corporation, Kitware Inc.
   All rights reserved.

   ParaView is a free software; you can redistribute it and/or modify it
   under the terms of the ParaView license version 1.2.

   See License_v1.2.txt for the full ParaView license.
   A copy of this license can be obtained by contacting
   Kitware Inc.
   28 Corporate Drive
   Clifton Park, NY 12065
   USA

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=========================================================================*/

/*-------------------------------------------------------------------------
   Copyright (c) 2022 Verein zur Foerderung der Software openCFS
-------------------------------------------------------------------------*/

/**
 * @class   hdf5Reader
 * @brief   holds a hdf5 based openCFS file and serves logical features to vtkCFSReader
 */

#ifndef HDF5READER_H
#define HDF5READER_H

#include <vector>

#include <vtkSystemIncludes.h>
#include <vtk_hdf5.h>

#include "hdf5Common.h" // same directory

namespace H5CFS
{

/**
 * Class for reading in mesh and simulation data from hdf5 file
 *
 * Class for handling the reading of mesh and simulation data from
 * HDF5 files.
 */
class VTK_EXPORT Hdf5Reader
{
public:
  Hdf5Reader() = default;

  virtual ~Hdf5Reader();

  /**
   * Initialize module
   */
  void LoadFile(const std::string& fileName);

  /**
   * Close H5 file object and the H5 main group
   */
  void CloseFile();

  /**
   * Return dimension of the mesh (2 or 3)
   */
  unsigned int GetDimension() const;

  /**
   * Return the gridOrder (1 for linear)
   */
  unsigned int GetGridOrder() const;

  /**
   * Get all nodal coordinates
   */
  void GetNodeCoordinates(std::vector<std::vector<double>>& coords) const;

  /**
   * Get all element definitions
   */
  void GetElements(
    std::vector<ElemType>& type, std::vector<std::vector<unsigned int>>& connect) const;

  /**
   * Get elements of specific region
   */
  const std::vector<unsigned int>& GetElementsOfRegion(const std::string& regionName);

  /**
   * Get nodes of specific region
   */
  const std::vector<unsigned int>& GetNodesOfRegion(const std::string& regionName);

  /**
   * Get nodes of named node group
   */
  const std::vector<unsigned int>& GetNamedNodes(const std::string& name);

  /**
   * Get elems of named elem group
   */
  const std::vector<unsigned int>& GetNamedElements(const std::string& name);

  /**
   * Get vector with all region names in mesh

   * Returns a vector with the names of regions in the mesh of all
   * dimensions.
   * \note Since the regionIdType is guaranteed to be defined by
   * a number type (unsigned int, unsigned int32), the regionId of an element can
   * be directly used as index to the regions-vector.
   */
  const std::vector<std::string>& GetAllRegionNames() { return RegionNames; }

  /**
   * Returns a vector which contains all names of named nodes.
   */
  const std::vector<std::string>& GetNodeNames() { return NodeNames; }

  /**
   * Returns a vector which contains all names of element groups
   */
  const std::vector<std::string>& GetElementNames() { return ElementNames; }

  /**
   * Get entities (nodes, elements), on which a result is defined on
   */
  const std::vector<unsigned int>& GetEntities(EntityType type, const std::string& name);

  /**
   * Return multisequence steps and their analysis types
   */
  void GetNumberOfMultiSequenceSteps(std::map<unsigned int, AnalysisType>& analysis,
    std::map<unsigned int, unsigned int>& numSteps, bool isHistory = false) const;

  /**
   * Obtain list with result types in each sequence step
   */
  void GetResultTypes(unsigned int sequenceStep, std::vector<std::shared_ptr<ResultInfo>>& infos,
    bool isHistory = false) const;

  /**
   * Return list with time / frequency values and step for a given result
   */
  void GetStepValues(unsigned int sequenceStep, const std::string& infoName,
    std::map<unsigned int, double>& steps, bool isHistory = false) const;

  /**
   * Fill pre-initialized result object with mesh result of specified step
   */
  void GetMeshResult(unsigned int sequenceStep, unsigned int stepNum, Result* result);

  /**
   * Fill pre-initialized result object with history result of specified entity
   * e.g. /Results/History/MultiStep_1/mechTotalEnergy/Regions/mech
   * @param entityId is the region string
   * @param result resultInfo gives name (mechTotalEnergy) and realVal and imaginaryVal are set
   * */
  void GetHistoryResult(
    unsigned int sequenceStep, const std::string& entityId, Result* result) const;

private:
  /**
   * Setup mesh information like regions and named entities
   */
  void ReadMeshStatusInformations();

  /**
   * Main hdf5 file, HDF-C-API object type
   */
  hid_t MainFile = -1;

  /**
   * Root group of main file
   */
  hid_t MainRoot = -1;

  /**
   * Root group for mesh section
   */
  hid_t MeshRoot = -1;

  std::string FileName;

  /**
   * Native directory path to hdf5 file
   */
  std::string BaseDir;

  /**
   * Flag indicating use of external files for mesh results
   */
  bool HasExternalFiles = false;

  std::vector<std::string> RegionNames;

  /**
   * Map with number of dimensions for each region
   * Surface regions have lower dimensions than volume regions.
   */
  std::map<std::string, unsigned int> RegionDims;

  /**
   * Map with element numbers for each region
   */
  std::map<std::string, std::vector<unsigned int>> RegionElems;

  /**
   * Map with node numbers for each region
   */
  std::map<std::string, std::vector<unsigned int>> RegionNodes;

  /**
   * List with names of node groups
   */
  std::vector<std::string> NodeNames;

  /**
   * List with names of element groups
   */
  std::vector<std::string> ElementNames;

  /**
   * Map with element numbers for each named element group
   */
  std::map<std::string, std::vector<unsigned int>> EntityElems;

  /**
   * Map with element numbers for each named element and node group
   */
  std::map<std::string, std::vector<unsigned int>> EntityNodes;

  unsigned int NumNodes = 0;

  unsigned int NumElems = 0;

  std::vector<double> NodeCoords;
}; // end of class

} // end of namespace H5CFS

#endif // HDF5COMMON_H
