text: /**
   *  \file   BoundaryCellInfo.h
   *  \date   Jul 10, 2013
   *  \author "James C. Sutherland"
   *
   *
   * The MIT License
   *
   * Copyright (c) 2014-2017 The University of Utah
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to
   * deal in the Software without restriction, including without limitation the
   * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   * sell copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   * IN THE SOFTWARE.
   *
   */
  
  #ifndef SpatialOps_BOUNDARYCELLINFO_H_
  #define SpatialOps_BOUNDARYCELLINFO_H_
  
  #include <spatialops/SpatialOpsDefs.h>
  #include <spatialops/structured/IntVec.h>
  
  namespace SpatialOps {
  
    /**
     *  \class  BoundaryCellInfo
     *  \date   Jul 10, 2013
     *  \author "James C. Sutherland"
     *
     *  \brief Provides information about boundary cells for various fields.
     */
    class BoundaryCellInfo
    {
      IntVec minus_, plus_;
      IntVec nExtra_;
  
      /**
       * Construct a BoundaryCellInfo.  This is private to disallow direct construction.
       * @param bcm true if a physical boundary is present on the (-) faces
       * @param bcp true if a physical boundary is present on the (+) face
       * @param nExtra the number of cells to augment this field by if a (+) boundary is present
       */
      inline BoundaryCellInfo( const IntVec bcm,
                               const IntVec bcp,
                               const IntVec nExtra )
      : minus_( bcm ),
        plus_ ( bcp ),
        nExtra_( plus_ * nExtra ) // only extras if there is a BC present
      {}
  
    public:
  
      /**
       * \brief obtain a BoundaryCellInfo object for the requested field type
       * @param bcmx true if a physical boundary is present on the (-x) face
       * @param bcpx true if a physical boundary is present on the (+x) face
       * @param bcmy true if a physical boundary is present on the (-y) face
       * @param bcpy true if a physical boundary is present on the (+y) face
       * @param bcmz true if a physical boundary is present on the (-z) face
       * @param bcpz true if a physical boundary is present on the (+z) face
       * @return the constructed BoundaryCellInfo object
       */
      template<typename FieldT>
      BoundaryCellInfo
      static inline build( const bool bcmx, const bool bcpx,
                           const bool bcmy, const bool bcpy,
                           const bool bcmz, const bool bcpz )
      {
        return BoundaryCellInfo( IntVec(bcmx,bcmy,bcmz), IntVec(bcpx,bcpy,bcpz), FieldT::Location::BCExtra::int_vec() );
      }
  
      /**
       * \brief obtain a BoundaryCellInfo object for the requested field type
       * @param bcm indicates if a physical boundary is present on each of the (-) faces
       * @param bcp indicates if a physical boundary is present on each of the (+) faces
       * @return the constructed BoundaryCellInfo object
       */
      template<typename FieldT>
      BoundaryCellInfo
      static inline build( const IntVec& bcm, const IntVec& bcp ){
        return BoundaryCellInfo( bcm, bcp, FieldT::Location::BCExtra::int_vec() );
      }
  
      /**
       * \brief obtain a BoundaryCellInfo object for the requested field type,
       *        assuming that there is no physical boundary present on the (+) faces.
       * @return the constructed BoundaryCellInfo object
       */
      template<typename FieldT>
      BoundaryCellInfo
      static inline build(){
        return BoundaryCellInfo( IntVec(false,false,false), IntVec(false,false,false), FieldT::Location::BCExtra::int_vec() );
      }
  
      /**
       * \brief assignment operator
       */
      inline BoundaryCellInfo& operator=( const BoundaryCellInfo& bc ){
        minus_  = bc.minus_;
        plus_   = bc.plus_;
        nExtra_ = bc.nExtra_;
        return *this;
      }
  
      /**
       * \brief copy constructor
       */
      inline BoundaryCellInfo( const BoundaryCellInfo& bc ) : minus_(bc.minus_), plus_(bc.plus_), nExtra_(bc.nExtra_) {}
  
      inline ~BoundaryCellInfo(){}
  
      /**
       * \brief query to see if a physical boundary is present in the given direction (0=x, 1=y, 2=z) and the specified side.
       */
      inline bool has_bc( const int dir, const BCSide side ) const{ return side==MINUS_SIDE ? minus_[dir] : plus_[dir]; }
  
      /**
       * \brief obtain an IntVec indicating the presence of physical boundaries on the (+) faces
       */
      inline IntVec has_bc( const BCSide side ) const{ return side==MINUS_SIDE ? minus_ : plus_; }
  
      /**
       * \brief obtain the number of extra cells *potentially* present on this field due to presence of physical boundaries
       * @param dir the direction of interest (0=x, 1=y, 2=z)
       */
      inline int num_extra( const int dir ) const{ assert(dir<3 && dir>=0); return nExtra_[dir]; }
  
      /**
       * \brief obtain the number of extra cells present on this field due to presence of physical boundaries.  If no physical boundary is present, this returns zero.
       */
      inline IntVec num_extra() const{ return nExtra_; }
  
      /**
       * \brief obtain the number of extra cells *actually* present on this field due to presence of physical boundaries
       * @param dir the direction of interest (0=x, 1=y, 2=z)
       */
      inline int has_extra( const int dir ) const{ assert(dir<3 && dir>=0); return has_bc(dir,PLUS_SIDE) ? num_extra(dir) : 0; }
  
      /**
       * \brief obtain the number of extra cells *actually* present on this field due to presence of physical boundaries
       */
      inline IntVec has_extra() const{ return IntVec(has_extra(0), has_extra(1), has_extra(2)); }
  
      /**
       * \brief limit extra cells to dimensions with extents > 1
       */
      inline BoundaryCellInfo limit_by_extent( const IntVec& extent ) const{
        return BoundaryCellInfo( minus_, plus_,
                                 IntVec( extent[0] == 1 ? 0 : has_extra(0),
                                         extent[1] == 1 ? 0 : has_extra(1),
                                         extent[2] == 1 ? 0 : has_extra(2) ) );
      }
  
      /**
       * \brief compare for equality
       */
      inline bool operator==( const BoundaryCellInfo& other ) const{
        return minus_ == other.minus_ && plus_ == other.plus_ && nExtra_ == other.nExtra_;
      }
    };
  
    inline std::ostream& operator<<( std::ostream& out, const BoundaryCellInfo& bc ){
      out << "BC flags:  minus: " << bc.has_bc(MINUS_SIDE)
          << " plus: " << bc.has_bc(PLUS_SIDE)
          << "  #extra: " << bc.num_extra() << " has_extra: " << bc.has_extra();
      return out;
    }
  
  } /* namespace SpatialOps */
  
  #endif /* SpatialOps_BOUNDARYCELLINFO_H_ */
  