__all__ = ['{X}MUMPS_STRUC_C', '{x}mumps_c']

########################################################################
# lib{x}mumps / {x}mumps_c.h wrappers (using Cython)
########################################################################

from libc.stdint cimport uintptr_t
from libc.string cimport strncpy

cdef extern from "{x}mumps_c.h":

    ctypedef int MUMPS_INT

    ctypedef float SMUMPS_COMPLEX
    ctypedef float SMUMPS_REAL

    ctypedef double DMUMPS_COMPLEX
    ctypedef double DMUMPS_REAL

    ctypedef struct mumps_complex:
        float r
        float i
    ctypedef struct mumps_double_complex:
        double r
        double i

    ctypedef mumps_complex CMUMPS_COMPLEX
    ctypedef float CMUMPS_REAL

    ctypedef mumps_double_complex ZMUMPS_COMPLEX
    ctypedef double ZMUMPS_REAL

    char* MUMPS_VERSION

    ctypedef struct c_{X}MUMPS_STRUC_C "{X}MUMPS_STRUC_C":
        MUMPS_INT      sym, par, job
        MUMPS_INT      comm_fortran    # Fortran communicator
        MUMPS_INT      icntl[40]
        {X}MUMPS_REAL  cntl[15]
        MUMPS_INT      n

        # used in matlab interface to decide if we
        # free + malloc when we have large variation
        MUMPS_INT      nz_alloc

        # Assembled entry
        MUMPS_INT        nz
        MUMPS_INT        *irn
        MUMPS_INT        *jcn
        {X}MUMPS_COMPLEX *a

        # Distributed entry
        MUMPS_INT        nz_loc
        MUMPS_INT        *irn_loc
        MUMPS_INT        *jcn_loc
        {X}MUMPS_COMPLEX *a_loc

        # Element entry
        MUMPS_INT        nelt
        MUMPS_INT        *eltptr
        MUMPS_INT        *eltvar
        {X}MUMPS_COMPLEX *a_elt

        # Ordering, if given by user
        MUMPS_INT      *perm_in

        # Orderings returned to user
        MUMPS_INT      *sym_perm    # symmetric permutation
        MUMPS_INT      *uns_perm    # column permutation

        # Scaling (input only in this version)
        {X}MUMPS_REAL    *colsca
        {X}MUMPS_REAL    *rowsca

        # RHS, solution, ouptput data and statistics
        {X}MUMPS_COMPLEX *rhs
        {X}MUMPS_COMPLEX *redrhs
        {X}MUMPS_COMPLEX *rhs_sparse
        {X}MUMPS_COMPLEX *sol_loc
        MUMPS_INT        *irhs_sparse
        MUMPS_INT        *irhs_ptr
        MUMPS_INT        *isol_loc
        MUMPS_INT        nrhs, lrhs, lredrhs, nz_rhs, lsol_loc
        MUMPS_INT        schur_mloc, schur_nloc, schur_lld
        MUMPS_INT        mblock, nblock, nprow, npcol
        MUMPS_INT        info[40]
        MUMPS_INT        infog[40]
        {X}MUMPS_REAL    rinfo[20]
        {X}MUMPS_REAL    rinfog[20]

        # Null space
        MUMPS_INT      deficiency
        MUMPS_INT      *pivnul_list
        MUMPS_INT      *mapping

        # Schur
        MUMPS_INT        size_schur
        MUMPS_INT        *listvar_schur
        {X}MUMPS_COMPLEX *schur

        # Internal parameters
        MUMPS_INT        instance_number
        {X}MUMPS_COMPLEX *wk_user

        char *version_number
        # For out-of-core
        char *ooc_tmpdir
        char *ooc_prefix
        # To save the matrix in matrix market format
        char *write_problem
        MUMPS_INT      lwk_user
    void c_{x}mumps_c "{x}mumps_c" (c_{X}MUMPS_STRUC_C *) nogil

cdef class {X}MUMPS_STRUC_C:
    cdef c_{X}MUMPS_STRUC_C ob

    property sym:
        def __get__(self): return self.ob.sym
        def __set__(self, value): self.ob.sym = value
    property par:
        def __get__(self): return self.ob.par
        def __set__(self, value): self.ob.par = value
    property job:
        def __get__(self): return self.ob.job
        def __set__(self, value): self.ob.job = value

    property comm_fortran:
        def __get__(self): return self.ob.comm_fortran
        def __set__(self, value): self.ob.comm_fortran = value

    property icntl:
        def __get__(self):
            cdef MUMPS_INT[:] view = self.ob.icntl
            return view
    property cntl:
        def __get__(self):
            cdef {X}MUMPS_REAL[:] view = self.ob.cntl
            return view

    property n:
        def __get__(self): return self.ob.n
        def __set__(self, value): self.ob.n = value
    property nz_alloc:
        def __get__(self): return self.ob.nz_alloc
        def __set__(self, value): self.ob.nz_alloc = value

    property nz:
        def __get__(self): return self.ob.nz
        def __set__(self, value): self.ob.nz = value
    property irn:
        def __get__(self): return <uintptr_t> self.ob.irn
        def __set__(self, value): self.ob.irn = <MUMPS_INT*> (<uintptr_t> value)
    property jcn:
        def __get__(self): return <uintptr_t> self.ob.jcn
        def __set__(self, value): self.ob.jcn = <MUMPS_INT*> (<uintptr_t> value)
    property a:
        def __get__(self): return <uintptr_t> self.ob.a
        def __set__(self, value): self.ob.a = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)

    property nz_loc:
        def __get__(self): return self.ob.nz_loc
        def __set__(self, value): self.ob.nz_loc = value
    property irn_loc:
        def __get__(self): return <uintptr_t> self.ob.irn_loc
        def __set__(self, value): self.ob.irn_loc = <MUMPS_INT*> (<uintptr_t> value)
    property jcn_loc:
        def __get__(self): return <uintptr_t> self.ob.jcn_loc
        def __set__(self, value): self.ob.jcn_loc = <MUMPS_INT*> (<uintptr_t> value)
    property a_loc:
        def __get__(self): return <uintptr_t> self.ob.a_loc
        def __set__(self, value): self.ob.a_loc = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)

    property nelt:
        def __get__(self): return self.ob.nelt
        def __set__(self, value): self.ob.nelt = value
    property eltptr:
        def __get__(self): return <uintptr_t> self.ob.eltptr
        def __set__(self, value): self.ob.eltptr = <MUMPS_INT*> (<uintptr_t> value)
    property eltvar:
        def __get__(self): return <uintptr_t> self.ob.eltvar
        def __set__(self, value): self.ob.eltvar = <MUMPS_INT*> (<uintptr_t> value)
    property a_elt:
        def __get__(self): return <uintptr_t> self.ob.a_elt
        def __set__(self, value): self.ob.a_elt = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)

    property perm_in:
        def __get__(self): return <uintptr_t> self.ob.perm_in
        def __set__(self, value): self.ob.perm_in = <MUMPS_INT*> (<uintptr_t> value)

    property sym_perm:
        def __get__(self): return <uintptr_t> self.ob.sym_perm
        def __set__(self, value): self.ob.sym_perm = <MUMPS_INT*> (<uintptr_t> value)
    property uns_perm:
        def __get__(self): return <uintptr_t> self.ob.uns_perm
        def __set__(self, value): self.ob.uns_perm = <MUMPS_INT*> (<uintptr_t> value)

    property colsca:
        def __get__(self): return <uintptr_t> self.ob.colsca
        def __set__(self, value): self.ob.colsca = <{X}MUMPS_REAL*> (<uintptr_t> value)
    property rowsca:
        def __get__(self): return <uintptr_t> self.ob.rowsca
        def __set__(self, value): self.ob.rowsca = <{X}MUMPS_REAL*> (<uintptr_t> value)

    property rhs:
        def __get__(self): return <uintptr_t> self.ob.rhs
        def __set__(self, value): self.ob.rhs = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)
    property redrhs:
        def __get__(self): return <uintptr_t> self.ob.redrhs
        def __set__(self, value): self.ob.redrhs = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)
    property rhs_sparse:
        def __get__(self): return <uintptr_t> self.ob.rhs_sparse
        def __set__(self, value): self.ob.rhs_sparse = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)
    property sol_loc:
        def __get__(self): return <uintptr_t> self.ob.sol_loc
        def __set__(self, value): self.ob.sol_loc = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)


    property irhs_sparse:
        def __get__(self): return <uintptr_t> self.ob.irhs_sparse
        def __set__(self, value): self.ob.irhs_sparse = <MUMPS_INT*> (<uintptr_t> value)
    property irhs_ptr:
        def __get__(self): return <uintptr_t> self.ob.irhs_ptr
        def __set__(self, value): self.ob.irhs_ptr = <MUMPS_INT*> (<uintptr_t> value)
    property isol_loc:
        def __get__(self): return <uintptr_t> self.ob.isol_loc
        def __set__(self, value): self.ob.isol_loc = <MUMPS_INT*> (<uintptr_t> value)

    property nrhs:
        def __get__(self): return self.ob.nrhs
        def __set__(self, value): self.ob.nrhs = value
    property lrhs:
        def __get__(self): return self.ob.lrhs
        def __set__(self, value): self.ob.lrhs = value
    property lredrhs:
        def __get__(self): return self.ob.lredrhs
        def __set__(self, value): self.ob.lredrhs = value
    property nz_rhs:
        def __get__(self): return self.ob.nz_rhs
        def __set__(self, value): self.ob.nz_rhs = value
    property lsol_loc:
        def __get__(self): return self.ob.lsol_loc
        def __set__(self, value): self.ob.lsol_loc = value

    property schur_mloc:
        def __get__(self): return self.ob.schur_mloc
        def __set__(self, value): self.ob.schur_mloc = value
    property schur_nloc:
        def __get__(self): return self.ob.schur_nloc
        def __set__(self, value): self.ob.schur_nloc = value
    property schur_lld:
        def __get__(self): return self.ob.schur_lld
        def __set__(self, value): self.ob.schur_lld = value


    property mblock:
        def __get__(self): return self.ob.mblock
        def __set__(self, value): self.ob.mblock = value
    property nblock:
        def __get__(self): return self.ob.nblock
        def __set__(self, value): self.ob.nblock = value
    property nprow:
        def __get__(self): return self.ob.nprow
        def __set__(self, value): self.ob.nprow = value
    property npcol:
        def __get__(self): return self.ob.npcol
        def __set__(self, value): self.ob.npcol = value

    property info:
        def __get__(self):
            cdef MUMPS_INT[:] view = self.ob.info
            return view
    property infog:
        def __get__(self):
            cdef MUMPS_INT[:] view = self.ob.infog
            return view

    property rinfo:
        def __get__(self):
            cdef {X}MUMPS_REAL[:] view = self.ob.rinfo
            return view
    property rinfog:
        def __get__(self):
            cdef {X}MUMPS_REAL[:] view = self.ob.rinfog
            return view

    property deficiency:
        def __get__(self): return self.ob.deficiency
        def __set__(self, value): self.ob.deficiency = value
    property pivnul_list:
        def __get__(self): return <uintptr_t> self.ob.pivnul_list
        def __set__(self, value): self.ob.pivnul_list = <MUMPS_INT*> (<uintptr_t> value)
    property mapping:
        def __get__(self): return <uintptr_t> self.ob.mapping
        def __set__(self, value): self.ob.mapping = <MUMPS_INT*> (<uintptr_t> value)

    property size_schur:
        def __get__(self): return self.ob.size_schur
        def __set__(self, value): self.ob.size_schur = value
    property listvar_schur:
        def __get__(self): return <uintptr_t> self.ob.listvar_schur
        def __set__(self, value): self.ob.listvar_schur = <MUMPS_INT*> (<uintptr_t> value)
    property schur:
        def __get__(self): return <uintptr_t> self.ob.schur
        def __set__(self, value): self.ob.schur = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)

    property instance_number:
        def __get__(self): return self.ob.instance_number
        def __set__(self, value): self.ob.instance_number = value
    property wk_user:
        def __get__(self): return <uintptr_t> self.ob.wk_user
        def __set__(self, value): self.ob.wk_user = <{X}MUMPS_COMPLEX*> (<uintptr_t> value)

    property version_number:
        def __get__(self):
            return (<bytes> self.ob.version_number).decode('ascii')

    property ooc_tmpdir:
        def __get__(self):
            return (<bytes> self.ob.ooc_tmpdir).decode('ascii')
        def __set__(self, char *value):
            strncpy(self.ob.ooc_tmpdir, value, sizeof(self.ob.ooc_tmpdir))
    property ooc_prefix:
        def __get__(self):
            return (<bytes> self.ob.ooc_prefix).decode('ascii')
        def __set__(self, char *value):
            strncpy(self.ob.ooc_prefix, value, sizeof(self.ob.ooc_prefix))

    property write_problem:
        def __get__(self):
            return (<bytes> self.ob.write_problem).decode('ascii')
        def __set__(self, char *value):
            strncpy(self.ob.write_problem, value, sizeof(self.ob.write_problem))

    property lwk_user:
        def __get__(self): return self.ob.lwk_user
        def __set__(self, value): self.ob.lwk_user = value

def {x}mumps_c({X}MUMPS_STRUC_C s not None):
    with nogil:
        c_{x}mumps_c(&s.ob)

__version__ = (<bytes> MUMPS_VERSION).decode('ascii')
