/**
 * 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 STRUCTURED_ELEMENT_SEQUENCE
#define STRUCTURED_ELEMENT_SEQUENCE

//
// Class: StructuredElementSeq
//
// Purpose: represent a rectangular element of mesh
//
// A ScdElement represents a rectangular element of mesh, including both vertices and
// elements, and the parametric space used to address that element.  Vertex data,
// i.e. coordinates, may not be stored directly in the element, but the element returns
// information about the vertex handles of vertices in the element.  Vertex and element
// handles associated with the element are each contiguous.

#include "moab_export.h"

#include "ElementSequence.hpp"
#include "ScdElementData.hpp"

namespace moab {

class MOAB_EXPORT StructuredElementSeq : public ElementSequence
{
public:

    //! constructor
  StructuredElementSeq(
                EntityHandle start_handle,
                const int imin, const int jmin, const int kmin,
                const int imax, const int jmax, const int kmax,
                int *is_periodic = NULL);
  
  virtual ~StructuredElementSeq();

  ScdElementData* sdata() 
    { return reinterpret_cast<ScdElementData*>(data()); }
  ScdElementData const* sdata() const 
    { return reinterpret_cast<const ScdElementData*>(data()); }

    //! get handle of vertex at i, j, k
  EntityHandle get_vertex(const int i, const int j, const int k) const
    { return get_vertex( HomCoord(i,j,k) ); }
  
    //! get handle of vertex at homogeneous coords
  inline EntityHandle get_vertex(const HomCoord &coords) const
    { return sdata()->get_vertex(coords); }
  
    //! get handle of element at i, j, k
  EntityHandle get_element(const int i, const int j, const int k) const
    { return sdata()->get_element( i, j, k ); }
  
    //! get handle of element at homogeneous coords
  EntityHandle get_element(const HomCoord &coords) const
    { return sdata()->get_element( coords.i(), coords.j(), coords.k() ); }
  
    //! get min params for this element
  const HomCoord &min_params() const
    { return sdata()->min_params(); }
  void min_params(HomCoord &coords) const
    { coords = min_params(); }
  void min_params(int &i, int &j, int &k) const
    { i = min_params().i(); j = min_params().j(); k = min_params().k(); }

    //! get max params for this element
  const HomCoord &max_params() const
    { return sdata()->max_params(); }
  void max_params(HomCoord &coords) const
    { coords = max_params(); }
  void max_params(int &i, int &j, int &k) const
    { i = max_params().i(); j = max_params().j(); k = max_params().k(); }
  
    //! get the number of vertices in each direction, inclusive
  void param_extents(int &di, int &dj, int &dk) const
    { sdata()->param_extents( di, dj, dk ); }

    //! given a handle, get the corresponding parameters
  ErrorCode get_params(const EntityHandle ehandle,
                          int &i, int &j, int &k) const
    { return sdata()->get_params( ehandle, i, j, k ); }
  
    //! convenience functions for parameter extents
  int i_min() const {return min_params().i();}
  int j_min() const {return min_params().j();}
  int k_min() const {return min_params().k();}
  int i_max() const {return max_params().i();}
  int j_max() const {return max_params().j();}
  int k_max() const {return max_params().k();}

    //! test the bounding vertex sequences and determine whether they fully
    //! define the vertices covering this element block's parameter space
  inline bool boundary_complete() const
    { return sdata()->boundary_complete(); }

    //! test whether this sequence contains these parameters
  bool contains(const int i, const int j, const int k) const
    { return sdata()->contains(HomCoord(i,j,k)); }
  inline bool contains(const HomCoord &coords) const
    { return sdata()->contains(coords); }

    //! get connectivity of an entity given entity's parameters
  ErrorCode get_params_connectivity(const int i, const int j, const int k,
                                std::vector<EntityHandle>& connectivity) const
    { return sdata()->get_params_connectivity( i, j, k, connectivity ); }
  
    //! Return whether box is periodic in i
    /** Return whether box is periodic in i
     * \return True if box is periodic in i direction
     */
  int is_periodic_i() const {return sdata()->is_periodic_i();};
  
    //! Return whether box is periodic in j
    /** Return whether box is periodic in j
     * \return True if box is periodic in j direction
     */
  int is_periodic_j() const {return sdata()->is_periodic_j();};
  
    //! Return whether box is periodic in i and j
    /** Return whether box is periodic in i and j
     * \param is_periodic_ij Non-zero if periodic in i [0] or j [1]
     */
  void is_periodic(int is_periodic_ij[2]) const {sdata()->is_periodic(is_periodic_ij);};
  
  
    /***************** Methods from ElementSequence *****************/

  virtual ErrorCode get_connectivity( EntityHandle handle,
                                        std::vector<EntityHandle>& connect,
                                        bool topological = false ) const;
  
  virtual ErrorCode get_connectivity( EntityHandle handle,
                                        EntityHandle const*& connect,
                                        int &connect_length,
                                        bool topological = false,
                                        std::vector<EntityHandle>* storage = 0
                                       ) const;

  virtual ErrorCode set_connectivity( EntityHandle handle,
                                        EntityHandle const* connect,
                                        int connect_length );
  
  virtual EntityHandle* get_connectivity_array();
  
  
    /***************** Methods from EntitySequence *****************/

    /* Replace the ElementSequence implementation of this method with
     * one that always returns zero, because we cannot re-use handles
     * that are within a ScdElementData
     */
  virtual int values_per_entity() const;

  virtual EntitySequence* split( EntityHandle here );

  virtual SequenceData* create_data_subset( EntityHandle start_handle,
                                            EntityHandle end_handle ) const;

  virtual void get_const_memory_use( unsigned long& bytes_per_entity,
                                     unsigned long& size_of_sequence ) const;

protected:
  StructuredElementSeq( StructuredElementSeq& split_from, EntityHandle here )
    : ElementSequence( split_from, here )
    {}
};

} // namespace moab

#endif
