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

//-------------------------------------------------------------------------
// Filename      : ReadNCDF.hpp
//
// Purpose       : ExodusII reader
//
// Special Notes : Lots of code taken from verde implementation
//
// Creator       : Tim Tautges & Corey Ernst
//
// Date          : 3/02
//
// Owner         : Tim Tautges & Corey Ernst
//-------------------------------------------------------------------------

#ifndef READNCDF_HPP
#define READNCDF_HPP

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

#include "moab_export.h"

#include <vector>
#include <string>

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

namespace moab {

class ReadUtilIface;

struct ReadBlockData
{
  int blockId;
  int startExoId; 
  EntityHandle startMBId; 
  int numElements;
  bool reading_in;
  ExoIIElementType elemType;
};

//! Output Exodus File for VERDE
class MOAB_EXPORT ReadNCDF : public ReaderIface
{
   
public:
  
  static ReaderIface* factory( Interface* );
  
  void tokenize( const std::string& str,
                 std::vector<std::string>& tokens,
                 const char* delimiters );

    //! load an ExoII file
  ErrorCode load_file( const char* file_name,
                       const EntityHandle* file_set,
                       const FileOptions& opts,
                       const SubsetList* subset_list = 0,
                       const Tag* file_id_tag = 0 );

  ErrorCode read_tag_values( const char* file_name,
                             const char* tag_name,
                             const FileOptions& opts,
                             std::vector<int>& tag_values_out,
                             const SubsetList* subset_list = 0 );
  
   //! Constructor
   ReadNCDF(Interface* impl = NULL);

   //! Destructor
  virtual ~ReadNCDF();

  //update the coords for deformed mesh according to FileOptions
  ErrorCode update(const char *exodus_file_name, const FileOptions& opts,
                     const int num_blocks, const int *blocks_to_load,
                     const EntityHandle file_set );

private:

  ReadUtilIface* readMeshIface;

  bool dimension_exists(const char *attrib_name);
  
  void reset();

    //! read the header from the ExoII file
  ErrorCode read_exodus_header();
  
    //! read the nodes
  ErrorCode read_nodes(const Tag* file_id_tag);
  
    //! read block headers, containing info about element type, number, etc.
  ErrorCode read_block_headers(const int *blocks_to_load,
                                  const int num_blocks);
  
    //! read the element blocks
  ErrorCode read_elements(const Tag* file_id_tag);
  
    //! read in the global element ids
  ErrorCode read_global_ids();

    //! read the nodesets into meshsets
  ErrorCode read_nodesets();
  
    //! read the sidesets (does nothing for now)
  ErrorCode read_sidesets();

    //! exodus file bound to this object
  int exodus_file();

    //! number of dimensions in this exo file
  int number_dimensions();

  //! map a character exodusII element type to a TSTT type & topology
  ErrorCode get_type(char *exo_element_type,
                        EntityType &elem_type);
 
  ErrorCode get_type(EntityType &elem_type,
                        std::string &exo_element_type);

  /* 
  int get_int_tag(const MB_MeshSet *this_ms,
                  const TagHandle tag_id);
 */

  //qa record stuff 
  ErrorCode read_qa_records(EntityHandle file_set);
  ErrorCode read_qa_information( std::vector<std::string> &qa_record_list);

  ErrorCode read_qa_string(char *string,
                              int record_number,
                              int record_position); 

  ErrorCode create_ss_elements( int *element_ids, int *side_list,
                                   int num_sides, int num_dist_factors,
                                   std::vector<EntityHandle> &entities_to_add,
                                   std::vector<EntityHandle> &reverse_entities,
                                   std::vector<double> &dist_factor_vector,
                                   int ss_seq_id);

  ErrorCode find_side_element_type( const int element_id, ExoIIElementType &type, 
                                       ReadBlockData &block_data, int &df_index, int side_id );
  
 /* ErrorCode assign_block_ids_to_ssets(EntityHandle ss_handle,
                                         MB_MeshSet *ss_mesh_set);
                                         */

  //! creates an element with the given connectivity
  ErrorCode create_sideset_element( const std::vector<EntityHandle>&, EntityType, EntityHandle&, int&);

  int get_number_nodes( EntityHandle handle );



  //------------member variables ------------//

    //! interface instance
  Interface* mdbImpl;
  
  int ncFile;        // netcdf/exodus file

  int CPU_WORD_SIZE;
  int IO_WORD_SIZE;

    //! int to offset vertex ids with
  int vertexOffset;

    //! file name
  std::string exodusFile;

    //! number of nodes in the current exoII file
  int numberNodes_loading;

    //! number of elements in the current exoII file
  int numberElements_loading;

    //! number of blocks in the current exoII file
  int numberElementBlocks_loading; 

    //! number of nodesets in the current exoII file
  int numberNodeSets_loading; 

    //! number of sidesets in the current exoII file
  int numberSideSets_loading; 

  int numberDimensions_loading;

    //! Meshset Handle for the mesh that is currently being read
  EntityHandle mCurrentMeshHandle;

  //keeps track of the exodus ids of the elements and nodes just loaded
  std::vector<char> nodesInLoadedBlocks;
  //note- vector<bool> has limited capabilities

  //vector of blocks that are loading 
  std::vector< ReadBlockData > blocksLoading;

  //! Cached tags for reading.  Note that all these tags are defined when the
  //! core is initialized.
  Tag mMaterialSetTag;
  Tag mDirichletSetTag;
  Tag mNeumannSetTag;
  Tag mHasMidNodesTag;
  Tag mDistFactorTag;
  Tag mGlobalIdTag;
  Tag mQaRecordTag;

  int max_line_length, max_str_length;

    //! range of entities in initial mesh, before this read
  Range initRange;
};

// inline functions
inline int ReadNCDF::number_dimensions() 
{
   return numberDimensions_loading;
}

} // namespace moab

#endif




