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

/**\file MeshSetSequence.hpp
 *\author Jason Kraftcheck (kraftche@cae.wisc.edu)
 *\date 2007-04-30
 */

#ifndef MESH_SET_SEQUENCE_HPP
#define MESH_SET_SEQUENCE_HPP

#include "EntitySequence.hpp"
#include "MeshSet.hpp"
#include "SequenceData.hpp"

namespace moab {

class SequenceManager;

class MeshSetSequence : public EntitySequence
{
public:

  MeshSetSequence( EntityHandle start,
                   EntityID count,
                   const unsigned* flags,
                   SequenceData* data );
  
  MeshSetSequence( EntityHandle start,
                   EntityID count,
                   unsigned flags,
                   SequenceData* data );

  MeshSetSequence( EntityHandle start,
                   EntityID count,
                   const unsigned* flags,
                   EntityID sequence_size );
  
  MeshSetSequence( EntityHandle start,
                   EntityID count,
                   unsigned flags,
                   EntityID sequence_size );

  virtual ~MeshSetSequence();

  EntitySequence* split( EntityHandle here );
  
  SequenceData* create_data_subset( EntityHandle, EntityHandle ) const
    { return 0; }
  
  ErrorCode pop_back( EntityID count );
  ErrorCode pop_front( EntityID count );
  ErrorCode push_back( EntityID count, const unsigned* flags );
  ErrorCode push_front( EntityID count, const unsigned* flags );
  
  void get_const_memory_use( unsigned long& bytes_per_entity,
                             unsigned long& size_of_sequence ) const;
  unsigned long get_per_entity_memory_use( EntityHandle first,
                                           EntityHandle last ) const;


  inline MeshSet* get_set( EntityHandle h );
  inline const MeshSet* get_set( EntityHandle h ) const;
  
  ErrorCode get_entities( EntityHandle set, std::vector<EntityHandle>& entities ) const;
  ErrorCode get_entities(  SequenceManager const* seqman, EntityHandle set,                    Range& entities, bool recursive ) const;
  ErrorCode get_dimension( SequenceManager const* seqman, EntityHandle set, int dim,           std::vector<EntityHandle>& entities, bool recursive ) const;
  ErrorCode get_dimension( SequenceManager const* seqman, EntityHandle set, int dim,           Range& entities, bool recursive ) const;
  ErrorCode get_type(      SequenceManager const* seqman, EntityHandle set, EntityType type, std::vector<EntityHandle>& entities, bool recursive ) const;
  ErrorCode get_type(      SequenceManager const* seqman, EntityHandle set, EntityType type, Range& entities, bool recursive ) const;
  
  ErrorCode num_entities(  SequenceManager const* seqman, EntityHandle set,                    int& count, bool recursive ) const;
  ErrorCode num_dimension( SequenceManager const* seqman, EntityHandle set, int dim,           int& count, bool recursive ) const;
  ErrorCode num_type(      SequenceManager const* seqman, EntityHandle set, EntityType type, int& count, bool recursive ) const;

  ErrorCode get_parents       ( SequenceManager const* seqman, EntityHandle of, std::vector<EntityHandle>& parents,  int num_hops ) const;
  ErrorCode get_children      ( SequenceManager const* seqman, EntityHandle of, std::vector<EntityHandle>& children, int num_hops ) const;
  ErrorCode get_contained_sets( SequenceManager const* seqman, EntityHandle of, std::vector<EntityHandle>& contents, int num_hops ) const;
  ErrorCode num_parents       ( SequenceManager const* seqman, EntityHandle of, int& number, int num_hops ) const;
  ErrorCode num_children      ( SequenceManager const* seqman, EntityHandle of, int& number, int num_hops ) const;
  ErrorCode num_contained_sets( SequenceManager const* seqman, EntityHandle of, int& number, int num_hops ) const;
  
private:

  enum SearchType { PARENTS, CHILDREN, CONTAINED };

  MeshSetSequence( MeshSetSequence& split_from, EntityHandle split_at )
    : EntitySequence( split_from, split_at )
    {}

  void initialize( const unsigned* set_flags );
  
  ErrorCode get_parent_child_meshsets( EntityHandle meshset,
                                    SequenceManager const* set_sequences,
                                    std::vector<EntityHandle>& results,
                                    int num_hops, SearchType link_type ) const;
                                    
  static ErrorCode recursive_get_sets( EntityHandle start_set,
                            SequenceManager const* set_sequences,
                            std::vector<const MeshSet*>* sets_out = 0,
                            Range* set_handles_out = 0,
                            std::vector<EntityHandle>* set_handle_vect_out = 0 );
  static ErrorCode recursive_get_sets( EntityHandle start_set,
                            SequenceManager* set_sequences,
                            std::vector<MeshSet*>& sets_out );
  
  enum { SET_SIZE = sizeof(MeshSet) };

  inline const unsigned char* array() const
    { return reinterpret_cast<const unsigned char*>(data()->get_sequence_data(0)); }

  inline unsigned char* array()
    { return reinterpret_cast<unsigned char*>(data()->get_sequence_data(0)); }
    
  inline void allocate_set( unsigned flags, EntityID index )
  {
    unsigned char* const ptr = array() + index * SET_SIZE;
    new (ptr) MeshSet(flags);
  }
    
  inline void deallocate_set( EntityID index ) 
  {
    MeshSet* set = reinterpret_cast<MeshSet*>(array() + SET_SIZE * index );
    set->~MeshSet();
  }
};

inline MeshSet* MeshSetSequence::get_set( EntityHandle h )
{
  return reinterpret_cast<MeshSet*>(array() + SET_SIZE*(h - data()->start_handle()));
}
inline const MeshSet* MeshSetSequence::get_set( EntityHandle h ) const
{
  return reinterpret_cast<const MeshSet*>(array() + SET_SIZE*(h - data()->start_handle()));
}
  
} // namespace moab

#endif
