module gmath_interfaces_private
  interface
    subroutine gr4_load(in,out,n,bval,eval,m)
      use gildas_def
      !---------------------------------------------------------------------
      ! @ private
      ! Copy input array into output array, but remove blanked values if
      ! any. Return the number of elements kept accordingly. Real*4 version.
      !---------------------------------------------------------------------
      integer(kind=size_length), intent(in)  :: n       ! Number of elements to copy
      real(kind=4),              intent(in)  :: in(n)   ! Input array
      real(kind=4),              intent(out) :: out(n)  ! Output array
      real(kind=4),              intent(in)  :: bval    ! Blanking value
      real(kind=4),              intent(in)  :: eval    ! Error value for blanking
      integer(kind=size_length), intent(out) :: m       ! Number elements kept
    end subroutine gr4_load
  end interface
  !
  interface
    subroutine gr8_load(in,out,n,bval,eval,m)
      use gildas_def
      !---------------------------------------------------------------------
      ! @ private
      ! Copy input array into output array, but remove blanked values if
      ! any. Return the number of elements kept accordingly. Real*8 version.
      !---------------------------------------------------------------------
      integer(kind=size_length), intent(in)  :: n       !
      real(kind=8),              intent(in)  :: in(n)   !
      real(kind=8),              intent(out) :: out(n)  !
      real(kind=8),              intent(in)  :: bval    !
      real(kind=8),              intent(in)  :: eval    !
      integer(kind=size_length), intent(out) :: m       !
    end subroutine gr8_load
  end interface
  !
  interface
    subroutine fit_message(fit,mseve,rname,message)
      use fit_minuit
      !---------------------------------------------------------------------
      ! @ private
      !  Print messages as usual, but they are owned by fit%owner, i.e.
      ! the message filter rules are those of the owner, not those of gmath
      ! ---
      !  Private to this file (i.e. to be used by MINUIT fitting routines
      ! only).
      !---------------------------------------------------------------------
      type(fit_minuit_t), intent(in) :: fit      !
      integer(kind=4),    intent(in) :: mseve    ! Message severity
      character(len=*),   intent(in) :: rname    ! Calling routine name
      character(len=*),   intent(in) :: message  !
    end subroutine fit_message
  end interface
  !
  interface
    subroutine derive(fit,gg,gg2,fcn)
      use fit_minuit
      !----------------------------------------------------------------------
      ! @ private
      ! Internal routine
      !      Calculates the first derivatives of FCN (GG),
      !      either by finite differences or by transforming the user-
      !      supplied derivatives to internal coordinates,
      !      according to whether ISW(3) is zero or one.
      !      if ISW(3) = 0, an error estimate GG2  is available
      !
      !      External routine FCN added to allow use of various
      !      minimization functions.
      !----------------------------------------------------------------------
      type(fit_minuit_t), intent(inout) :: fit        !
      real(kind=8),       intent(inout) :: gg(ntot)   ! First derivatives of function FCN
      real(kind=8),       intent(out)   :: gg2(nvar)  ! Error estimate for variables
      external                          :: fcn        ! Function to minimise
    end subroutine derive
  end interface
  !
  interface
    subroutine fixpar(fit,i2,kode,ilax)
      use gbl_message
      use fit_minuit
      !----------------------------------------------------------------------
      ! @ private
      ! MINUIT      Internal routine
      !      Removes parameter I2 from the internal (variable) parameter
      !      list, and arranges the rest of the list to fill the hole.
      !      If KODE=0, I2 is an external number, otherwise internal.
      !      ILAX is returned as the external number of the parameter.
      !----------------------------------------------------------------------
      type(fit_minuit_t), intent(inout) :: fit   !
      integer(kind=4),    intent(in)    :: kode  ! Indicates Internal (1) or External (0)
      integer(kind=4),    intent(in)    :: i2    ! Internal or external parameter number
      integer(kind=4),    intent(out)   :: ilax  ! External number
    end subroutine fixpar
  end interface
  !
  interface
    subroutine razzia(fit,ynew,pnew,ier)
      use gbl_message
      use fit_minuit
      !----------------------------------------------------------------------
      ! @ private
      ! MINUIT      Internal routine
      !      Called only by SIMPLEX (and IMPROV) to add a new point
      !      and remove an old one from the current simplex, and get the
      !      estimated distance to minimum.
      !----------------------------------------------------------------------
      type(fit_minuit_t), intent(inout) :: fit         !
      real(kind=8),       intent(in)    :: ynew        !
      real(kind=8),       intent(in)    :: pnew(nvar)  !
      integer(kind=4),    intent(out)   :: ier         !
    end subroutine razzia
  end interface
  !
  interface
    subroutine restor(fit,k)
      use gbl_message
      use fit_minuit
      !----------------------------------------------------------------------
      ! @ private
      ! MINUIT      Internal routine
      !      Restores a fixed parameter to variable status
      !      by inserting it into the internal parameter list at the
      !      appropriate place.
      !
      !       K = 0 means restore all parameters
      !       K = 1 means restore the last parameter fixed
      !       K = -I means restore external parameter I (if possible)
      !       IQ = fix-location where internal parameters were stored
      !       IR = external number of parameter being restored
      !       IS = internal number of parameter being restored
      !----------------------------------------------------------------------
      type(fit_minuit_t), intent(inout) :: fit  !
      integer(kind=4),    intent(in)    :: k    ! Code for operation
    end subroutine restor
  end interface
  !
  interface
    subroutine vermin(fit,a,l,m,n,ifail)
      use fit_minuit
      !----------------------------------------------------------------------
      ! @ private
      ! MINUIT      Internal routine
      !      Inverts a symmetric matrix.   Matrix is first scaled to
      !      have all ones on the diagonal (equivalent to change of units)
      !      but no pivoting is done since matrix is positive-definite.
      !----------------------------------------------------------------------
      type(fit_minuit_t), intent(in)    :: fit     !
      integer(kind=4),    intent(in)    :: l       ! 1st dim of matrix A
      integer(kind=4),    intent(in)    :: m       ! 2nd dim of matrix A
      integer(kind=4),    intent(in)    :: n       !
      real(kind=8),       intent(inout) :: a(l,m)  ! Matrix to be inverted
      integer(kind=4),    intent(out)   :: ifail   ! Error code
    end subroutine vermin
  end interface
  !
  interface
    subroutine fft1d(data,n,isign,m,xr,xi)
      !---------------------------------------------------------------------
      ! @ private-mandatory (because of explicit renaming elsewhere)
      ! Transformee de Fourier               Pierre Duhamel
      !
      ! Ce sous-programme calcule la transformee de Fourier directe
      ! (ISIGN=-1) ou inverse (ISIGN=1) du tableau complexe DATA de
      ! dimension N=2**M (n doit etre compris entre 8 et 2**mmax et etre
      ! une puissance de 2)
      !---------------------------------------------------------------------
      complex(kind=4), intent(inout) :: data(*)  !
      integer(kind=4), intent(in)    :: n        !
      integer(kind=4), intent(in)    :: isign    !
      integer(kind=4), intent(in)    :: m        !
      real(kind=4)                   :: xr(*)    !
      real(kind=4)                   :: xi(*)    !
    end subroutine fft1d
  end interface
  !
  interface
    subroutine fft2d(data,dim1,dim2,isign,m1,m2,xr,xi,mm)
      !---------------------------------------------------------------------
      ! @ private-mandatory (because of explicit renaming elsewhere)
      ! Joue le meme role que Fourt : Pas de Normalisation.
      !
      ! If Signe=-1 Then
      !       Direct Fourier Transform
      ! Else
      !       Inverse Fourier Transform
      !---------------------------------------------------------------------
      integer(kind=4), intent(in)    :: dim1             !
      integer(kind=4), intent(in)    :: dim2             !
      complex(kind=4), intent(inout) :: data(dim1,dim2)  !
      integer(kind=4), intent(in)    :: isign            !
      integer(kind=4), intent(in)    :: m1               !
      integer(kind=4), intent(in)    :: m2               !
      integer(kind=4), intent(in)    :: mm               !
      real(kind=4)                   :: xr(mm)           !
      real(kind=4)                   :: xi(mm)           !
    end subroutine fft2d
  end interface
  !
  interface
    subroutine fftcfr(xr,xi,m,n)
      !---------------------------------------------------------------------
      ! @ private
      ! FFT de sequence complexe (xr + j*xi) de taille 2**m
      !
      ! Algorithme SRFFT, version rapide, qui necessite donc un appel
      ! de INIFFT , et decimation en frequences (les rearrangements sont a
      ! effectuer apres appel a la FFT)
      !
      !  Un algorithme de transformation de Fourier rapide a double base.
      !    Pierre DUHAMEL
      !  Annales des teleommunications, tome 40, n! 9-10, sept-oct 1985
      !---------------------------------------------------------------------
      real(kind=4)                 :: xr(*)  !
      real(kind=4)                 :: xi(*)  !
      integer(kind=4), intent(in)  :: m      !
      integer(kind=4), intent(in)  :: n      !
    end subroutine fftcfr
  end interface
  !
  interface
    subroutine inifft(ind,m,n)
      !---------------------------------------------------------------------
      ! @ private
      !  Precalcul des cos, debuts de blocs et bit-reversal
      !
      !  Sous programme a appeler avant utilisation des versions rapides.
      ! Il est commun a toutes les versions, et un seul appel a INIFFT est
      ! necessaire.
      !
      ! Taille memoire requise :
      !         w1c     :       nmax/4
      !         w3c     :       nmax/4
      !         jx0     :       nmax/3
      !         BITREV  :       nmax
      !                      ---------
      !         total   :    11*nmax/6
      !---------------------------------------------------------------------
      integer(kind=4), intent(out) :: ind(*)  !
      integer(kind=4), intent(in)  :: m       !
      integer(kind=4), intent(in)  :: n       !
    end subroutine inifft
  end interface
  !
  interface
    subroutine fourct(data,nn,ndim,isign,iform,work)
      !---------------------------------------------------------------------
      ! @ private-mandatory (because symbol is used elsewhere)
      ! Cooley-Tukey Fast Fourier Transform
      !
      ! If the data is of type Real (IFORM=0), the imaginary part should be
      ! set to 0. WORK should be dimensioned to twice the largest dimension
      ! which is not a power of 2. It can be replaced by 0 if all dimensions
      ! are powers of 2.
      !
      ! The FT are not normalized in the standard way. If a Direct FT is
      ! performed, then an Inverse FT on the result, the original data is
      ! multiply by the size of the data (product of all dimensions).
      !----------------------------------------------------------------------
      real(kind=4),    intent(inout) :: data(*)  ! Complex array of data
      integer(kind=4), intent(in)    :: nn(*)    ! Dimensions of data array
      integer(kind=4), intent(in)    :: ndim     ! Number of dimensions
      integer(kind=4), intent(in)    :: isign    ! Sign of FT (-1 Direct, 1 Inverse)
      integer(kind=4), intent(in)    :: iform    ! Type of data (0 Real, 1 Complex)
      real(kind=4)                   :: work(*)  ! Work space
    end subroutine fourct
  end interface
  !
  interface
    subroutine gmath_message(mkind,procname,message)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Messaging facility for the current library. Calls the low-level
      ! (internal) messaging routine with its own identifier.
      !---------------------------------------------------------------------
      integer,          intent(in) :: mkind     ! Message kind
      character(len=*), intent(in) :: procname  ! Name of calling procedure
      character(len=*), intent(in) :: message   ! Message string
    end subroutine gmath_message
  end interface
  !
  interface
    subroutine gi4_quicksort_array(array,work,index,n,error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Reorder an integer(4) array by increasing order using the sorted
      ! index computed by gi4_quicksort_index
      !---------------------------------------------------------------------
      integer(kind=4), intent(in)    :: n         ! Length of arrays
      integer(kind=4), intent(inout) :: array(n)  ! Array
      integer(kind=4), intent(inout) :: work(n)   ! Work space
      integer(kind=4), intent(in)    :: index(n)  ! index array
      logical,         intent(out)   :: error     ! Error status
    end subroutine gi4_quicksort_array
  end interface
  !
  interface
    subroutine gmath_random_seed_datetime(error)
      !---------------------------------------------------------------------
      ! @ private
      !  (Re)set the Fortran random seed, based on current date and time
      !  Based on Gfortran online help
      !---------------------------------------------------------------------
      logical, intent(inout) :: error  !
    end subroutine gmath_random_seed_datetime
  end interface
  !
  interface
    subroutine gmath_random_seed_urandom(error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      !  (Re)set the Fortran random seed, based on the OS random generator
      ! (if any)
      !---------------------------------------------------------------------
      logical, intent(inout) :: error  !
    end subroutine gmath_random_seed_urandom
  end interface
  !
  interface
    subroutine gmath_random_seed_value(argum,error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      !  (Re)set the Fortran random seed by using the caller input value,
      ! so that the seed and the random number sequence will be the same
      ! for an identical value.
      !---------------------------------------------------------------------
      character(len=*), intent(in)    :: argum  !
      logical,          intent(inout) :: error  !
    end subroutine gmath_random_seed_value
  end interface
  !
  interface
    subroutine gmath_random_seed_print(error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Print the current Fortran random seed
      !---------------------------------------------------------------------
      logical, intent(inout) :: error  !
    end subroutine gmath_random_seed_print
  end interface
  !
  interface
    subroutine transpose_check(code,error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Check that the input code is correct, i.e. check:
      !  - code too large (unsupported number of dimensions)
      !  - illegal characters (e.g. letters)
      !  - correct numbering (each dimension must be present once and only
      !    once)
      !---------------------------------------------------------------------
      character(len=*), intent(in)    :: code   !
      logical,          intent(inout) :: error  !
    end subroutine transpose_check
  end interface
  !
  interface
    subroutine transpose_repack(start,goal,repack)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      !   Compute the repack array for the 'goal' starting from 'start'
      !   Note that there is no assumption on the order of the start code
      ! (in particular you can not assume it is '1234567'). This is a
      ! desired feature to call consecutively this subroutine to achieve the
      ! goal in several steps.
      !   Note also that there no assumption on the characters it contains,
      ! e.g. if you plan to modify this code, think on what should be done
      ! if start='baefdcg' and goal='bedgafc'
      !---------------------------------------------------------------------
      character(len=*), intent(inout) :: start      ! Updated on return
      character(len=*), intent(in)    :: goal       !
      integer(kind=4),  intent(out)   :: repack(5)  ! How the dimensions should be packed
    end subroutine transpose_repack
  end interface
  !
  interface
    subroutine transpose_guess(code)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      !  Give users the serie of permutations needed to achieve the goal.
      ! Note that each user permutation must be given from '1234567' to
      ! 'intermediate-goal', e.g. 2143 = 2134 + 1243
      !---------------------------------------------------------------------
      character(len=*), intent(in) :: code
    end subroutine transpose_guess
  end interface
  !
  interface
    subroutine transposition_repack_to_code(repack,code)
      !---------------------------------------------------------------------
      ! @ private
      !  Generate the transposition code from the repack array
      !---------------------------------------------------------------------
      integer(kind=4),  intent(in)  :: repack(5)  !
      character(len=*), intent(out) :: code       !
    end subroutine transposition_repack_to_code
  end interface
  !
  interface
    subroutine gwavelet_mirror(nvec,vec1,vec2,error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Double the size of a vector, fill the central part with the initial
      ! vector and fill the left and right part with mirror versions of the
      ! initial vector.
      ! On return the vec2 array has been allocated and filled
      !---------------------------------------------------------------------
      integer(kind=4),           intent(in)    :: nvec       ! Data size
      real(kind=4),              intent(in)    :: vec1(nvec) ! Data
      real(kind=4), allocatable, intent(inout) :: vec2(:)    ! Results
      logical,                   intent(inout) :: error      ! Logical error flag
    end subroutine gwavelet_mirror
  end interface
  !
  interface
    subroutine gwavelet_extract(nvec,nwav,wavelets2,wavelets1,error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Extract the central part of a wavelet array
      ! On return the wavelet1 array has been allocated and filled
      !---------------------------------------------------------------------
      integer(kind=4),           intent(in)    :: nvec                   ! Data size
      integer(kind=4),           intent(in)    :: nwav                   ! Number of wavelets
      real(kind=4),              intent(in)    :: wavelets2(2*nvec,nwav) ! Data
      real(kind=4), allocatable, intent(inout) :: wavelets1(:,:)         ! Results
      logical,                   intent(inout) :: error                  ! Logical error flag
    end subroutine gwavelet_extract
  end interface
  !
  interface
    subroutine gwavelet_gaps_sub(vec,vsize,wavelets,nwav,error)
      use gbl_message
      !---------------------------------------------------------------------
      ! @ private
      ! Compute and modify inplace the wavelets for input 1D data
      ! On return the input wavelets array has been allocated and filled
      !---------------------------------------------------------------------
      integer(kind=4),           intent(in)    :: vsize          ! Vector size
      real(kind=4),              intent(inout) :: vec(vsize)     ! Data / working buffer
      real(kind=4), allocatable, intent(inout) :: wavelets(:,:)  ! Results
      integer(kind=4),           intent(out)   :: nwav           ! Number of wavelets in working buffer
      logical,                   intent(inout) :: error          ! Logical error flag
    end subroutine gwavelet_gaps_sub
  end interface
  !
  interface
    subroutine gwavelet_gaps_prepare(vsize,fw,nwav)
      !---------------------------------------------------------------------
      ! @ private
      ! Compute the number of wavelets which will be needed
      !---------------------------------------------------------------------
      integer(kind=4), intent(in)  :: vsize  ! Data size
      integer(kind=4), intent(in)  :: fw     ! Filter width
      integer(kind=4), intent(out) :: nwav   ! Number of wavelets
    end subroutine gwavelet_gaps_prepare
  end interface
  !
  interface
    subroutine gwavelet_gaps_compute(vec,vsize,f1,fw1,nwav,wav,error)
      !---------------------------------------------------------------------
      ! @ private
      ! Compute the wavelets
      !---------------------------------------------------------------------
      integer(kind=4), intent(in)    :: vsize            ! Data size
      real(kind=4),    intent(inout) :: vec(vsize)       ! Data / working buffer
      integer(kind=4), intent(in)    :: fw1              ! Original filter width
      real(kind=4),    intent(in)    :: f1(fw1)          ! Original filter
      integer(kind=4), intent(in)    :: nwav             ! Number of wavelets
      real(kind=4),    intent(out)   :: wav(vsize,nwav)  ! Wavelets on return
      logical,         intent(inout) :: error            ! Logical error flag
    end subroutine gwavelet_gaps_compute
  end interface
  !
  interface
    subroutine gwavelet_convolve(din,dout,dsize,kern,ksize)
      !---------------------------------------------------------------------
      ! @ private
      ! 1D convolution
      ! This version is optimized for convolution kernels which have
      ! 0-valued elements.
      !---------------------------------------------------------------------
      integer(kind=4), intent(in)  :: dsize        ! Data size
      real(kind=4),    intent(in)  :: din(dsize)   ! Data in
      real(kind=4),    intent(out) :: dout(dsize)  ! Data out
      integer(kind=4), intent(in)  :: ksize        ! Kernel size
      real(kind=4),    intent(in)  :: kern(ksize)  ! Kernel
    end subroutine gwavelet_convolve
  end interface
  !
end module gmath_interfaces_private
