! stubs for serial build

!  Copyright (C) 2017 The authors of Py-ChemShell
!
!  This file is part of Py-ChemShell.
!
!  Py-ChemShell is free software: you can redistribute it and/or modify
!  it under the terms of the GNU Lesser General Public License as
!  published by the Free Software Foundation, either version 3 of the
!  License, or (at your option) any later version.
!
!  Py-ChemShell 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 Lesser General Public License for more details.
!
!  You should have received a copy of the GNU Lesser General Public
!  License along with Py-ChemShell.  If not, see
!  <http://www.gnu.org/licenses/>.

module ChemShellParallelModule

    use iso_c_binding

    implicit none

    private

    integer :: mpi_comm_workgroup, mpi_comm_counterparts
    integer :: nWorkgroups, nProcs, workgroupSize
    integer :: myWorldRank, myWorkgroup, myWorkgroupRank
  
    type parallelType
        integer, public  :: nprocs         =  1
        integer, public  :: nnodes_subset  =  1
        integer, public  :: rank           =  0
        integer, public  :: nworkgroups    =  1
        integer, public  :: workgroup      =  0
        integer, public  :: node_subset    =  0
        integer, public  :: node           =  0
        integer, public  :: comm_workgroup =  0
        integer, public  :: comm_node      = -1
        integer, public  :: comm_subset    =  0
        integer, public  :: null           = -1
        integer, public  :: debug          = -1
        contains
        generic, public :: broadcast   => private_broadcastScalar, &
                                          private_broadcastOneDim, &
                                          private_broadcastTwoDim
        generic, public :: send        => private_sendScalar, &
                                          private_sendOneDim, &
                                          private_sendTwoDim
        generic, public :: receive     => private_receiveScalar, &
                                          private_receiveOneDim, &
                                          private_receiveTwoDim
        procedure, public         :: init        => private_function
        procedure, public         :: initialise  => private_function
        procedure, public         :: finalise    => private_function
        procedure, public         :: print       => private_function
        procedure, public         :: summarise   => private_function
        procedure, public         :: sync        => private_function
        procedure, public         :: synchronise => private_function
        procedure, nopass, public :: is_root
        procedure, nopass, public :: is_subset
        procedure, nopass, public :: is_taskfarmed
        procedure, nopass, public :: is_parallel
        procedure, nopass, public :: exec_function
        procedure, nopass, public :: get_function_handle
        procedure, private        :: private_broadcastScalar
        procedure, private        :: private_broadcastOneDim
        procedure, private        :: private_broadcastTwoDim
        procedure, private        :: private_sendScalar
        procedure, private        :: private_sendOneDim
        procedure, private        :: private_sendTwoDim
        procedure, private        :: private_receiveScalar
        procedure, private        :: private_receiveOneDim
        procedure, private        :: private_receiveTwoDim
        procedure, private        :: private_function
    endtype parallelType

    type(parallelType), public :: chemsh_parallel

    contains

    logical function is_root() result(result)

        result = .true.

    endfunction is_root
    logical function is_subset() result(result)

        result = .true.

    endfunction is_subset
    logical function is_taskfarmed() result(result)

        result = .false.

    endfunction is_taskfarmed
    integer function private_function(this, arg) result(result)

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in), optional :: arg

        result = 0

    endfunction private_function
    integer function private_broadcastScalar(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf, lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_broadcastScalar
    integer function private_broadcastOneDim(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf(:), lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_broadcastOneDim
    integer function private_broadcastTwoDim(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf(:,:), lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_broadcastTwoDim
    integer function private_sendScalar(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf, lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_sendScalar
    integer function private_sendOneDim(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf(:), lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_sendOneDim
    integer function private_sendTwoDim(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf(:,:), lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_sendTwoDim
    integer function private_receiveScalar(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf, lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_receiveScalar
    integer function private_receiveOneDim(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf(:), lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_receiveOneDim
    integer function private_receiveTwoDim(this, buf, lenbuf, root, dummy) result(ierror)

        implicit none

        class(parallelType), intent(in)           :: this
        class(*)           , intent(in)           :: buf(:,:), lenbuf, root
        class(*)           , intent(in), optional :: dummy
        
        ierror = 0
        
    endfunction private_receiveTwoDim
    integer(c_int) function create_python_result(dummy) result(ierror) bind(c)

        implicit none

        integer(c_int), intent(in) :: dummy
    
        ierror = 0
    
    endfunction create_python_result
    integer(c_int) function synchronise_python_object(dummyObj, dummyEntry) result(ierror) bind(c)

        implicit none

        integer(c_int), intent(in) :: dummyObj, dummyEntry
    
        ierror = 0
    
    endfunction synchronise_python_object
    integer(c_int) function synchronise_python_result(dummy) result(ierror) bind(c)

        implicit none

        integer(c_int), intent(in) :: dummy
    
        ierror = 0
    
    endfunction synchronise_python_result
    integer(c_int) function clean_python_result() result(ierror) bind(c)

        implicit none

        ierror = 0
    
    endfunction clean_python_result
    integer(c_int) function initialise_parallel(ChemShell_debug) result(ierror) bind(c, name="chemsh_parallel_f_initialise")
    
        implicit none
    
        integer, intent(in), value :: ChemShell_debug
    
        ierror = 0
    
    endfunction initialise_parallel
    integer(c_int) function finalise_parallel() result(ierror) bind(c, name="chemsh_parallel_f_finalise")

        implicit none

        ierror = 0

    endfunction finalise_parallel
    integer(c_int) function get_function_handle(func_pointer) result(handle)

        type(c_funptr), value :: func_pointer

        handle = 0

    endfunction get_function_handle
    integer(c_int) function exec_function(handle, debug) result(ierror)

        integer(c_int), intent(in)           :: handle
        integer(c_int), intent(in), optional :: debug

        ierror = 0

    endfunction exec_function
    ! myWorkgroup
    integer(c_int) function getWG() result(wg) bind(c, name="chemsh_parallel_f_get_wg")

        wg = 0

    endfunction getWG
    ! myWorkgroupRank
    integer(c_int) function getNode() result(node) bind(c, name="chemsh_parallel_f_get_node")

        node = 0

    endfunction getNode
    integer(c_int) function getWGNumNodes() result(result) bind(c, name="chemsh_parallel_f_get_nnodes_wg")

        result = 1

    endfunction getWGNumNodes
    ! number of workgroups
    integer(c_int) function getNumWorkgroups() result(nwgs) bind(c, name="chemsh_parallel_f_get_nwgs")

        nwgs = 1

    endfunction getNumWorkgroups
    ! number of nodes in a workgroup's subset
    integer(c_int) function getSubsetNumNodes() result(result) bind(c, name="chemsh_parallel_f_get_nnodes_subset")

        result = 1

    endfunction getSubsetNumNodes
    ! query ChemShell build
    logical function is_parallel() result(result)
    
        result = .false.
    
    endfunction is_parallel

endmodule ChemShellParallelModule

