module cubetools_disambiguate
  use cubetools_parameters
  use cubetools_messaging
  !
  public :: cubetools_disambiguate_strict,cubetools_disambiguate_flexible,cubetools_disambiguate_toupper
  public :: cubetools_find_key
  private
  !
contains
  !
  subroutine cubetools_disambiguate_toupper(anycase,uppercase,error)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Shift anycase to uppercase
    !-------------------------------------------------------------------
    character(len=*),      intent(in)    :: anycase
    character(len=*),      intent(out)   :: uppercase
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='DISAMBIGUATE>TOUPPER'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    uppercase = anycase
    call sic_upper(uppercase)
  end subroutine cubetools_disambiguate_toupper
  !
  subroutine cubetools_disambiguate_list(cname,list,error)
    !-------------------------------------------------------------------
    ! List available keywords
    !-------------------------------------------------------------------
    character(len=*),      intent(in)    :: cname
    character(len=*),      intent(in)    :: list(:)
    logical,               intent(inout) :: error
    !
    character(len=mess_l) :: mess
    integer(kind=4) :: ikey,n
    character(len=*), parameter :: rname='DISAMBIGUATE>LIST'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    n = size(list)
    call cubetools_message(seve%r,cname,'  Available options are:')
    do ikey=1,n
       if (ikey.eq.1) then
          write (mess,'(4x,a)') trim(list(ikey))
       else if (ikey.eq.n) then
          write (mess,'(3a)') trim(mess),' and ',trim(list(ikey))
       else
          write (mess,'(3a)') trim(mess),', ',trim(list(ikey))
       endif
    enddo
    call cubetools_message(seve%r,cname,mess)
    error = .true.
  end subroutine cubetools_disambiguate_list
  !
  subroutine cubetools_disambiguate_sub(cname,keyword,list,ikey,solved,error)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Turns inputs into upper case, then calls sic_ambigs
    !-------------------------------------------------------------------
    character(len=*),      intent(in)    :: cname
    character(len=*),      intent(in)    :: keyword
    character(len=*),      intent(in)    :: list(:)
    integer(kind=4),       intent(out)   :: ikey
    character(len=*),      intent(out)   :: solved
    logical,               intent(inout) :: error
    !
    integer(kind=4) :: nlist,list_l,str_l,ier,iwrd
    character(len=:),allocatable :: upper,upperlist(:)
    character(len=*), parameter :: rname='DISAMBIGUATE>SUB'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    nlist = size(list)
    str_l = len(keyword)
    list_l = len(list)
    allocate(character(len=str_l)::upper,stat=ier)
    if (failed_allocate(rname,'Upper case string',ier,error)) return
    allocate(character(len=list_l)::upperlist(nlist),stat=ier)
    if (failed_allocate(rname,'Upper case strings',ier,error)) return
    !
    call cubetools_disambiguate_toupper(keyword,upper,error)
    if (error) return
    do iwrd = 1,nlist
       call cubetools_disambiguate_toupper(list(iwrd),upperlist(iwrd),error)
       if (error) return
    enddo
    call sic_ambigs_sub(rname,upper,solved,ikey,upperlist,nlist,error)
    if (error) return
  end subroutine cubetools_disambiguate_sub
  
  subroutine cubetools_disambiguate_strict(keyword,list,ikey,solved,error)
    !-------------------------------------------------------------------
    ! Resolve a keyword returning ikey and the solved keyword and
    ! raising an error if word is not found in list
    !-------------------------------------------------------------------
    character(len=*),      intent(in)    :: keyword
    character(len=*),      intent(in)    :: list(:)
    integer(kind=4),       intent(out)   :: ikey
    character(len=*),      intent(out)   :: solved
    logical,               intent(inout) :: error
    !
    
    character(len=*), parameter :: rname='DISAMBIGUATE>STRICT'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    call cubetools_disambiguate_sub(rname,keyword,list,ikey,solved,error)
    if (error) return
    if (ikey.lt.1) then
       call cubetools_message(seve%e,rname,'Unknown keyword '//trim(keyword))
       call cubetools_disambiguate_list(rname,list,error)
       if (error) return
    endif
  end subroutine cubetools_disambiguate_strict
  !
  subroutine cubetools_disambiguate_flexible(keyword,list,ikey,solved,error)
    !-------------------------------------------------------------------
    ! Resolve a keyword returning ikey and the solved keyword and
    ! *NOT* raising an error if word is not found in list
    !-------------------------------------------------------------------
    character(len=*),      intent(in)    :: keyword
    character(len=*),      intent(in)    :: list(:)
    integer(kind=4),       intent(out)   :: ikey
    character(len=*),      intent(out)   :: solved
    logical,               intent(inout) :: error
    !
    character(len=*), parameter :: rname='DISAMBIGUATE>FLEXIBLE'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    call cubetools_disambiguate_sub(rname,keyword,list,ikey,solved,error)
    if (error) return
    if (ikey.lt.1) then
       ikey = code_unresolved
       solved = strg_unresolved
    endif
  end subroutine cubetools_disambiguate_flexible
  !
  subroutine cubetools_find_key(keyword,list,okey,error)
    !-------------------------------------------------------------------
    ! Find if the input key is present in the list. The search is
    ! case-sensitive and not disambiguated. Return code_unresolved if
    ! not found.
    !
    ! Typical use-case is physical units:
    !   mJy is not the same as MJy (i.e. case-sensitive), and
    !   MJy is not the same as MJy/sr (no disambiguisation)
    !-------------------------------------------------------------------
    character(len=*), intent(in)    :: keyword
    character(len=*), intent(in)    :: list(:)
    integer(kind=4),  intent(out)   :: okey
    logical,          intent(inout) :: error
    !
    integer(kind=4) :: ikey
    character(len=*), parameter :: rname='FIND>KEY'
    !
    call cubetools_message(toolseve%trace,rname,'Welcome')
    !
    do ikey=1,size(list)
      if (list(ikey).eq.keyword) then
        okey = ikey
        return
      endif
    enddo
    okey = code_unresolved
  end subroutine cubetools_find_key
  !
end module cubetools_disambiguate
