// ---------------------------------------------------------------------
//
// Copyright (C) 2017 by the deal.II authors
//
// This file is part of the deal.II library.
//
// The deal.II library is free software; you can use it, 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.
// The full text of the license can be found in the file LICENSE at
// the top level of the deal.II distribution.
//
// ---------------------------------------------------------------------

#ifndef dealii_mesh_worker_assemble_flags_h
#define dealii_mesh_worker_assemble_flags_h


#include <deal.II/base/config.h>
#include <vector>


DEAL_II_NAMESPACE_OPEN

/*!@addtogroup MeshWorker */
/*@{*/

namespace MeshWorker
{

  /**
   * The enum type given to the mesh_loop() function, telling that function which
   * elements need to be assembled.
   *
   * You can select more than one flag by concatenation using the bitwise or
   * <code>operator|(AssembleFlags,AssembleFlags)</code>.
   *
   * @author Luca Heltai, 2017.
   */
  enum AssembleFlags
  {
    /**
     * Do Nothing.
     */
    assemble_nothing = 0,
    /**
     * Assemble on locally owned cells.
     */
    assemble_own_cells = 0x0001,
    /**
     * Assemble on ghost cells.
     */
    assemble_ghost_cells = 0x0002,
    /**
     * Assemble on interior faces between two locally owned cells,
     * visiting each face only once.
     */
    assemble_own_interior_faces_once = 0x0004,
    /**
     * Assemble on interior faces between two locally owned cells,
     * visiting each interior face twice, once from each of the two
     * adjacent cells.
     */
    assemble_own_interior_faces_both = 0x0008,
    /**
     * Assemble on faces between a locally owned cell and a ghost cell, making
     * sure that only one of the processes will assemble these faces (from the
     * finer side or the process with the lower mpi rank).
     */
    assemble_ghost_faces_once = 0x0010,
    /**
     * Assemble on faces between a locally owned cell and a ghost cell. Both
     * processes will assemble these faces. Note that they are never
     * assembled from both sides on a single process.
     */
    assemble_ghost_faces_both = 0x0020,
    /**
     * Assemble on boundary faces of the locally owned cells.
     */
    assemble_boundary_faces = 0x0040,

    /**
     * By default we assemble cell integrals before face integrals. If this
     * flag is specified, cells will be assembled after faces and boundaries.
     */
    cells_after_faces = 0x0080,

    /**
     * Combination of flags to determine if any work on cells is done.
     */
    work_on_cells = assemble_own_cells | assemble_ghost_cells,

    /**
     * Combination of flags to determine if any work is done on faces.
     */
    work_on_faces = assemble_own_interior_faces_once
                    | assemble_own_interior_faces_both
                    | assemble_ghost_faces_once
                    | assemble_ghost_faces_both,

    /**
     * Combination of flags to determine if any work is done on the boundary
     * faces.
     */
    work_on_boundary = assemble_boundary_faces,
  };


  /**
   * Output operator which outputs assemble flags as a set of or'd text values.
   *
   * @ref AssembleFlags
   */
  template <class StreamType>
  inline
  StreamType &operator << (StreamType &s, AssembleFlags u)
  {
    s << " AssembleFlags";
    if (u & assemble_own_cells        ) s << "|own_cells"        ;
    if (u & assemble_own_interior_faces_once   ) s << "|own_faces_once"   ;
    if (u & assemble_own_interior_faces_both   ) s << "|own_faces_both"   ;
    if (u & assemble_ghost_cells      ) s << "|ghost_cells"      ;
    if (u & assemble_ghost_faces_once ) s << "|ghost_faces_once" ;
    if (u & assemble_ghost_faces_both ) s << "|ghost_faces_both" ;
    if (u & assemble_boundary_faces   ) s << "|boundary_faces"   ;
    return s;
  }


  /**
   * Global operator which returns an object in which all bits are set which are
   * either set in the first or the second argument. This operator exists since
   * if it did not then the result of the bit-or <tt>operator |</tt> would be an
   * integer which would in turn trigger a compiler warning when we tried to
   * assign it to an object of type AssembleFlags.
   *
   * @ref AssembleFlags
   */
  inline
  AssembleFlags
  operator | (AssembleFlags f1, AssembleFlags f2)
  {
    return static_cast<AssembleFlags> (
             static_cast<unsigned int> (f1) |
             static_cast<unsigned int> (f2));
  }




  /**
   * Global operator which sets the bits from the second argument also in the
   * first one.
   *
   * @ref AssembleFlags
   */
  inline
  AssembleFlags &
  operator |= (AssembleFlags &f1, AssembleFlags f2)
  {
    f1 = f1 | f2;
    return f1;
  }


  /**
   * Global operator which returns an object in which all bits are set which are
   * set in the first as well as the second argument. This operator exists since
   * if it did not then the result of the bit-and <tt>operator &</tt> would be
   * an integer which would in turn trigger a compiler warning when we tried to
   * assign it to an object of type AssembleFlags.
   *
   * @ref AssembleFlags
   */
  inline
  AssembleFlags
  operator & (AssembleFlags f1, AssembleFlags f2)
  {
    return static_cast<AssembleFlags> (
             static_cast<unsigned int> (f1) &
             static_cast<unsigned int> (f2));
  }


  /**
   * Global operator which clears all the bits in the first argument if they are
   * not also set in the second argument.
   *
   * @ref AssembleFlags
   */
  inline
  AssembleFlags &
  operator &= (AssembleFlags &f1, AssembleFlags f2)
  {
    f1 = f1 & f2;
    return f1;
  }
}

/*@}*/

DEAL_II_NAMESPACE_CLOSE

#endif
