#undef DEBUG
      module keyvalue_container
      implicit none
      integer,private,parameter::maxstring=120
      integer,private,parameter :: maxfile=10
      integer,private::nfile=0

      integer,private,parameter::maxvar_initialvalue=50

      type var_container
      integer:: maxvar
      integer:: nvar
      character(maxstring)::filename
      integer:: fileid
      character(maxstring),pointer:: vars(:)
      end type var_container

      type(var_container),private:: file_vars(maxfile)

      private:: keyvalue_container_init,keyvalue_container_destructor1

      private:: input_toupper
c=================================================
      contains
c--------------
      subroutine input_toupper(buf)
      implicit none
      character(*) :: buf
      integer:: i,n

      n=len_trim(buf)
      do i=1,n
         if (  ichar(buf(i:i)).ge.ichar('a') .and. 
     i        ichar(buf(i:i)).le.ichar('z')) then
            buf(i:i) = char(ichar(buf(i:i))+ichar('Z')-ichar('z'))
         endif
      enddo
      end subroutine input_toupper

c--------------------------------------------------
      subroutine keyvalue_container_init(n, filename,fileid)
      implicit none
      integer,intent(in):: n
      character(*),optional:: filename
      integer,optional::fileid

      character(55):: this='keyvalue_container::keyvalue_container_init: '

      if (n < 0 .or. n>maxfile ) then
         write(*,*) this, 'error n must be [0:maxfile]'
         stop
      endif

      file_vars(n)%maxvar= maxvar_initialvalue ! default
      file_vars(n)%nvar=0
      file_vars(n)%filename=''
      file_vars(n)%fileid=0
      allocate(file_vars(n)%vars(file_vars(n)%maxvar))

      if (present(filename)) file_vars(n)%filename=filename
      if (present(fileid)) file_vars(n)%fileid=fileid

      end subroutine keyvalue_container_init
c--------------------------------------------------
      subroutine keyvalue_container_destructor1(n)
      implicit none
      integer,intent(in)::n
      
      if (associated(file_vars(n)%vars) )then
         deallocate(file_vars(n)%vars)
      endif

      file_vars(n)%maxvar= maxvar_initialvalue ! default
      file_vars(n)%nvar=0
      file_vars(n)%filename=''
      file_vars(n)%fileid=0

      end subroutine keyvalue_container_destructor1
c--------------------------------------------------
      subroutine keyvalue_container_destructor(filename,fileid)
      implicit none
      character(*),optional:: filename
      integer,optional :: fileid

      integer::i,ifile
      logical::flag

      flag=.false.
      do ifile=1,nfile
         if (present(filename))then
            if (file_vars(ifile)%filename.eq.filename ) then
               flag=.true.
               exit
            endif
         endif
         if (present(fileid))then
            if( file_vars(ifile)%fileid.eq.fileid ) then
               flag=.true.
               exit
            endif
         endif
      enddo
      if (flag) then
c     use ifile
         call keyvalue_container_destructor1(ifile)
      else
c     destruct all
         do i=1,nfile
            call keyvalue_container_destructor1(i)
         enddo
         nfile=0
      endif

      end subroutine keyvalue_container_destructor
c---------------------------------------------------

      subroutine keyvalue_container_addvar(var0,filename,fileid)
      implicit none
      character(*),intent(in)::var0
      character(*),optional:: filename
      integer,optional :: fileid
      character(52)::this='keyvalue_container::keyvalue_container_addvar: '

      character(maxstring)::var
      integer::ifile,ivar
      logical::flag
      character(maxstring),pointer:: tmpvars(:)
      integer::oldsize

      if (len_trim(var0)==0) return

      var = adjustl(var0)
      
      flag=.false.
      do ifile=1,nfile
         if (present(filename)) then
            if (file_vars(ifile)%filename.eq.filename) then
               flag=.true.
               exit
            endif
         endif
         if (present(fileid))then
            if ( file_vars(ifile)%fileid.eq.fileid ) then
               flag=.true.
               exit
            endif
         endif
      enddo 
      if (flag) then            ! found
                                ! use ifile
      else
                                ! next fileid
         nfile=nfile+1
         ifile = nfile
c     boundary check
         if (nfile  > maxfile) then
            write(*,*) this, 'error, increase maxfile'
            stop
         endif

         if (present(filename))then
            call keyvalue_container_init(nfile,filename=filename)
         else if (present(fileid)) then
            call keyvalue_container_init(nfile,fileid=fileid)
         endif

      endif

c     use file_vars(ifile)%????       
      do ivar=1,file_vars(ifile)%nvar
         if (var.eq.file_vars(ifile)%vars(ivar)) then
                                ! found, return
            return
         endif
      enddo
c     not found, add it
      file_vars(ifile)%nvar=file_vars(ifile)%nvar+1
      if ( file_vars(ifile)%nvar > file_vars(ifile)%maxvar ) then
c     increase size
         oldsize = file_vars(ifile)%maxvar 
         allocate( tmpvars( oldsize ) )
         tmpvars(1:oldsize) = file_vars(ifile)%vars(1:oldsize)
         deallocate( file_vars(ifile)%vars )
         file_vars(ifile)%maxvar = file_vars(ifile)%maxvar + 50
         allocate( file_vars(ifile)%vars( file_vars(ifile)%maxvar ) )
         file_vars(ifile)%vars(1:oldsize) = tmpvars(1:oldsize)
         deallocate(tmpvars)
      endif
      file_vars(ifile)%vars( file_vars(ifile)%nvar ) = var
#ifdef DEBUG
      write(*,*)'add ',var
#endif
      end subroutine keyvalue_container_addvar
c---------------

c----------------------------------------------------------
      logical function keyvalue_container_findvar(var0,filename,fileid)
      implicit none
      character(*),intent(in):: var0
      character(*),optional:: filename
      integer,optional:: fileid 

      character(52)::this='keyvalue_container::keyvalue_container_findvar: '

      character(maxstring)::var,vartmp
      integer::ifile,i
      logical::flag

      var = adjustl(var0)
      call input_toupper(var)

      flag=.false.
      do ifile=1,nfile
         if (present(filename))then
            if (file_vars(ifile)%filename.eq.filename ) then
               flag=.true.
               exit
            endif
         endif
         if (present(fileid))then
            if( file_vars(ifile)%fileid.eq.fileid ) then
               flag=.true.
               exit
            endif
         endif
      enddo
      if (.not.flag ) then
         keyvalue_container_findvar = .false.
         return
      endif

c     write(*,*) this,'ifile=',ifile

      do i=1,file_vars(ifile)%nvar
         vartmp= file_vars(ifile)%vars(i) 
         call input_toupper(vartmp)
c     write(*,*) '<',var(:len_trim(var)), '><',vartmp(:len_trim(vartmp)),'>'
         if ( var.eq. vartmp ) then
            keyvalue_container_findvar = .true.
            return
         endif
      enddo

      keyvalue_container_findvar = .false.
      end function keyvalue_container_findvar

c-----------------------------------------------------
      subroutine keyvalue_container_printall()
      integer:: ifile,i
      character(maxstring):: str,str2
      do ifile=1,nfile
         str =  file_vars(ifile)%filename
         do i=1,file_vars(ifile)%nvar
            str2 =  file_vars(ifile)%vars(i)
            write(*,*) str(:len_trim(str)),':',file_vars(ifile)%fileid,':',str2(:len_trim(str2))
         enddo
      enddo

      end subroutine keyvalue_container_printall

      end module keyvalue_container

c++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#if 0
      program main
      use keyvalue_container

      integer :: n,i,ifile
      character(5):: str

      do i=1,101
         write(str,'(i3)') i 
         call keyvalue_container_addvar( str,  fileid=200)
      enddo

      do i=1,201
         write(str,'(i3)') i 
         call keyvalue_container_addvar( str,  fileid=200)
      enddo

c     ifile=1
c     write(*,*) file_vars(ifile)%maxvar, file_vars(ifile)%nvar 
c     do i = 1,file_vars(ifile)%nvar
c     write(*,*) file_vars(ifile)%vars(i)
c     enddo

      write(*,*) keyvalue_container_findvar('200',fileid=200)
      write(*,*) keyvalue_container_findvar('300',fileid=200)

      do i=1,70
         write(str,'(i3)')i 
         call keyvalue_container_addvar( str,  filename='IN')
      enddo

      write(*,*) keyvalue_container_findvar('50',filename='IN')
      write(*,*) keyvalue_container_findvar('300',filename='IN')

      call keyvalue_container_destructor(filename='IN')
      write(*,*) keyvalue_container_findvar('50',filename='IN')

      end program main

#endif
