#include "PyMFEMTrampolines/Operator/PyOperator.h"
#include "mfem.hpp"

namespace serif::pybind {

    // --- Pure virtual function implementation ---
    // This override is mandatory for the trampoline class to be concrete.
    void PyOperator::Mult(const mfem::Vector &x, mfem::Vector &y) const {
        PYBIND11_OVERRIDE_PURE(
            void,            /* Return type */
            mfem::Operator,  /* C++ base class */
            Mult,            /* C++ function name */
            x,               /* Argument 1 */
            y                /* Argument 2 */
        );
    }

    // --- Regular virtual function implementations ---
    // These overrides allow Python subclasses to optionally provide their own
    // implementation for these methods. If they don't, the default C++
    // implementation from mfem::Operator will be called.

    void PyOperator::MultTranspose(const mfem::Vector &x, mfem::Vector &y) const {
        PYBIND11_OVERRIDE(
            void,
            mfem::Operator,
            MultTranspose,
            x,
            y
        );
    }

    void PyOperator::AddMult(const mfem::Vector &x, mfem::Vector &y, const mfem::real_t a) const {
        PYBIND11_OVERRIDE(
            void,
            mfem::Operator,
            AddMult,
            x,
            y,
            a
        );
    }

    void PyOperator::AddMultTranspose(const mfem::Vector &x, mfem::Vector &y, const mfem::real_t a) const {
        PYBIND11_OVERRIDE(
            void,
            mfem::Operator,
            AddMultTranspose,
            x,
            y,
            a
        );
    }

    mfem::Operator& PyOperator::GetGradient(const mfem::Vector &x) const {
        PYBIND11_OVERRIDE(
            mfem::Operator&,
            mfem::Operator,
            GetGradient,
            x
        );
    }

    void PyOperator::AssembleDiagonal(mfem::Vector &diag) const {
        PYBIND11_OVERRIDE(
            void,
            mfem::Operator,
            AssembleDiagonal,
            diag
        );
    }

    const mfem::Operator* PyOperator::GetProlongation() const {
        PYBIND11_OVERRIDE(
            const mfem::Operator*,
            mfem::Operator,
            GetProlongation
        );
    }

    const mfem::Operator* PyOperator::GetRestriction() const {
        PYBIND11_OVERRIDE(
            const mfem::Operator*,
            mfem::Operator,
            GetRestriction
        );
    }

    void PyOperator::RecoverFEMSolution(const mfem::Vector &X, const mfem::Vector &b, mfem::Vector &x) {
        PYBIND11_OVERRIDE(
            void,
            mfem::Operator,
            RecoverFEMSolution,
            X,
            b,
            x
        );
    }

} // namespace serif::pybind::mfem
