module coolprop_mod
  ! List of DLL interface definitions: [1]
  ! [1] http://www.coolprop.org/_static/doxygen/html/_cool_prop_lib_8h.html#a4564f1d68573e96636ef87371c0f06a0
  use, intrinsic :: iso_c_binding, only: c_char, c_double, c_int, c_null_char
  use, intrinsic :: iso_fortran_env, only: REAL32, REAL64
  implicit none
  
  integer, parameter :: wp = REAL64

  interface
    real(c_double) function PropsSI_i(output,name1,prop1,name2,prop2,ref) bind(C,name='PropsSI')
      use, intrinsic :: iso_c_binding, only: c_char, c_double
      character(kind=c_char), intent(in) :: output(*)
      character(kind=c_char), intent(in) :: name1(*)
      real(c_double), value :: prop1
      character(kind=c_char), intent(in) :: name2(*)
      real(c_double), value :: prop2
      character(kind=c_char), intent(in) :: ref(*)
    end function PropsSI_i

    integer(c_int) function set_reference_stateD_i(ref,T,rhomolar,hmolar0,smolar0) bind(C,name='set_reference_stateD')
      use, intrinsic :: iso_c_binding, only: c_char, c_double, c_int
      character(kind=c_char), intent(in) :: ref
      ! THIS WAS WRONG:   character(len=*,kind=c_char), intent(in) :: ref
      real(c_double), value :: T, rhomolar, hmolar0, smolar0
    end function set_reference_stateD_i
  end interface

contains
  real(wp) function cp_value(output,name1,prop1,name2,prop2,ref)
    use, intrinsic :: ieee_arithmetic, only: ieee_is_normal

    character(*), intent(in) :: output
    character(*), intent(in) :: name1, name2
    real(wp), intent(in) :: prop1, prop2
    character(*), intent(in) :: ref
    
    character(:,kind=c_char), allocatable :: c_output, c_name1, c_name2, c_ref
    
    c_output = trim(output) // c_null_char
    c_name1 = trim(name1) // c_null_char
    c_name2 = trim(name2) // c_null_char
    c_ref = trim(ref) // c_null_char
    cp_value = PropsSI_i(c_output,c_name1,real(prop1,c_double),c_name2,real(prop2,c_double),c_ref)
    if (.not.ieee_is_normal(cp_value)) error stop 'CP: non-normal value'
  end function cp_value

  subroutine set_reference_state(ref,T,rhomolar,hmolar0,smolar0)
    character(*), intent(in) :: ref
    real(wp), intent(in) :: T, rhomolar, hmolar0, smolar0

    ! An over-sized non-allocatable string would also be fine:
    ! character(len=1000,kind=c_char) :: c_ref
    character(:,kind=c_char), allocatable :: c_ref
    integer(c_int) :: export_code

    c_ref = trim(ref) // c_null_char
    export_code = set_reference_stateD_i(                &
        c_ref,real(T,c_double),real(rhomolar,c_double),  & 
        real(hmolar0,c_double),real(smolar0,c_double)    &
    )
    if (export_code /= 0_c_int) error stop 'export_code /= 0'
  end subroutine set_reference_state
end module coolprop_mod


program test_cp
  use coolprop_mod
  implicit none

  real(wp) ::  ref_temperature, ref_pressure, ref_rhomolar

  ref_temperature = 308.0_wp
  ref_pressure = 8.0e+06_wp
  ref_rhomolar = cp_value('DMOLAR','T',ref_temperature,'P',ref_pressure,'CO2')

  ! The call to 'set_reference_state' seems to have no effect.
  ! The output is always '347560.340103337'.
  call set_reference_state('CO2',ref_temperature,ref_rhomolar,hmolar0=0.0_wp,smolar0=0.0_wp)
  print *, cp_value('HMASS','T',ref_temperature,'P',ref_pressure,'CO2')
end program test_cp
