!-----------------------------------------------------------------------
! First in this file, the subroutines which interact with the SIC
! symbols table. Then, the generic subroutines with interact with any
! symbol dictionary.
!-----------------------------------------------------------------------
!
subroutine sic_setsymbol(symb,tran,error)
  use gbl_message
  use sic_interfaces, except_this=>sic_setsymbol
  use sic_dictionaries
  use sic_interactions
  !---------------------------------------------------------------------
  ! @ public
  !   Add a new entry in the SIC symbol table
  !---------------------------------------------------------------------
  character(len=*), intent(in)  :: symb   ! Symbol name
  character(len=*), intent(in)  :: tran   ! Symbol translation
  logical,          intent(out) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SYMBOL'
  !
  if (.not.loaded) then
    call sic_message(seve%e,rname,'SIC is not loaded')
    error = .true.
    return
  endif
  !
  call sic_symdict_set(symbols,symb,tran,error)
  if (error)  return
  !
  error = .false.
  !
end subroutine sic_setsymbol
!
subroutine sic_getsymbol(symb,tran,error)
  use sic_interfaces, except_this=>sic_getsymbol
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ public-mandatory (because symbol is used elsewhere)
  ! Get a symbol definition from the SIC symbol table
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: symb   ! Symbol name
  character(len=*), intent(out)   :: tran   ! Symbol translation
  logical,          intent(inout) :: error  ! Logical error flag
  !
  call sic_symdict_get(symbols,symb,tran,error)
  if (error)  return
  !
end subroutine sic_getsymbol
!
subroutine sic_delsymbol(symb,error)
  use sic_interfaces, except_this=>sic_delsymbol
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! Remove a symbol from the SIC symbol table
  !---------------------------------------------------------------------
  character(len=*), intent(in)    :: symb   ! Symbol name
  logical,          intent(inout) :: error  ! Logical error flag
  !
  call sic_symdict_del(symbols,symb,error)
  if (error)  return
  !
end subroutine sic_delsymbol
!
subroutine sic_inisymbol(error)
  use sic_interfaces, except_this=>sic_inisymbol
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! Initialize the SIC symbol table
  !---------------------------------------------------------------------
  logical, intent(inout) :: error  ! Logical error flag
  !
  call sic_symdict_init(symbols,maxsym,error)
  !
end subroutine sic_inisymbol
!
subroutine sic_freesymbol(error)
  use sic_interfaces, except_this=>sic_freesymbol
  use sic_dictionaries
  !---------------------------------------------------------------------
  ! @ private
  ! Clean the SIC symbol table
  !---------------------------------------------------------------------
  logical, intent(inout) :: error  ! Logical error flag
  !
  call sic_symdict_free(symbols,error)
  !
end subroutine sic_freesymbol
!
!-----------------------------------------------------------------------
! Below this point, all the generic subroutines which work on any
! dictionary of type 'sic_symdict_t'
!-----------------------------------------------------------------------
!
subroutine sic_symdict_init(dict,msym,error)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_symdict_init
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  !  Initialize any dictionary of type 'sic_symdict_t'
  !---------------------------------------------------------------------
  type(sic_symdict_t), intent(out)   :: dict   !
  integer(kind=4),     intent(in)    :: msym   ! Maximum number of elements
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SYMBOL'
  integer(kind=4) :: ier
  !
  allocate(dict%name(msym),    &
           dict%trans(msym),   &
           dict%ltrans(msym),  &
           dict%pn(msym),stat=ier)
  if (ier.ne.0) then
    call sic_message(seve%e,rname,'Failed to allocate symbol arrays')
    error = .true.
    return
  endif
  !
  call gag_hasini(msym,dict%pf,dict%pn)
  !
  dict%msym = msym
  !
end subroutine sic_symdict_init
!
subroutine sic_symdict_free(dict,error)
  use gbl_message
  use sic_interfaces, except_this=>sic_symdict_free
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  ! Clean any dictionary of type 'sic_symdict_t'
  !---------------------------------------------------------------------
  type(sic_symdict_t), intent(inout) :: dict   !
  logical,             intent(inout) :: error  !
  ! Local
  character(len=*), parameter :: rname='SYMBOL'
  integer(kind=4) :: ier
  !
  dict%msym = 0
  !
  deallocate(dict%name,    &
             dict%trans,   &
             dict%ltrans,  &
             dict%pn,stat=ier)
  if (ier.ne.0) then
    call sic_message(seve%e,rname,'Failed to deallocate symbol arrays')
    error = .true.
    return
  endif
  !
end subroutine sic_symdict_free
!
subroutine sic_symdict_set(dict,symb,tran,error)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_symdict_set
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  !  Add a new entry in the input symbol dictioanry
  !---------------------------------------------------------------------
  type(sic_symdict_t), intent(inout) :: dict   !
  character(len=*),    intent(in)    :: symb   ! Symbol name
  character(len=*),    intent(in)    :: tran   ! Symbol translation
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SYMBOL'
  character(len=symbol_length) :: name
  integer(kind=4) :: lt,in,ier,kname,kstar
  character(len=message_length) :: mess
  !
  ! Define abbreviation
  lt = len_trim(tran)
  if (lt.gt.translation_length) then
    call sic_message(seve%e,rname,'Symbol definition too long')
    error = .true.
    return
  endif
  !
  ! Insert or replace in symbol dictionnary
  kstar = index(symb,'*')
  if (kstar.ne.0) then
    kstar = kstar-1
    name = symb(1:kstar)//symb(kstar+2:)
    kname = len_trim(symb)-1  ! Length of 'symb' (less the wilcard) for length check below
  else
    name = symb
    kname = len_trim(symb)  ! Length of 'symb' for length check below
  endif
  call sic_upper(name)
  !
  ! Reject symbols larger than symbol_length (should have been truncated
  ! before if required), not taking into account the wildcard
  if (kname.gt.symbol_length) then
    write(mess,'(A,A,A,I2,A)') "Symbol name '",name,  &
      "' too long (max ",symbol_length," chars)"
    call sic_message(seve%e,rname,mess)
    error = .true.
    return
  endif
  !
10 continue
  ier = gag_hasins(dict%msym,dict%pf,dict%pn,dict%name,name(1:kname),in)
  if (ier.eq.0) then
    call sic_message(seve%e,rname,'Invalid symbol name '//name)
    error = .true.
    return
  elseif (ier.eq.2) then
    call sic_message(seve%e,rname,'Too many symbols')
    error = .true.
    return
  endif
  !
  ! Put into symbol table
  dict%trans(in) = tran
  dict%ltrans(in) = lt
  !
  ! Loop if a stared symbol was used
  kname = kname-1
  if (kname.ge.kstar .and. kstar.ne.0) goto 10
  !
end subroutine sic_symdict_set
!
subroutine sic_symdict_get(dict,symb,tran,error)
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_symdict_get
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  ! Get a symbol definition
  !---------------------------------------------------------------------
  type(sic_symdict_t), intent(inout) :: dict   !
  character(len=*),    intent(in)    :: symb   ! Symbol name
  character(len=*),    intent(out)   :: tran   ! Symbol translation
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=symbol_length) :: name
  integer(kind=4) :: in,ier
  !
  name = symb
  call sic_upper(name)
  ier = gag_hasfin(dict%msym,dict%pf,dict%pn,dict%name,name,in)
  if (ier.ne.1) then
    error = .true.
  else
    tran = dict%trans(in)(1:dict%ltrans(in))
  endif
  !
end subroutine sic_symdict_get
!
subroutine sic_symdict_del(dict,symb,error)
  use gbl_message
  use sic_dependencies_interfaces
  use sic_interfaces, except_this=>sic_symdict_del
  use sic_types
  !---------------------------------------------------------------------
  ! @ private
  ! Remove a symbol from the input dictionary
  !---------------------------------------------------------------------
  type(sic_symdict_t), intent(inout) :: dict   !
  character(len=*),    intent(in)    :: symb   ! Symbol name
  logical,             intent(inout) :: error  ! Logical error flag
  ! Local
  character(len=*), parameter :: rname='SYMBOL'
  integer(kind=4) :: kstar,kname,ier
  character(len=symbol_length) :: name
  !
  kstar = index(symb,'*')
  if (kstar.ne.0) then
    kstar = kstar-1
    name = symb(1:kstar)//symb(kstar+2:)
  else
    name = symb
  endif
  call sic_upper(name)
  kname = len_trim(name)
  !
20 ier = gag_hasdel(dict%msym,dict%pf,dict%pn,dict%name,name(1:kname))
  if (ier.ne.1) then
    call sic_message(seve%e,rname,'Undefined symbol '//name)
    error = .true.
  endif
  !
  ! Loop if a stared symbol was used
  kname = kname-1
  if (kname.ge.kstar .and. kstar.ne.0) goto 20
  !
end subroutine sic_symdict_del
