/**
 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
 * storing and accessing finite element mesh data.
 * 
 * Copyright 2004 Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
 * retains certain rights in this software.
 * 
 * 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, or (at your option) any later version.
 * 
 */

#ifndef EXOII_UTIL
#define EXOII_UTIL

//
// ExoIIUtil class: utility class for functions used by both reader
// and writer

#ifndef IS_BUILDING_MB
#error "ExoIIUtil.hpp isn't supposed to be included into an application"
#endif

#include "moab_export.h"

#include "moab/Forward.hpp"
#include "moab/ExoIIInterface.hpp"


namespace moab {

class MOAB_EXPORT ExoIIUtil : public ExoIIInterface
{

  Interface* mMB;

public:
  ExoIIUtil(Interface* mdb) : mMB(mdb) {}
  ~ExoIIUtil(){}

  //! given the element name, return the type
  virtual ExoIIElementType element_name_to_type(const char* name)
  {
    return static_element_name_to_type(name);
  }

  //! get the element type of the entity; this entity can either be a meshset, 
  //! in which case it will be assumed to be a material set meshset, or an 
  //! individual entity.
  virtual  ExoIIElementType get_element_type(EntityHandle entity,
                                             Tag mid_nodes_tag, Tag geom_dimension_tag, 
                                             EntityType indiv_entity_type = MBMAXTYPE)
  {
    return static_get_element_type(mMB, entity, mid_nodes_tag, geom_dimension_tag,
                                   indiv_entity_type);    
  }

  virtual void has_mid_nodes(ExoIIElementType elem_type, int* array)
  {
    array[0] = HasMidNodes[elem_type][0]; 
    array[1] = HasMidNodes[elem_type][1]; 
    array[2] = HasMidNodes[elem_type][2]; 
    array[3] = HasMidNodes[elem_type][3]; 
  }

  virtual int has_mid_nodes(ExoIIElementType elem_type, int dimension )
  {
    return HasMidNodes[elem_type][dimension];
  }

  virtual int geometric_dimension(const ExoIIElementType elem_type) 
  {
    return ElementGeometricDimension[elem_type];
  }
  
  virtual const char* element_type_name(ExoIIElementType type)
  {
    return ElementTypeNames[type];
  }


  
//! given the element name, return the type
  static ExoIIElementType static_element_name_to_type(const char *name);

//! get the element type of the entity; this entity can either be a meshset, in which
//! case it will be assumed to be a material set meshset, or an individual entity.  If a
//! meshset, and indiv_entity_type is input, that type is used to start the search for
//! the connectivity tag which determines how many vertices per entity are defined for that meshset
  static ExoIIElementType static_get_element_type(Interface *mdbImpl,
                                           const EntityHandle entity,
                                           const Tag mid_nodes_tag,
                                           const Tag geom_dimension_tag,
                                           const EntityType indiv_entity_type = MBMAXTYPE);

//! given the number of vertices in an entity, and optionally the entity type and
//! geometric dimension, return the corresponding exodusII element type; dimension defaults
//! to 3 following TSTT convention
  static ExoIIElementType get_element_type_from_num_verts(const int num_verts, 
                                                          const EntityType entity_type = MBMAXTYPE,
                                                          const int dimension = 3);

//! the MB entity type used for each element type
  static const EntityType ExoIIElementMBEntity[];

//! names for all the element types that MB ExoII reader supports
  static const char* ElementTypeNames[];

//! number of vertices per element
  static const int VerticesPerElement[];

//! HasMidNode[elem_type][dim] = 1 denotes that elem_type has mid-nodes
//! on sub-entities of dimension dim
  static const int HasMidNodes[][4];

//! geometric dimension of each element
  static const int ElementGeometricDimension[];

};

//! postfix increment operator for EntityType
inline ExoIIElementType operator++(ExoIIElementType &type, int)
{
  return (ExoIIElementType)(((int&)type)++);
}  

//! prefix increment operator for EntityType
inline ExoIIElementType& operator++(ExoIIElementType& type)
{
  return (ExoIIElementType&)(++((int&)type));
}

} // namespace moab

#endif
