/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
    \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
     \\/     M anipulation  |
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.

    OpenFOAM 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 3 of the License, or
    (at your option) any later version.

    OpenFOAM 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 OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.

Class
    Foam::globalIndexAndTransform

Description
    Determination and storage of the possible independent transforms
    introduced by coupledPolyPatches, as well as all of the possible
    permutations of these transforms generated by the presence of
    multiple coupledPolyPatches, i.e. more than one cyclic boundary.

    Also provides global index encoding and decoding for entity
    (i.e. cell) index, processor index and transform index (0 or
    positive integer) to a labelPair.

SourceFiles
    globalIndexAndTransform.C

\*---------------------------------------------------------------------------*/

#ifndef globalIndexAndTransform_H
#define globalIndexAndTransform_H

#include "labelPair.H"
#include "vectorTensorTransform.H"
#include "HashSet.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

namespace Foam
{

class polyMesh;


/*---------------------------------------------------------------------------*\
                   Class globalIndexAndTransform Declaration
\*---------------------------------------------------------------------------*/

class globalIndexAndTransform
{
public:

    // Public classes

        //- Less function class used in sorting encoded transforms and indices
        //  Minimum of:
        //  - processor
        //  - local index
        //  - transform
        class less
        {
        public:

            inline bool operator()(const labelPair&, const labelPair&) const;
        };


private:

    // Private data

        //- Reference to mesh
        const polyMesh& mesh_;

        //- The possible independent (non-permuted) transforms of the
        //  geometry, i.e. for a geometry with two cyclics, this
        //  stores the two transforms, not the eight permutations.
        //  There may not be more than three transforms in the range
        //  of coupledPolyPatch geometries (separated XOR
        //  non-parallel) and symmetries (cuboid periodicity only)
        //  supported.
        List<vectorTensorTransform> transforms_;

        //- The permutations of the transforms, stored for lookup
        //  efficiency.  If there are n transforms, then there are
        //  (3^n) permutations, including the no-transformation
        //  transform.
        List<vectorTensorTransform> transformPermutations_;

        //- Index of identity transform.
        label nullTransformIndex_;

        //- Mapping from patch index to which transform it matches (or
        //  -1 for none) (.first()) and what sign to use for it,
        //  i.e. +/- 1 (.second()).
        List<Pair<label> > patchTransformSign_;


    // Private static data

        //- Number of spaces to reserve for transform encoding
        static const label base_;


    // Private Member Functions

        //- Determine all of the independent basic transforms of the
        //  geometry by analysing the coupledPolyPatches
        void determineTransforms();

        //- Generate all of the transformation permutations
        void determineTransformPermutations();

        //- Determine which patch uses which transform (if any) and which
        //- Sign to use
        void determinePatchTransformSign();

        //- Test a list of reference transforms to see if the test
        //  transform matches one.  Return +1 or -1 depending on the
        //  sign of the match, or 0 if none matches.
        label matchTransform
        (
            const List<vectorTensorTransform>& refTransforms,
            label& matchedRefTransformI,
            const vectorTensorTransform& testTransform,
            scalar tolerance,
            bool checkBothSigns
        ) const;

        //- Encode transform index. Hardcoded to 3 independent transforms max.
        inline label encodeTransformIndex
        (
            const FixedList<Foam::label, 3>& permutationIndices
        ) const;

        //- Decode transform index. Hardcoded to 3 independent transforms max.
        inline FixedList<label, 3> decodeTransformIndex
        (
            const label transformIndex
        ) const;

        //- Disallow default bitwise copy construct
        globalIndexAndTransform(const globalIndexAndTransform&);

        //- Disallow default bitwise assignment
        void operator=(const globalIndexAndTransform&);


public:

        //- Declare friendship with the entry class for IO
        friend class globalPoints;


    // Declare name of the class and its debug switch
    ClassName("globalIndexAndTransform");


    // Constructors

        //- Construct from components
        globalIndexAndTransform(const polyMesh& mesh);


    //- Destructor
    ~globalIndexAndTransform();


    // Member Functions

        //- Generate a transform index from the permutation indices of
        //  the independent transforms.  Permutations indices must
        //  only be -1, 0 or +1.
        inline label encodeTransformIndex
        (
            const List<label>& permutationIndices
        ) const;

        //- Add patch transformation to transformIndex. Return new
        //  transformIndex. (by default the patch is the sending, not the
        //  receiving, patch)
        inline label addToTransformIndex
        (
            const label transformIndex,
            const label patchI,
            const bool isSendingSide = true,
            const scalar tol = SMALL
        ) const;

        //- Combine two transformIndices
        inline label mergeTransformIndex
        (
            const label transformIndex0,
            const label transformIndex1
        ) const;

        //- Combine two transformIndices
        inline label minimumTransformIndex
        (
            const label transformIndex0,
            const label transformIndex1
        ) const;

        //- Subtract two transformIndices
        inline label subtractTransformIndex
        (
            const label transformIndex0,
            const label transformIndex1
        ) const;

        //- Encode index and bare index as components on own processor
        inline static labelPair encode
        (
            const label index,
            const label transformIndex
        );

        //- Encode index and bare index as components on given processor
        inline static labelPair encode
        (
            const label procI,
            const label index,
            const label transformIndex
        );

        //- Index carried by the object
        inline static label index(const labelPair& globalIAndTransform);

        //- Which processor does this come from?
        inline static label processor(const labelPair& globalIAndTransform);

        //- Transform carried by the object
        inline static label transformIndex
        (
            const labelPair& globalIAndTransform
        );

        // Access

            //- Return the number of independent transforms
            inline label nIndependentTransforms() const;

            //- Return access to the stored independent transforms
            inline const List<vectorTensorTransform>& transforms() const;

            //- Return access to the permuted transforms
            inline const List<vectorTensorTransform>&
            transformPermutations() const;

            //- Return the transformIndex (index in transformPermutations)
            //  of the identity transform
            inline label nullTransformIndex() const;

            //- Return access to the per-patch transform-sign pairs
            inline const List<Pair<label> >& patchTransformSign() const;

            //- Access the overall (permuted) transform corresponding
            //  to the transformIndex
            inline const vectorTensorTransform& transform
            (
                label transformIndex
            ) const;

            //- Access the all of the indices of the transform
            //  permutations corresponding the transforms of the
            //  listed patch indices
            inline labelList transformIndicesForPatches
            (
                const labelHashSet& patchIs
            ) const;

            //- Apply all of the transform permutations
            //  corresponding the transforms of the listed patch
            //  indices to the supplied point
            inline pointField transformPatches
            (
                const labelHashSet& patchIs,
                const point& pt
            ) const;

};


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

} // End namespace Foam

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#include "globalIndexAndTransformI.H"

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#endif

// ************************************************************************* //
