
/**************************************************************************
 *                                                                        *
 *  Regina - A Normal Surface Theory Calculator                           *
 *  Computational Engine                                                  *
 *                                                                        *
 *  Copyright (c) 1999-2025, Ben Burton                                   *
 *  For further details contact Ben Burton (bab@debian.org).              *
 *                                                                        *
 *  This program is free software; you can redistribute it and/or         *
 *  modify it under the terms of the GNU General Public License as        *
 *  published by the Free Software Foundation; either version 2 of the    *
 *  License, or (at your option) any later version.                       *
 *                                                                        *
 *  As an exception, when this program is distributed through (i) the     *
 *  App Store by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or     *
 *  (iii) Google Play by Google Inc., then that store may impose any      *
 *  digital rights management, device limits and/or redistribution        *
 *  restrictions that are required by its terms of service.               *
 *                                                                        *
 *  This program is distributed in the hope that it will be useful, but   *
 *  WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *  General Public License for more details.                              *
 *                                                                        *
 *  You should have received a copy of the GNU General Public License     *
 *  along with this program. If not, see <https://www.gnu.org/licenses/>. *
 *                                                                        *
 **************************************************************************/

#ifndef __REGINA_FACETPAIRING3_H
#ifndef __DOXYGEN
#define __REGINA_FACETPAIRING3_H
#endif

/*! \file triangulation/facetpairing3.h
 *  \brief Deals with dual graphs of 3-manifold triangulations.
 */

#include "regina-core.h"
#include "triangulation/dim3.h"
#include "triangulation/generic/facetpairing.h"

namespace regina {

class FacePair;

/**
 * Represents the dual graph of a 3-manifold triangulation.
 *
 * This is a specialisation of the generic FacetPairing class template; see the
 * generic FacetPairing documentation for an overview of how the facet pairing
 * classes work.  In Python, you can read this generic documentation by
 * looking at a higher dimension: try `help(FacetPairing5)`.
 *
 * This 3-dimensional specialisation contains some extra functionality.
 * In particular, it provides routines for finding informative subgraphs
 * within the dual graph.
 *
 * This class implements C++ move semantics and adheres to the C++ Swappable
 * requirement.  It is designed to avoid deep copies wherever possible,
 * even when passing or returning objects by value.
 *
 * \ingroup triangulation
 */
template <>
class FacetPairing<3> : public detail::FacetPairingBase<3> {
    public:
        /**
         * Creates a new copy of the given face pairing.
         *
         * \param src the face pairing to clone.
         */
        FacetPairing(const FacetPairing& src) = default;

        /**
         * Moves the given face pairing into this face pairing.
         * This is a fast (constant time) operation.
         *
         * The face pairing that is passed (\a src) will no longer be usable.
         *
         * \param src the face pairing to move.
         */
        FacetPairing(FacetPairing&& src) noexcept = default;

        /**
         * Creates the face pairing of the given 3-manifold triangulation.
         * This describes how the tetrahedron faces of the given triangulation
         * are joined together in pairs.
         *
         * Calling `FacetPairing<3>(tri)` is equivalent to calling
         * `tri.pairing()`.
         *
         * \pre The given triangulation is not empty.
         *
         * \param tri the triangulation whose face pairing should be
         * constructed.
         */
        FacetPairing(const Triangulation<3>& tri);

        /**
         * Reads a new facet pairing from the given input stream.  This
         * routine reads data in the format written by textRep().
         *
         * This routine will skip any initial whitespace in the given input
         * stream.  Once it finds its first non-whitespace character,
         * it will read the _entire_ line from the input stream and expect
         * that line to containin the text representation of a facet pairing.
         *
         * If the data found in the input stream is invalid, incomplete or
         * incorrectly formatted, this constructor will throw an InvalidInput
         * exception.
         *
         * \nopython Instead use fromTextRep(), which reads this same text
         * format in string form.  The main differences between this
         * constructor and fromTextRep() are: (i) fromTextRep() does not
         * skip over initial whitespace; and (ii) fromTextRep() throws
         * InvalidArgument exceptions on error (not InvalidInput).
         *
         * \param in the input stream from which to read.
         */
        FacetPairing(std::istream& in);

        /**
         * Copies the given face pairing into this face pairing.
         *
         * It does not matter if this and the given face pairing use
         * different numbers of tetrahedra; if they do then this
         * face pairing will be resized accordingly.
         *
         * This operator induces a deep copy of \a src.
         *
         * \param src the facet pairing to copy.
         * \return a reference to this face pairing.
         */
        FacetPairing& operator = (const FacetPairing& src) = default;

        /**
         * Moves the given face pairing into this facet pairing.
         * This is a fast (constant time) operation.
         *
         * It does not matter if this and the given face pairing use
         * different numbers of tetrahedra; if they do then this
         * face pairing will be resized accordingly.
         *
         * The face pairing that is passed (\a src) will no longer be usable.
         *
         * \param src the face pairing to move.
         * \return a reference to this face pairing.
         */
        FacetPairing& operator = (FacetPairing&& src) noexcept = default;

        /**
         * Follows a chain as far as possible from the given point.
         *
         * A chain is the underlying face pairing for a layered chain;
         * specifically it involves one tetrahedron joined to a second
         * along two faces, the remaining two faces of the second
         * tetrahedron joined to a third and so on.  A chain can involve
         * as few as one tetrahedron or as many as we like.  Note that
         * the remaining two faces of the first tetrahedron and the
         * remaining two faces of the final tetrahedron remain
         * unaccounted for by this structure.
         *
         * This routine begins with two faces of a given tetrahedron,
         * described by parameters \a tet and \a faces.
         * If these two faces are both joined to some different
         * tetrahedron, parameter \a tet will be changed to this new
         * tetrahedron and parameter \a faces will be changed to the
         * remaining faces of this new tetrahedron (i.e., the two faces
         * that were not joined to the original faces of the original
         * tetrahedron).
         *
         * This procedure is repeated as far as possible until either
         * the two faces in question join to two different tetrahedra,
         * the two faces join to each other, or at least one of the
         * two faces is unmatched.
         *
         * Thus, given one end of a chain, this procedure can be used to
         * follow the face pairings through to the other end of the chain.
         *
         * \warning You must be sure when calling this routine that you
         * are not inside a chain that loops back onto itself!
         * If the face pairing forms a
         * large loop with each tetrahedron joined by two faces to the
         * next, this routine will cycle around the loop forever and
         * never return.
         *
         * \param tet the index in the underlying triangulation of the
         * tetrahedron to begin at.  This parameter will be modified
         * directly by this routine as a way of returning the results.
         * \param faces the pair of face numbers in the given
         * tetrahedron at which we begin.  This parameter will also be
         * modified directly by this routine as a way of returning results.
         */
        void followChain(ssize_t& tet, FacePair& faces) const;

        /**
         * Deprecated version of followChain() that uses an unsigned
         * integer type.
         *
         * This routine behaves identically to followChain(size_t&, FacePair&),
         * except that the tetrahedron index is passed using type \c size_t
         * instead of \c ssize_t.  This was the behaviour of followChain()
         * in Regina 7.0 and earlier.
         *
         * As of Regina 7.1, followChain() has been reimplemented using
         * \c ssize_t, for consistency with the type used by FacetSpec<3>::simp.
         *
         * See followChain(size_t&, FacePair&) for further details.
         *
         * \deprecated Use \c ssize_t for the tetrahedron index instead.
         * This routine is implemented by calling the \c ssize_t variant
         * with some extra casts on either side that may add a tiny
         * performance cost.
         *
         * \nopython Use the non-deprecated variant of this routine instead.
         *
         * \param tet the index in the underlying triangulation of the
         * tetrahedron to begin at.  This parameter will be modified
         * directly by this routine as a way of returning the results.
         * \param faces the pair of face numbers in the given
         * tetrahedron at which we begin.  This parameter will also be
         * modified directly by this routine as a way of returning results.
         */
        [[deprecated]] void followChain(size_t& tet, FacePair& faces) const;

        /**
         * Determines whether this face pairing contains a triple edge.
         * A triple edge is where two different tetrahedra are joined
         * along three of their faces.
         *
         * A face pairing containing a triple edge cannot model a closed
         * minimal irreducible P²-irreducible 3-manifold triangulation on
         * more than two tetrahedra.  See "Face pairing graphs and 3-manifold
         * enumeration", Benjamin A. Burton, J. Knot Theory Ramifications
         * 13 (2004), 1057--1101.
         *
         * This routine is identical to calling `hasMultiEdge<3>()`.
         *
         * \return \c true if and only if this face pairing contains a
         * triple edge.
         */
        bool hasTripleEdge() const;

        /**
         * Determines whether this face pairing contains a broken
         * double-ended chain.
         *
         * A chain involves a sequence of tetrahedra, each joined to the
         * next along two faces, and is described in detail in the
         * documentation for followChain().
         *
         * A one-ended chain is a chain in which the first tetrahedron
         * is also joined to itself along one face (i.e., the underlying
         * face pairing for a layered solid torus).  A double-ended
         * chain is a chain in which the first tetrahedron is joined to
         * itself along one face and the final tetrahedron is also
         * joined to itself along one face (i.e., the underlying
         * face pairing for a layered lens space).
         *
         * A broken double-ended chain consists of two one-ended chains
         * (using distinct sets of tetrahedra) joined together along one
         * face.  The remaining two faces (one from each chain)
         * that were unaccounted for by the individual one-ended chains
         * remain unaccounted for by this broken double-ended chain.
         *
         * In this routine we are interested specifically in finding a
         * broken double-ended chain that is not a part of a complete
         * double-ended chain, i.e., the final two unaccounted faces are
         * not joined together.
         *
         * A face pairing containing a broken double-ended chain cannot
         * model a closed minimal irreducible P²-irreducible 3-manifold
         * triangulation on more than two tetrahedra.  See "Face pairing
         * graphs and 3-manifold enumeration", Benjamin A. Burton,
         * J. Knot Theory Ramifications 13 (2004), 1057--1101.
         *
         * \return \c true if and only if this face pairing contains a
         * broken double-ended chain that is not part of a complete
         * double-ended chain.
         */
        bool hasBrokenDoubleEndedChain() const;

        /**
         * Determines whether this face pairing contains a one-ended chain
         * with a double handle.
         *
         * A chain involves a sequence of tetrahedra, each joined to the
         * next along two faces, and is described in detail in the
         * documentation for followChain().
         *
         * A one-ended chain is a chain in which the first tetrahedron
         * is also joined to itself along one face (i.e., the underlying
         * face pairing for a layered solid torus).
         *
         * A one-ended chain with a double handle begins with a one-ended
         * chain.  The two faces that are unaccounted for by this
         * one-ended chain must be joined
         * to two different tetrahedra, and these two tetrahedra must be
         * joined to each other along two faces.  The remaining two
         * faces of these two tetrahedra remain unaccounted for by this
         * structure.
         *
         * A face pairing containing a one-ended chain with a double handle
         * cannot model a closed minimal irreducible P²-irreducible
         * 3-manifold triangulation on more than two tetrahedra.  See
         * "Face pairing graphs and 3-manifold enumeration",
         * Benjamin A. Burton, J. Knot Theory Ramifications 13 (2004),
         * 1057--1101.
         *
         * \return \c true if and only if this face pairing contains a
         * one-ended chain with a double handle.
         */
        bool hasOneEndedChainWithDoubleHandle() const;

        /**
         * Determines whether this face pairing contains a wedged
         * double-ended chain.
         *
         * A chain involves a sequence of tetrahedra, each joined to the
         * next along two faces, and is described in detail in the
         * documentation for followChain().
         *
         * A one-ended chain is a chain in which the first tetrahedron
         * is also joined to itself along one face (i.e., the underlying
         * face pairing for a layered solid torus).  A double-ended
         * chain is a chain in which the first tetrahedron is joined to
         * itself along one face and the final tetrahedron is also
         * joined to itself along one face (i.e., the underlying
         * face pairing for a layered lens space).
         *
         * A wedged double-ended chain is created from two one-ended
         * chains as follows.  Two new tetrahedra are added, and each
         * one-ended chain is joined to each of the new tetrahedra along
         * a single face.  In addition, the two new tetrahedra are
         * joined to each other along a single face.  The remaining two
         * faces (one from each of the new tetrahedra) remain
         * unaccounted for by this structure.
         *
         * An alternative way of viewing a wedged double-ended chain is
         * as an ordinary double-ended chain, where one of the internal
         * tetrahedra is removed and replaced with a pair of tetrahedra
         * joined to each other.  Whereas the original tetrahedron met its
         * two neighbouring tetrahedra along two faces each (giving a
         * total of four face identifications), the two new tetrahedra now
         * meet each of the two neighbouring tetrahedra along a single
         * face each (again giving four face identifications).
         *
         * Note that if this alternate construction is used to replace
         * one of the end tetrahedra of the double-ended chain (not an
         * internal tetrahedron), the resulting structure will either be
         * a triple edge or a one-ended chain with a double handle
         * (according to whether the original chain has zero or positive
         * length).  See hasTripleEdge() and
         * hasOneEndedChainWithDoubleHandle() for further details.
         *
         * A face pairing containing a wedged double-ended chain
         * cannot model a closed minimal irreducible P²-irreducible
         * 3-manifold triangulation on more than two tetrahedra.  See
         * "Enumeration of non-orientable 3-manifolds using face-pairing
         * graphs and union-find", Benjamin A. Burton,
         * Discrete Comput. Geom. 38 (2007), no. 3, 527--571.
         *
         * \return \c true if and only if this face pairing contains a
         * wedged double-ended chain.
         */
        bool hasWedgedDoubleEndedChain() const;

        /**
         * Determines whether this face pairing contains a one-ended
         * chain with a stray bigon.
         *
         * A chain involves a sequence of tetrahedra, each joined to the
         * next along two faces, and is described in detail in the
         * documentation for followChain().
         *
         * A one-ended chain is a chain in which the first tetrahedron
         * is also joined to itself along one face (i.e., the underlying
         * face pairing for a layered solid torus).
         *
         * A one-ended chain with a stray bigon describes the following
         * structure.  We begin with a one-ended chain.  Two new
         * tetrahedra are added; these are joined to each other along
         * two pairs of faces, and one of the new tetrahedra is joined
         * to the end of the one-ended chain.  We then ensure that:
         * - This configuration is not part of a longer one-ended chain
         *   that encompasses all of the aforementioned tetrahedra;
         * - There is no extra tetrahedron that is joined to both the
         *   two new tetrahedra and the end of the chain;
         * - There is no extra tetrahedron that is joined to the end of
         *   the chain along one face and the far new tetrahedron along
         *   two additional faces (where by "the far new tetrahedron"
         *   we mean the new tetrahedron that was not originally joined to
         *   the chain).
         *
         * Aside from these constraints, the remaining four tetrahedron faces
         * (two faces of the far new tetrahedron, one face of the other new
         * tetrahedron, and one face at the end of the chain) remain
         * unaccounted for by this structure.
         *
         * A face pairing containing a structure of this type
         * cannot model a closed minimal irreducible P²-irreducible
         * 3-manifold triangulation on more than two tetrahedra.  See
         * "Enumeration of non-orientable 3-manifolds using face-pairing
         * graphs and union-find", Benjamin A. Burton,
         * Discrete Comput. Geom. 38 (2007), no. 3, 527--571.
         *
         * \return \c true if and only if this face pairing contains a
         * one-ended chain with a stray bigon.
         */
        bool hasOneEndedChainWithStrayBigon() const;

        /**
         * Determines whether this face pairing contains a triple
         * one-ended chain.
         *
         * A chain involves a sequence of tetrahedra, each joined to the
         * next along two faces, and is described in detail in the
         * documentation for followChain().
         *
         * A one-ended chain is a chain in which the first tetrahedron
         * is also joined to itself along one face (i.e., the underlying
         * face pairing for a layered solid torus).
         *
         * A triple one-ended chain is created from three one-ended
         * chains as follows.  Two new tetrahedra are added, and each
         * one-ended chain is joined to each of the new tetrahedra along
         * a single face.  The remaining two faces (one from each of the
         * new tetrahedra) remain unaccounted for by this structure.
         *
         * A face pairing containing a triple one-ended chain
         * cannot model a closed minimal irreducible P²-irreducible
         * 3-manifold triangulation on more than two tetrahedra.  See
         * "Enumeration of non-orientable 3-manifolds using face-pairing
         * graphs and union-find", Benjamin A. Burton,
         * Discrete Comput. Geom. 38 (2007), no. 3, 527--571.
         *
         * \return \c true if and only if this face pairing contains a
         * triple one-ended chain.
         */
        bool hasTripleOneEndedChain() const;

        /**
         * Determines whether this face pairing contains a single-edged
         * star.
         *
         * A single-edged star involves two tetrahedra that are adjacent
         * along a single face, where the six remaining faces of these
         * tetrahedra are joined to six entirely new tetrahedra (so that
         * none of the eight tetrahedra described in this structure are
         * the same).
         *
         * \return \c true if and only if this face pairing contains a
         * single-edged star.
         */
        bool hasSingleStar() const;

        /**
         * Determines whether this face pairing contains a double-edged
         * star.
         *
         * A double-edged star involves two tetrahedra that are adjacent
         * along two separate pairs of faces, where the four remaining
         * faces of these tetrahedra are joined to four entirely new
         * tetrahedra (so that none of the six tetrahedra described in
         * this structure are the same).
         *
         * \return \c true if and only if this face pairing contains a
         * double-edged star.
         */
        bool hasDoubleStar() const;

        /**
         * Determines whether this face pairing contains a double-edged
         * square.
         *
         * A double-edged square involves four distinct tetrahedra that
         * meet each other as follows.  Two pairs of tetrahedra are
         * joined along two pairs of faces each.  Then each tetrahedron
         * is joined along a single face to one tetrahedron of the other
         * pair.  The four tetrahedron faces not yet joined to anything
         * (one from each tetrahedron) remain unaccounted for by this
         * structure.
         *
         * \return \c true if and only if this face pairing contains a
         * double-edged square.
         */
        bool hasDoubleSquare() const;

    private:
        /**
         * Creates a new face pairing.  All internal arrays will be
         * allocated but not initialised.
         *
         * \pre \a size is at least 1.
         *
         * \param size the number of tetrahedra under
         * consideration in this new face pairing.
         */
        FacetPairing(size_t size);

        /**
         * Internal to hasBrokenDoubleEndedChain().  This routine assumes
         * that the give face of the given tetrahedron is glued to this
         * same tetrahedron, and attempts to find a broken double-ended
         * chain for which this tetrahedron is at the end of one of the
         * one-ended chains therein.
         *
         * \pre The given face of the given tetrahedron is paired with
         * another face of the same tetrahedron under this face pairing.
         *
         * \param tet the index in the triangulation of the given
         * tetrahedron.
         * \param face the number of the given face in the tetrahedron;
         * this must be between 0 and 3 inclusive.
         *
         * \return \c true if and only if this face pairing contains a
         * broken double-ended chain as described above.
         */
        bool hasBrokenDoubleEndedChain(size_t tet, int face) const;

        /**
         * Internal to hasOneEndedChainWithDoubleHandle().  This routine
         * assumes that the give face of the given tetrahedron is glued
         * to this same tetrahedron, and attempts to find a one-ended
         * chain with a double handle for which this tetrahedron is at
         * the end of the chain contained therein.
         *
         * \pre The given face of the given tetrahedron is paired with
         * another face of the same tetrahedron under this face pairing.
         *
         * \param tet the index in the triangulation of the given
         * tetrahedron.
         * \param face the number of the given face in the tetrahedron;
         * this must be between 0 and 3 inclusive.
         *
         * \return \c true if and only if this face pairing contains a
         * one-ended chain with a double handle as described above.
         */
        bool hasOneEndedChainWithDoubleHandle(size_t tet, int face) const;

        /**
         * Internal to hasWedgedDoubleEndedChain().  This routine assumes
         * that the give face of the given tetrahedron is glued to this
         * same tetrahedron, and attempts to find a wedged double-ended
         * chain for which this tetrahedron is at one end of the
         * double-ended chain.
         *
         * \pre The given face of the given tetrahedron is paired with
         * another face of the same tetrahedron under this face pairing.
         *
         * \param tet the index in the triangulation of the given
         * tetrahedron.
         * \param face the number of the given face in the tetrahedron;
         * this must be between 0 and 3 inclusive.
         *
         * \return \c true if and only if this face pairing contains a
         * wedged double-ended chain as described above.
         */
        bool hasWedgedDoubleEndedChain(size_t tet, int face) const;

        /**
         * Internal to hasOneEndedChainWithStrayBigon().  This routine assumes
         * that the give face of the given tetrahedron is glued to this
         * same tetrahedron, and attempts to find a one-ended chain with
         * stray bigon for which this tetrahedron is at the end of the
         * one-ended chain.
         *
         * \pre The given face of the given tetrahedron is paired with
         * another face of the same tetrahedron under this face pairing.
         *
         * \param tet the index in the triangulation of the given
         * tetrahedron.
         * \param face the number of the given face in the tetrahedron;
         * this must be between 0 and 3 inclusive.
         *
         * \return \c true if and only if this face pairing contains a
         * one-ended chain with stray bigon as described above.
         */
        bool hasOneEndedChainWithStrayBigon(size_t tet, int face) const;

        /**
         * Internal to hasTripleOneEndedChain().  This routine assumes
         * that the give face of the given tetrahedron is glued to this
         * same tetrahedron, and attempts to find a triple one-ended
         * chain for which this tetrahedron is at the end of one of the
         * individual one-ended chains.
         *
         * \pre The given face of the given tetrahedron is paired with
         * another face of the same tetrahedron under this face pairing.
         *
         * \param tet the index in the triangulation of the given
         * tetrahedron.
         * \param face the number of the given face in the tetrahedron;
         * this must be between 0 and 3 inclusive.
         *
         * \return \c true if and only if this face pairing contains a
         * triple one-ended chain as described above.
         */
        bool hasTripleOneEndedChain(size_t tet, int face) const;

    // Make sure the parent class can call the private constructor.
    friend class detail::FacetPairingBase<3>;

    // Facet pairings are largely read-only: allow application of isomorphisms
    // and graph cuts.
    friend class Isomorphism<3>;
    friend class Cut;
};

// Inline functions for FacetPairing<3>

inline FacetPairing<3>::FacetPairing(const Triangulation<3>& tri) :
        detail::FacetPairingBase<3>(tri) {
}

inline FacetPairing<3>::FacetPairing(std::istream& in) :
        detail::FacetPairingBase<3>(in) {
}

inline FacetPairing<3>::FacetPairing(size_t size) :
        detail::FacetPairingBase<3>(size) {
}

inline bool FacetPairing<3>::hasTripleEdge() const {
    return hasMultiEdge<3>();
}

inline void FacetPairing<3>::followChain(size_t& tet, FacePair& faces) const {
    auto t = static_cast<ssize_t>(tet);
    followChain(t, faces);
    tet = static_cast<size_t>(t);
}

} // namespace regina

#endif

