#include "PyMFEMTrampolines/Operator/Matrix/PyMatrix.h"
#include "mfem.hpp"

namespace serif::pybind {

    // --- Trampolines for new mfem::Matrix pure virtual methods ---

    mfem::real_t& PyMatrix::Elem(int i, int j) {
        PYBIND11_OVERRIDE_PURE(
            mfem::real_t&,   /* Return type */
            mfem::Matrix,    /* C++ base class */
            Elem,            /* C++ function name */
            i,               /* Argument 1 */
            j                /* Argument 2 */
        );
    }

    const mfem::real_t& PyMatrix::Elem(int i, int j) const {
        PYBIND11_OVERRIDE_PURE(
            const mfem::real_t&,
            mfem::Matrix,
            Elem,
            i,
            j
        );
    }

    mfem::MatrixInverse* PyMatrix::Inverse() const {
        PYBIND11_OVERRIDE_PURE(
            mfem::MatrixInverse*,
            mfem::Matrix,
            Inverse
        );
    }

    // --- Trampoline for new mfem::Matrix regular virtual methods ---

    void PyMatrix::Finalize(int skip_zeros) {
        PYBIND11_OVERRIDE(
            void,
            mfem::Matrix,
            Finalize,
            skip_zeros
        );
    }

    // --- Trampolines for inherited mfem::Operator virtual methods ---

    void PyMatrix::Mult(const mfem::Vector &x, mfem::Vector &y) const {
        // This remains PURE as mfem::Matrix does not implement it.
        PYBIND11_OVERRIDE_PURE(
            void,
            mfem::Matrix,
            Mult,
            x,
            y
        );
    }

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

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

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

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

    void PyMatrix::AssembleDiagonal(mfem::Vector &diag) const {
        PYBIND11_OVERRIDE(
            void,
            mfem::Matrix,
            AssembleDiagonal,
            diag
        );
    }

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

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

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

} // namespace serif::pybind
