!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubetools_unit_arg
  use cubetools_parameters
  use cubesyntax_messaging
  use cubetools_primitive_arg
  use cubetools_structure
  !---------------------------------------------------------------------
  ! Implement the parsing and resolution of a unit argument from a
  ! predefined list of possible units, including support for extra
  ! magnitude factor (k, M, G, etc).
  !    COMMAND Unit
  !---------------------------------------------------------------------
  !
  public :: unit_arg_t
  private
  !
  type, extends(primitive_arg_t) :: unit_arg_t
     integer(kind=4)                    :: nunit
     character(len=unit_l), allocatable :: units(:)
  contains
     procedure :: register       => cubetools_unit_register_arg
     procedure :: print_abstract => cubetools_unit_abstract_arg  ! Overloading. ZZZ Should be renamed 'list'
  end type unit_arg_t
  !
contains
  !
  subroutine cubetools_unit_arg_put(code,arg,error)
    use cubetools_unit_setup
    !-------------------------------------------------------------------
    !
    !-------------------------------------------------------------------
    integer(kind=code_k), intent(in)    :: code
    type(unit_arg_t),     intent(inout) :: arg
    logical,              intent(inout) :: error
    !
    call cubetools_unit_get_list_for_code(code,arg%units,error)
    if (error)  return
    arg%nunit = size(arg%units)
  end subroutine cubetools_unit_arg_put
  !
  !---------------------------------------------------------------------
  !
  subroutine cubetools_unit_register_arg(templatearg,name,abstract,  &
    help,mandat,kind,unitarg,error)
    !-------------------------------------------------------------------
    !
    !-------------------------------------------------------------------
    class(unit_arg_t),    intent(in)    :: templatearg  ! Template
    character(len=*),     intent(in)    :: name
    character(len=*),     intent(in)    :: abstract
    character(len=*),     intent(in)    :: help
    integer(kind=code_k), intent(in)    :: mandat
    integer(kind=code_k), intent(in)    :: kind         ! Unit kind
    type(unit_arg_t),     pointer       :: unitarg
    logical,              intent(inout) :: error
    !
    class(primitive_arg_t), pointer :: actualarg
    character(len=*), parameter :: rname='UNIT>REGISTER>ARG'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    ! Register the primitive parts, and get pointer to the actual object
    ! saved in the parsing structure
    call cubetools_register_primitive_arg(templatearg,name,abstract,help,mandat,actualarg,error)
    if (error) return
    !
    ! Register the extended parts
    select type (actualarg)
    type is (unit_arg_t)
      unitarg => actualarg
      call cubetools_unit_arg_put(kind,unitarg,error)
      if (error) return
    class default
      call cubesyntax_message(seve%e,rname,'Internal error: argument has wrong type')
      error = .true.
      return
    end select
    !
  end subroutine cubetools_unit_register_arg
  !
  subroutine cubetools_unit_abstract_arg(arg,iarg,error)
    use cubetools_terminal_tool
    !-------------------------------------------------------------------
    ! Dedicated subroutine for custom display of unit_arg_t argument
    ! abstract in help (as displayed with question mark)
    !-------------------------------------------------------------------
    class(unit_arg_t),    intent(in)    :: arg
    integer(kind=narg_k), intent(in)    :: iarg
    logical,              intent(inout) :: error
    !
    character(len=mess_l) :: mess
    integer(kind=4) :: ikey
    character(len=*), parameter :: tab = '     '
    character(len=*), parameter :: comma = ','
    logical :: linehead
    character(len=*), parameter :: rname='UNIT>ABSTRACT>ARG'
    !
    ! One line for the generic help:
    call arg%primitive_arg_t%print_abstract(iarg,error)
    if (error) return
    !
    ! One more line for the specific help:
    if (arg%nunit.le.1) then
      mess = tab//'Possible unit (with an optional magnitude prefix like k, M,...) is: '
    else
      mess = tab//'Possible units (with an optional magnitude prefix like k, M,...) are: '
    endif
    do ikey=1,arg%nunit
       if (len_trim(mess)+len_trim(arg%units(ikey)).gt.terminal%width()) then
          call cubesyntax_message(syntaxseve%help,rname,mess)
          linehead = .true.
       else
          linehead = .false.
       endif
       if (linehead) then
          write(mess,'(2a)') tab,arg%units(ikey)
       else
          write(mess,'(A,1X,A)')  trim(mess),arg%units(ikey)
       endif
       if (ikey.le.arg%nunit-2) write(mess,'(2a)') trim(mess),comma
       if (ikey.eq.arg%nunit-1) write(mess,'(2a)') trim(mess),' or'
    enddo
    call cubesyntax_message(syntaxseve%help,rname,mess)
    !
  end subroutine cubetools_unit_abstract_arg
end module cubetools_unit_arg
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubetools_unit_types
  use cubetools_parameters
  use cubetools_unit
  use cubetools_unit_arg
  use cubesyntax_messaging
  !
  public :: unit_comm_t,unit_user_t
  private
  !
  type unit_comm_t
     type(unit_arg_t), pointer :: arg
     integer(kind=code_k)      :: code
   contains
     procedure, public :: register => cubetools_unit_comm_register
     procedure, public :: parse    => cubetools_unit_comm_parse
  end type unit_comm_t
  !
contains
  !
  subroutine cubetools_unit_comm_register(comm,name,code,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    class(unit_comm_t),   intent(inout) :: comm
    character(len=*),     intent(in)    :: name
    integer(kind=code_k), intent(in)    :: code
    logical,              intent(inout) :: error
    !
    type(unit_arg_t) :: unitarg
    character(len=*), parameter :: rname='UNIT>COMM>REGISTER'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    comm%code = code
    call unitarg%register(&
         'UNIT',&
         trim(name)//' unit',&
         strg_id,&
         code_arg_optional,&
         code,&
         comm%arg,&
         error)
    if (error) return
  end subroutine cubetools_unit_comm_register
  !
  subroutine cubetools_unit_comm_parse(comm,line,user,error)
    use cubetools_structure
    !----------------------------------------------------------------------
    ! [unit]
    !----------------------------------------------------------------------
    class(unit_comm_t), intent(in)    :: comm
    character(len=*),   intent(in)    :: line
    type(unit_user_t),  intent(out)   :: user
    logical,            intent(inout) :: error
    !
!!$    logical :: do
!!$    character(len=unit_l) :: unitname
    character(len=*), parameter :: rname='UNIT>COMM>PARSE'
    !
    call cubesyntax_message(syntaxseve%trace,rname,'Welcome')
    !
    !***JP: Here is what I would like to do
!!$ call comm%present(line,do,error)
!!$ if (error) return
!!$ if (do) then
!!$    call comm%get(line,unitname,optional,error)
!!$    if (error) return
!!$    call user%unit%get_from_name(unitname,error)
!!$    if (error) return
!!$ else
!!$    call user%unit%get_from_code(comm%code,error)
!!$    if (error) return
!!$ endif
    !***JP: As I don't know how to do this, I return an error for the moment
    call cubesyntax_message(seve%e,rname,'Do not know yet how to parse a unit argument')
    error = .true.
    return
  end subroutine cubetools_unit_comm_parse  
end module cubetools_unit_types
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
