!
!  Oak Leaf
!
!  Copyright © 2001 - 2018 F.Hroch (hroch@physics.muni.cz)
!
!  This file is part of OakLeaf.
!
!  OakLeaf 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.
!
!  OakLeaf 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 OakLeaf.  If not, see <http://www.gnu.org/licenses/>.
!
!

module oakleaf

  use iso_fortran_env
  use rfun
  use likescale
  use medians
  use madmean
  use quantilmean
  use fluxmean
  use robustline

  implicit none
  public

  interface rmean
     module procedure rmean_real64, rmean_real32, rwmean_real32, rwmean_real64
  end interface rmean

  private :: rmean_real32, rmean_real64, rwmean_real32, rwmean_real64

contains


  subroutine rmean_real32(data,mean,stderr,stdsig,scale,reliable,flag,verbose)

    ! this single precision interface, via double precision,
    ! is a little bit slower, than genuine single one,
    ! although no code is doubled.

    use robustmean

    real, dimension(:),intent(in) :: data
    real, intent(out) :: mean
    real, intent(out), optional :: stderr,stdsig,scale
    logical, intent(out), optional :: reliable
    integer, intent(out), optional :: flag
    logical, intent(in), optional :: verbose

    real(REAL64), dimension(:), allocatable :: x
    real(REAL64) :: t,s,dt,c
    integer :: iflag
    logical :: reli

    allocate(x(size(data)))
    x = data
    if( present(verbose) ) then
       call rmean_estimator(x,t,dt,s,c,reli,iflag,verbose)
    else
       call rmean_estimator(x,t,dt,s,c,reli,iflag)
    end if
    deallocate(x)
    mean = real(t)
    if( present(stderr) ) stderr = real(dt)
    if( present(stdsig) ) stdsig = real(s)
    if( present(scale) )  scale =  real(c)
    if( present(reliable) ) reliable = reli
    if( present(flag) ) flag = iflag

  end subroutine rmean_real32

  subroutine rmean_real64(data,mean,stderr,stdsig,scale,reliable,flag,verbose)

    use robustmean

    real(REAL64), dimension(:),intent(in) :: data
    real(REAL64), intent(out) :: mean
    real(REAL64), intent(out), optional :: stderr,stdsig,scale
    logical, intent(out), optional :: reliable
    integer, intent(out), optional :: flag
    logical, intent(in), optional :: verbose

    real(REAL64) :: t,s,dt,c
    integer :: iflag
    logical :: reli

    if( present(verbose) ) then
       call rmean_estimator(data,t,dt,s,c,reli,iflag,verbose)
    else
       call rmean_estimator(data,t,dt,s,c,reli,iflag)
    end if
    mean = t
    if( present(stderr) ) stderr = dt
    if( present(stdsig) ) stdsig = s
    if( present(scale) )  scale = c
    if( present(reliable) ) reliable = reli
    if( present(flag) ) flag = iflag

  end subroutine rmean_real64

  subroutine rwmean_real32(data,errors,mean,stderr,stdsig,scale, &
       reliable,flag,verbose)

    ! single precision version

    use weightedmean

    real, dimension(:),intent(in) :: data, errors
    real, intent(out) :: mean
    real, intent(out), optional :: stderr, stdsig, scale
    logical, intent(out), optional :: reliable
    integer, intent(out), optional :: flag
    logical, intent(in), optional :: verbose

    real(REAL64) :: t,dt,s,c
    real(REAL64), dimension(:), allocatable :: x,dx
    integer :: iflag, stat
    logical :: reli
    character(len=80) :: errmsg

    allocate(x(size(data)),dx(size(errors)),stat=stat,errmsg=errmsg)
    if( stat /= 0 ) then
       write(error_unit,*) 'rwmean_real32: ',trim(errmsg)
       if( present(reliable) ) reliable = .false.
       return
    end if

    x = data
    dx = errors

    if( present(verbose) ) then
       call rwmean_estimator(x,dx,t,dt,s,c,reli,iflag,verbose)
    else
       call rwmean_estimator(x,dx,t,dt,s,c,reli,iflag)
    end if

    mean = real(t)
    if( present(stderr) ) stderr = real(dt)
    if( present(stdsig) ) stdsig = real(s)
    if( present(scale) )  scale =  real(c)
    if( present(reliable) ) reliable = reli
    if( present(flag) )     flag = iflag

  end subroutine rwmean_real32

  subroutine rwmean_real64(data,errors,mean,stderr,stdsig,scale, &
       reliable,flag,verbose)

    use weightedmean

    real(REAL64), dimension(:),intent(in) :: data, errors
    real(REAL64), intent(out) :: mean
    real(REAL64), intent(out), optional :: stderr, stdsig, scale
    logical, intent(out), optional :: reliable
    integer, intent(out), optional :: flag
    logical, intent(in), optional :: verbose

    real(REAL64) :: t,dt,s,c
    integer :: iflag
    logical :: reli

    if( present(verbose) ) then
       call rwmean_estimator(data,errors,t,dt,s,c,reli,iflag,verbose)
    else
       call rwmean_estimator(data,errors,t,dt,s,c,reli,iflag)
    end if

    mean = t
    if( present(stderr) )     stderr = dt
    if( present(stdsig) )     stdsig = s
    if( present(scale) )       scale =  c
    if( present(reliable) ) reliable = reli
    if( present(flag) )         flag = iflag

  end subroutine rwmean_real64

end module oakleaf
