!------------------------------------------------------------------------------
!
! MODULE: HS2Kinds
!
!------------------------------------------------------------------------------

MODULE HS2Kinds
  USE ISO_FORTRAN_ENV, ONLY: INT8, INT16, INT32, INT64
  USE ISO_FORTRAN_ENV, ONLY: REAL32, REAL64, REAL128
  IMPLICIT NONE
  PUBLIC

  INTEGER, PARAMETER :: I4B = INT32
  INTEGER, PARAMETER  :: SP = REAL32
  INTEGER, PARAMETER  :: DP = REAL64
  INTEGER, PARAMETER  :: QP = REAL128
END MODULE HS2Kinds

!------------------------------------------------------------------------------
!
! MODULE: HS2Ode
!
!------------------------------------------------------------------------------

MODULE HS2ODE
  USE HS2Kinds
  IMPLICIT NONE
  PRIVATE

  PUBLIC :: HSODE, HSODESolver


  TYPE :: HSODE(kind)
     INTEGER(I4B), KIND :: kind = DP

     REAL(kind) :: xi
   CONTAINS
     GENERIC :: start => startq, startd, starts
     PROCEDURE, PASS :: startq
     PROCEDURE, PASS :: startd
     PROCEDURE, PASS :: starts
  END TYPE HSODE


  TYPE :: HSODESolver(kind)
     INTEGER(I4B), KIND :: kind = DP
   CONTAINS
     GENERIC :: solve => solverq, solverd, solvers
     PROCEDURE, PASS :: solverq
     PROCEDURE, PASS :: solverd
     PROCEDURE, PASS :: solvers
  END TYPE HSODESolver



CONTAINS
  !----------------------------------------------------------------------------
  !
  ! Implementation of HSODE
  !
  PURE SUBROUTINE startq(this, xi)
    USE HS2Kinds, ONLY: XP => QP
    CLASS(HSODE(XP)), INTENT(IN) :: this
    REAL(XP), INTENT(OUT)        :: xi

    xi = this%xi
    RETURN
  END SUBROUTINE startq

  PURE SUBROUTINE startd(this, xi)
    USE HS2Kinds, ONLY: XP => DP
    CLASS(HSODE(XP)), INTENT(IN) :: this
    REAL(XP), INTENT(OUT)        :: xi

    xi = this%xi
    RETURN
  END SUBROUTINE startd

  PURE SUBROUTINE starts(this, xi)
    USE HS2Kinds, ONLY: XP => SP
    CLASS(HSODE(XP)), INTENT(IN) :: this
    REAL(XP), INTENT(OUT)        :: xi

    xi = this%xi
    RETURN
  END SUBROUTINE starts


  !----------------------------------------------------------------------------
  !
  ! Implementation of HSODESolver
  !
  SUBROUTINE solverq(this, ODE, ystart)
    USE HS2Kinds, ONLY: XP => QP
    CLASS(HSODESolver(XP)), INTENT(INOUT) :: this
    CLASS(HSODE(XP)), INTENT(INOUT)       :: ODE
    REAL(XP), DIMENSION(:), INTENT(INOUT) :: ystart

    REAL(XP) :: xi

    CALL ODE%start(xi)
  END SUBROUTINE solverq

  SUBROUTINE solverd(this, ODE, ystart)
    USE HS2Kinds, ONLY: XP => DP
    CLASS(HSODESolver(XP)), INTENT(INOUT) :: this
    CLASS(HSODE(XP)), INTENT(INOUT)       :: ODE
    REAL(XP), DIMENSION(:), INTENT(INOUT) :: ystart

    REAL(XP) :: xi

    CALL ODE%start(xi)
  END SUBROUTINE solverd

  SUBROUTINE solvers(this, ODE, ystart)
    USE HS2Kinds, ONLY: XP => SP
    CLASS(HSODESolver(XP)), INTENT(INOUT) :: this
    CLASS(HSODE(XP)), INTENT(INOUT)       :: ODE
    REAL(XP), DIMENSION(:), INTENT(INOUT) :: ystart

    REAL(XP) :: xi

    CALL ODE%start(xi)
  END SUBROUTINE solvers
END MODULE HS2ODE


PROGRAM dt
  use HS2Kinds
  USE HS2ODE

  !REAL(DP) :: x1
  !TYPE(HSODE(DP)) :: ode
  !
  !ode%xi = 1.0_DP
  !CALL ode%start(x1)

  WRITE(*,*) "Does not compile"
END PROGRAM dt
