//-------------------------------------------------------------------------
// Filename      : WriteDamsel.hpp
//
// Purpose       : ExodusII writer
//
// Special Notes : Lots of code taken from verde implementation
//
// Creator       : Corey Ernst
//
// Date          : 8/02
//
// Owner         : Corey Ernst
//-------------------------------------------------------------------------

#ifndef WRITEDAMSEL_HPP
#define WRITEDAMSEL_HPP

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

#include <vector>
#include <string>

#include "moab/Interface.hpp"
#include "moab/Range.hpp"
#include "moab/WriterIface.hpp"
#include "RangeSeqIntersectIter.hpp"
#include "moab/FileOptions.hpp"
#include "DamselUtil.hpp"

#include "damsel.h"

namespace moab
{

class WriteUtilIface;
class SequenceManager;
class Error;

class WriteDamsel : public WriterIface
{
  public:
    //! Factory function, for ReaderWriter
    static WriterIface* factory( Interface* iface );

    //! Constructor
    WriteDamsel( Interface* impl );

    //! Destructor
    virtual ~WriteDamsel();

    //! Primary interface function
    //! \param file_name Filename being written
    //! \param overwrite If true and the file exists, an error is returned
    //! \param opts File options, e.g. whether and how to write in parallel
    //! \param meshset_list If non-NULL, a vector of sets defining what is to be written
    //! \param num_sets The number of sets to be written, only used if meshset_list is non-NULL
    //! \param qa_records Strings defining provenance information
    //! \param tag_list If non-NULL, only these tags should be written
    //! \param num_tags The number of tag handles in tag_list, used only if tag_list is non-NULL
    //! \param requested_output_dimension Dimension used for coordinates
    ErrorCode write_file( const char* file_name, const bool /* overwrite */, const FileOptions& opts,
                          const EntityHandle* meshset_list, const int num_sets,
                          const std::vector< std::string >& /* qa_records */, const Tag* /* tag_list */ = NULL,
                          int /* num_tags */ = 0, int /* requested_output_dimension */ = 3 );

    enum
    {
        DAMSEL_IS_TRACKING = 0x1
    } DAMSEL_FLAGS;

  private:
    //! Initialize global information about dense/sparse/conventional tags, once for entire
    //! write_file call
    ErrorCode init_tag_info();

    //! Write a subrange of entities/sets; just a wrapper to write_[vertices, entities, sets]
    ErrorCode write_subrange( RangeSeqIntersectIter& rsi );

    //! Write the vertices in the model, for the handles in the specified RangeSeqIntersectIter
    //! \param rsi Range sequence iterator defining range of entities/sets to be written
    ErrorCode write_vertices( RangeSeqIntersectIter& rsi );

    //! Write the entities in the model, for the handles in the specified RangeSeqIntersectIter
    //! \param rsi Range sequence iterator defining range of entities/sets to be written
    ErrorCode write_entities( RangeSeqIntersectIter& rsi );

    //! Write the sets in the model, for the handles in the specified RangeSeqIntersectIter
    //! \param rsi Range sequence iterator defining range of entities/sets to be written
    ErrorCode write_sets( RangeSeqIntersectIter& rsi );

    //! Map dense tags for the specified entities, using the specified damsel entity container
    ErrorCode map_dense_tags( RangeSeqIntersectIter& rsi, damsel_container& ent_cont );

    //! Map sparse tags for all entities
    ErrorCode map_sparse_tags();

    //! Interface instance
    Interface* mbImpl;

    //! WriteUtil object used in this writer
    WriteUtilIface* mWriteIface;

    //! Used to initialize the RangeSeqIntersectIter
    SequenceManager* sequenceManager;

    //! File name
    std::string fileName;

    //! Utility for storing damsel-specific stuff
    DamselUtil dU;
};

inline ErrorCode WriteDamsel::write_subrange( RangeSeqIntersectIter& rsi )
{
    ErrorCode rval = MB_SUCCESS;

    if( MBVERTEX == mbImpl->type_from_handle( rsi.get_start_handle() ) )
        rval = write_vertices( rsi );
    else if( MBENTITYSET > mbImpl->type_from_handle( rsi.get_start_handle() ) )
        rval = write_entities( rsi );
    // else
    //  rval = write_sets(rsi);

    return rval;
}

}  // namespace moab

#endif
