/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
    \\  /    A nd           | www.openfoam.com
     \\/     M anipulation  |
-------------------------------------------------------------------------------
    Copyright (C) 2016-2024 OpenCFD Ltd.
-------------------------------------------------------------------------------
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/>.

Description
    Containers for holding STARCCM interface definitions

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

#ifndef Foam_ccmInterfaceDefinitions_H
#define Foam_ccmInterfaceDefinitions_H

#include "Map.H"
#include "Ostream.H"

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

namespace Foam
{
namespace ccm
{

class interfaceEntry;
class interfaceDefinitions;

Ostream& operator<<(Ostream& os, const interfaceEntry& entry);
Ostream& operator<<(Ostream& os, const interfaceDefinitions& defs);

/*---------------------------------------------------------------------------*\
                  Class Foam::ccm::interfaceEntry Declaration
\*---------------------------------------------------------------------------*/

//- A STARCCM interface definition is a pair of boundary ids
class interfaceEntry
{
public:

    // Public Data

        //- The internal interface id
        label id;

        //- The first boundary
        label bnd0;

        //- The second boundary
        label bnd1;


    // Constructors

        //- Default construct
        constexpr interfaceEntry() noexcept
        :
            id(-1),
            bnd0(-1),
            bnd1(-1)
        {}

        //- Construct empty interface definition
        constexpr interfaceEntry(const label index) noexcept
        :
            id(index),
            bnd0(-1),
            bnd1(-1)
        {}

        //- Construct from components
        constexpr interfaceEntry
        (
            const label index,
            const label boundary0,
            const label boundary1
        ) noexcept
        :
            id(index),
            bnd0(boundary0),
            bnd1(boundary1)
        {}


    // Access

        //- Check for in-place interfaces
        static bool isInPlace(const std::string& configurationType)
        {
            return configurationType == "IN_PLACE";
        }


        //- True if the boundary id is in this interface
        bool inInterface(label bndId) const noexcept
        {
            return bndId == bnd0 || bndId == bnd1;
        }

        //- True if all internal ids are non-negative
        bool good() const noexcept
        {
            return (id >= 0 && bnd0 >= 0 && bnd1 >= 0 && bnd0 != bnd1);
        }

        //- Same as good()
        bool valid() const noexcept { return good(); }


        //- Canonical name for boundary 0
        word canonicalName0() const
        {
            return "Interface" + ::Foam::name(id) + "_0";
        }

        //- Canonical name for boundary 1
        word canonicalName1() const
        {
            return "Interface" + ::Foam::name(id) + "_1";
        }

        //- Canonical name for boundary
        word canonicalName(label bndId) const
        {
            if (bndId == bnd0)
            {
                return canonicalName0();
            }
            else if (bndId == bnd1)
            {
                return canonicalName1();
            }
            else
            {
                return word();
            }
        }


    // IOstream Operators

        friend Ostream& operator<<
        (
            Ostream& os,
            const interfaceEntry& entry
        )
        {
            os  << '(' << entry.bnd0 << ' ' << entry.bnd1 << ')';
            return os;
        }
};


/*---------------------------------------------------------------------------*\
                  Class ccm::interfaceDefinitions Declaration
\*---------------------------------------------------------------------------*/

//- A list of available interface definitions
class interfaceDefinitions
:
    public Map<interfaceEntry>
{
    typedef Map<interfaceEntry> map_type;

    const map_type& map() const noexcept { return *this; }


public:

    // Constructor

        //- Default construct
        interfaceDefinitions() noexcept = default;

        //- Map size
        using map_type::size;

        //- Map empty?
        using map_type::empty;

        //- Map clear
        using map_type::clear;


        //- Add (valid) interface entry
        bool add(const interfaceEntry& entry)
        {
            return (entry.good() && map_type::set(entry.id, entry));
        }


        //- Scan available interface entries for one matching this boundary id
        bool isInterface(label bndId)
        {
            forAllConstIters(map(), iter)
            {
                if (iter.val().inInterface(bndId))
                {
                    return true;
                }
            }
            return false;
        }


        //- Scan interface entries for one matching this boundary id
        //  return the canonical name
        word interfaceName(label bndId)
        {
            word ifname;
            forAllConstIters(map(), iter)
            {
                ifname = iter.val().canonicalName(bndId);
                if (!ifname.empty())
                {
                    break;
                }
            }

            return ifname;
        }


    // IOstream Operators

        friend Ostream& operator<<
        (
            Ostream& os,
            const interfaceDefinitions& defs
        )
        {
            os  << defs.map() << nl;
            return os;
        }
};


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

} // End namespace ccm
} // End namespace Foam

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

#endif

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