module test_mod

  use iso_fortran_env, only : output_unit

  implicit none

  private

  type, public :: test_type

    private

    integer, allocatable :: foo(:)

  contains

    private

    !> @brief Document in the type declaration
    !> @details No good as there are no arguments here. If they are documented
    !>          as here they show up as documented but none existant. If they
    !>          are not, then they are not.
    !>
    !>          Regardless the documentation is separate from the
    !>          implementation.
    !> @param teapot Some argument.
    !>
    procedure, public :: wobble
    procedure, public :: wubble
    generic,   public :: wibble => wibble_integer, wibble_real

    !> @brief One aspect of wibble
    !> @details I can document this here but it should really appear under
    !>          "wibble". After all, it is private and not part of the
    !>          API.
    !>
    procedure wibble_integer
    procedure wibble_real

    final :: destroy_test

  end type test_type

  interface test_type
    procedure create_test_default
    !> @brief Specific initialiser
    !> @details Will this how up? No it will not.
    procedure create_test_specific
  end interface test_type

contains

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> @brief Default initialiser
  !>
  !> @details It would be nice to document this here but it wont show up.
  !>
  function create_test_default() result(new_test)

    implicit none

    type(test_type) :: new_test

    allocate( new_test%foo(10) )

  end function create_test_default

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  function create_test_specific( tally ) result(new_test)

    implicit none

    integer, intent(in) :: tally

    type(test_type) :: new_test

    allocate( new_test%foo(tally) )

  end function create_test_specific

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> @brief Destructor.
  !> @details Would prefer to document this here.
  !>
  subroutine destroy_test( this )

    implicit none

    type(test_type), intent(inout) :: this

    deallocate( this%foo )

  end subroutine destroy_test

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> @brief A more sensible place to document.
  !> @details But it does not appear.
  !> @param teapot Some other argument.
  !>
  subroutine wobble( this, teapot )

    implicit none

    class(test_type), intent(in) :: this
    integer,          intent(in) :: teapot

    write( output_unit, '("wobble ", I0)' ) teapot

  end subroutine wobble

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  subroutine wubble( this, cheese )

    implicit none

    class(test_type), intent(in) :: this
    integer,          intent(in) :: cheese

    write( output_unit, '("wubble ", I0)' ) cheese

  end subroutine wubble

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  subroutine wibble_integer( this, value )

    implicit none

    class(test_type), intent(inout) :: this
    integer,         intent(in) :: value

    write( output_unit, '("wibble ", I0)' ) value

  end subroutine wibble_integer

  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  !> @brief Again I would like to document this here.
  !> @details But again it will not show up.
  !> @param value A floating point argument.
  !>
  subroutine wibble_real( this, value )

    implicit none

    class(test_type), intent(inout) :: this
    real,            intent(in) :: value

    write( output_unit, '("wibble ", F14.4)' ) value

  end subroutine wibble_real

end module test_mod
