!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
module cubeadm_import
  use cubetools_structure
  use cubetools_keywordlist_types
  use cubedag_parameters
  use cubedag_link_type
  use cubedag_node_type
  use cubedag_node
  use cubedag_dag
  use cubeadm_messaging
  use cubeadm_directory_type
  use cubeadm_setup
  !
  type(cubedag_link_t) :: im  ! List of imported cubes
  !
  public :: import
  private
  !
  type :: import_comm_t
     type(option_t),      pointer :: comm
     type(option_t),      pointer :: mapping
     type(option_t),      pointer :: class
     type(option_t),      pointer :: optparse
     type(option_t),      pointer :: sort
     type(keywordlist_comm_t), pointer :: sort_arg
     type(option_t),      pointer :: verbose
  contains
     procedure, public  :: register => cubeadm_import_register
     procedure, private :: parse    => cubeadm_import_parse
     procedure, private :: main     => cubeadm_import_main
  end type import_comm_t
  type(import_comm_t) :: import
  !
  integer(kind=code_k), parameter :: sort_none=1
  integer(kind=code_k), parameter :: sort_chro=2
  integer(kind=code_k), parameter :: sort_alph=3
  integer(kind=4), parameter :: nsort=3
  character(len=*), parameter :: sort_names(nsort) = &
    (/ 'NONE         ','CHRONOLOGICAL','ALPHABETICAL ' /)
  !
  type import_user_t
     character(len=file_l), allocatable :: argum(:)
     logical               :: domapping = .false.
     logical               :: doclass   = .false.
     logical               :: doparse   = .false.
     character(len=1)      :: parse_sep = '-'
     logical               :: dosort    = .false.
     integer(kind=code_k)  :: sort      = sort_alph
     logical               :: doverbose = .false.
  end type import_user_t
  !
  ! ZZZ Still missing an import_prog_t
  !
contains
  !
  subroutine cubeadm_import_register(import,error)
    !---------------------------------------------------------------------
    ! 
    !---------------------------------------------------------------------
    class(import_comm_t), intent(inout) :: import
    logical,              intent(inout) :: error
    !
    type(standard_arg_t) :: stdarg
    type(keywordlist_comm_t) :: keyarg
    character(len=*), parameter :: comm_abstract = &
         'Import files into the DAG'
    character(len=*), parameter :: comm_help = &
         'With a file pattern as argument (e.g. raw/*{.lmv|.fits}),&
         & import files using this pattern (pattern is assumed&
         & relative from current directory, if relevant).'&
         & //strg_cr//strg_cr//&
         &'With a&
         & directory name as argument, import all files (*.*, only&
         & Gildas Data Format or FITS format files are imported) from&
         & this directory (no recursion).'&
         & //strg_cr//strg_cr//&
         & 'Without argument, import files from the RAW directory.'
    character(len=*), parameter :: rname='IMPORT>REGISTER'
    !
    call cubeadm_message(admseve%trace,rname,'Welcome')
    !
    call cubetools_register_command(&
         'IMPORT','[Directory|FilePattern]',&
         comm_abstract,&
         comm_help,&
         cubeadm_import_command,&
         import%comm,error)
    if (error) return
    call stdarg%register( &
         'Target',  &
         'Import target, a directory or a File Pattern', &
         strg_id,&
         code_arg_unlimited, &
         error)
    if (error) return
    !
    call cubetools_register_option(&
         'MAPPING','',&
         'Import MAPPING files with flags based on extension',&
         'This option is ignored if the file header provides its own flags.',&
         import%mapping,error)
    if (error) return
    !
    call cubetools_register_option(&
         'CLASS','',&
         'Import CLASS files with flags based on extension',&
         'This option is ignored if the file header provides its own flags.',&
         import%class,error)
    if (error) return
    !
    call cubetools_register_option(&
         'PARSE','Separator',&
         'Split the file base name into family and flags',&
         'The computed flags are ignored if the file header provides its own '//&
         'flags. Without this option, the whole base name is used as family name.',&
         import%optparse,error)
    if (error) return
    call stdarg%register( &
         'Separator',  &
         'Single character separator in file base name', &
         'Default is "-".',&
         code_arg_optional, &
         error)
    if (error) return
    !
    call cubetools_register_option(&
         'SORT','Mode',&
         'Specify the sorting order of imported files',&
         'Without this option, sorting is done in chronological order.',&
         import%sort,error)
    if (error) return
    call keyarg%register( &
         'Mode',  &
         'Sorting mode', &
         strg_id,&
         code_arg_mandatory, &
         sort_names, &
         .not.flexible, &
         import%sort_arg,&
         error)
    if (error) return
    !
    call cubetools_register_option(&
         'VERBOSE','',&
         'Indicate which files are imported or skipped',&
         strg_id,&
         import%verbose,error)
    if (error) return
  end subroutine cubeadm_import_register
  !
  subroutine cubeadm_import_command(line,error)
    !----------------------------------------------------------------------
    !
    !----------------------------------------------------------------------
    character(len=*), intent(in)    :: line
    logical,          intent(inout) :: error
    !
    type(import_user_t) :: user
    character(len=*), parameter :: rname='IMPORT>COMMAND'
    !
    call cubeadm_message(admseve%trace,rname,'welcome')
    !
    call import%parse(line,user,error)
    if (error) return
    call import%main(user,line,error)
    if (error) return
  end subroutine cubeadm_import_command
  !
  subroutine cubeadm_import_parse(comm,line,user,error)
    use gkernel_interfaces
    !---------------------------------------------------------------------
    ! Support routine for command:
    !   IMPORT
    !   IMPORT Directory
    !   IMPORT Pattern
    !---------------------------------------------------------------------
    class(import_comm_t), intent(in)    :: comm
    character(len=*),     intent(in)    :: line
    type(import_user_t),  intent(out)   :: user
    logical,              intent(inout) :: error
    !
    integer(kind=4) :: narg,iarg,ier
    logical :: defaul
    character(len=argu_l) :: argum,key
    character(len=*), parameter :: rname='IMPORT>COMMAND'
    !
    narg = import%comm%getnarg()
    defaul = narg.le.0
    if (defaul) narg = 1
    allocate(user%argum(narg),stat=ier)
    if (failed_allocate(rname,'arguments',ier,error)) return
    if (defaul) then
      user%argum(1) = dir%raw
    else
      do iarg=1,narg
        call cubetools_getarg(line,import%comm,iarg,user%argum(iarg),mandatory,error)
        if (error) return
      enddo
    endif
    !
    call import%mapping%present(line,user%domapping,error)
    if (error) return
    call import%class%present(line,user%doclass,error)
    if (error) return
    call import%optparse%present(line,user%doparse,error)
    if (error) return
    call import%sort%present(line,user%dosort,error)
    if (error) return
    call import%verbose%present(line,user%doverbose,error)
    if (error) return
    !
    if (user%domapping.and.user%doclass) then
       call cubeadm_message(seve%e,rname,'Options /MAPPING and /CLASS conflict with each other')
       error = .true.
       return
    endif
    !
    if (user%doparse) then
      call cubetools_getarg(line,import%optparse,1,user%parse_sep,.not.mandatory,error)
      if (error)  return
    endif
    !
    if (user%dosort) then
      call cubetools_getarg(line,import%sort,1,argum,mandatory,error)
      if (error) return
      call cubetools_keywordlist_user2prog(import%sort_arg,argum,user%sort,key,error)
      if (error) return
    else
      user%sort = sort_chro
    endif
  end subroutine cubeadm_import_parse
  !
  subroutine cubeadm_import_main(import,user,line,error)
    use gkernel_interfaces
    use cubedag_find
    use cubedag_history
    !----------------------------------------------------------------------
    ! Import all arguments passed to the command, create CX, and terminate
    ! command.
    !----------------------------------------------------------------------
    class(import_comm_t), intent(in)    :: import
    type(import_user_t),  intent(in)    :: user
    character(len=*),     intent(in)    :: line
    logical,              intent(inout) :: error
    !
    logical :: do_cx
    integer(kind=4) :: iarg
    type(find_prog_t) :: criter
    type(cubedag_link_t) :: void
    integer(kind=entr_k) :: hid
    character(len=*), parameter :: rname='IMPORT>MAIN'
    !
    do_cx = .false.
    !
    do iarg=1,size(user%argum)
      call cubeadm_import_argument(user,user%argum(iarg),do_cx,error)
      if (error)  return
    enddo
    !
    if (do_cx) then
      ! Implicitly FIND everything in current index
      call criter%ix2cx(error)
      if (error) return
    endif
    !
    ! Insert in history
    call cubedag_history_add_tohx('IMPORT',line,void,im,hid,error)
    if (error) return
    call cubedag_node_history(im,hid,error)
    if (error) return
    !
    call cubeadm_imported_reset()
  end subroutine cubeadm_import_main
  !
  subroutine cubeadm_import_argument(user,argum,do_cx,error)
    use gkernel_interfaces
    !----------------------------------------------------------------------
    ! Process 1 argument passed to the command
    !----------------------------------------------------------------------
    type(import_user_t), intent(in)    :: user
    character(len=*),    intent(in)    :: argum
    logical,             intent(inout) :: do_cx
    logical,             intent(inout) :: error
    !
    integer(kind=4) :: nc
    logical :: skipped
    character(len=*), parameter :: rname='IMPORT>ARGUMENT'
    !
    call cubeadm_message(admseve%trace,rname,'welcome')
    !
    nc = len_trim(argum)
    if (gag_isdir(argum(1:nc)).eq.0) then
       ! A directory
       do_cx = cubset%index%default.eq.code_index_current
       call cubeadm_import_directory(user,argum,nc,error)
    elseif (gag_inquire(argum,nc).eq.0) then
       ! A file. Note it can contain unfriendly characters (space, parentheses, etc).
       do_cx = cubset%index%default.eq.code_index_current
       call cubeadm_import_onefile(user,argum,skipped,error)
    elseif (gag_exists(argum(1:nc))) then
       ! Try a pattern. Unfriendly characters badly supported.
       do_cx = cubset%index%default.eq.code_index_current
       call cubeadm_import_pattern(user,argum,error)
    else
       ! Resolves as nothing in the shell!
       call cubeadm_message(seve%w,rname,'No such file or directory '''//argum(1:nc)//'''')
    endif
    if (error) return
  end subroutine cubeadm_import_argument
  !
  function gag_exists(pattern)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Return .true. if the pattern resolves as some file(s) or
    ! directory(ies) resolved by the shell.
    !-------------------------------------------------------------------
    logical :: gag_exists
    character(len=*), intent(in) :: pattern
    !
    integer(kind=4) :: nfile
    character(len=file_l), allocatable :: filelist(:)
    logical :: error
    !
    gag_exists = .false.
    !
    ! No better way to invoke a subroutine which translates the
    ! shell-dependant syntax (e.g. *, ?, ... for bash). The pattern
    ! is passed "as is":
    !  - exact directory name            => return the same exact name (not its contents)
    !  - exact file name                 => return the same exact name
    !  - wilcarded directory name        => return the expanded directory name (not its contents)
    !  - wilcarded file      name        => return the expanded file name
    !  - exact but non-existent name     => return empty list
    !  - wilcarded but non-existent name => return empty list
    ! (wilcarded combinations on existing material are possible).
    !
    error = .false.
    call gag_directory('.',pattern,filelist,nfile,error)
    if (error) return
    gag_exists = nfile.gt.0
  end function gag_exists
  !
  subroutine cubeadm_import_directory(user,dirname,nc,error)
    !---------------------------------------------------------------------
    ! Import *.* files from a directory into the DAG
    !---------------------------------------------------------------------
    type(import_user_t), intent(in)    :: user
    character(len=*),    intent(in)    :: dirname
    integer(kind=4),     intent(in)    :: nc
    logical,             intent(inout) :: error
    !
    character(len=*), parameter :: rname='IMPORT>DIRECTORY'
    !
    if (dirname(nc:nc).eq.'/') then
      call cubeadm_import_pattern(user,dirname(1:nc)//'*.*',error)
    else
      call cubeadm_import_pattern(user,dirname(1:nc)//'/*.*',error)
    endif
    if (error) return
  end subroutine cubeadm_import_directory
  !
  recursive subroutine cubeadm_import_pattern(user,pattern,error)
    use gkernel_types
    use gkernel_interfaces
    !---------------------------------------------------------------------
    ! Import files given a pattern into the DAG
    !---------------------------------------------------------------------
    type(import_user_t), intent(in)    :: user
    character(len=*),    intent(in)    :: pattern
    logical,             intent(inout) :: error
    !
    integer(kind=4) :: nfile,ifile,nimported,nskipped,nc,myseve
    logical :: skipped
    character(len=file_l), allocatable :: filelist(:)
    character(len=mess_l) :: mess
    type(time_t) :: time
    character(len=*), parameter :: rname='IMPORT>PATTERN'
    !
    ! Get the file names and sorting array
    call gag_directory('.',trim(pattern),filelist,nfile,error)
    if (error) return
    call cubeadm_import_sort(filelist,nfile,user%sort,error)
    if (error)  return
    !
    if (user%doverbose) then
      myseve = seve%i  ! ZZZ Put in a prog_t
    else
      myseve = seve%d
    endif
    !
    call gtime_init(time,nfile,error)
    if (error) return
    !
    ! Import the GDF and FITS files in the DAG
    nimported = 0
    nskipped = 0
    do ifile=1,nfile
      call gtime_current(time)
      nc = len_trim(filelist(ifile))
      if (gag_isdir(filelist(ifile)(1:nc)).eq.0) then
        ! This is a directory. NB: this is not precisely a recursion
        ! as cubeadm_import_directory imports "somedir/*.*"
        call cubeadm_message(myseve,rname,'Importing directory '//filelist(ifile)(1:nc))
        call cubeadm_import_directory(user,filelist(ifile),nc,error)
        if (error) error = .false.  ! Skip errors indexing file
      else
        ! This is not a directory (regular file...)
        call cubeadm_import_onefile(user,filelist(ifile),skipped,error)
        if (error) error = .false.  ! Skip errors indexing file
        if (skipped) then ! Duplicate or not supported kind
          nskipped = nskipped+1
        else
          nimported = nimported+1
        endif
      endif
    enddo
    deallocate(filelist)
    !
    write(mess,'(I0,A,A)')  nimported,' new file(s) imported from ',trim(pattern)
    if (nimported.le.0) then
      myseve = seve%w
    else
      myseve = seve%i
    endif
    if (nskipped.gt.0)  &
      write(mess,'(A,A,I0,A)')  trim(mess),', skipped ',nskipped,' file(s)'
    call cubeadm_message(myseve,rname,mess)
  end subroutine cubeadm_import_pattern
  !
  subroutine cubeadm_import_sort(filelist,nfile,sortmode,error)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Sort the file-list in-place according to sorting mode
    !-------------------------------------------------------------------
    integer(kind=4),      intent(in)    :: nfile
    character(len=*),     intent(inout) :: filelist(nfile)
    integer(kind=code_k), intent(in)    :: sortmode
    logical,              intent(inout) :: error
    !
    integer(kind=4) :: ifile,ier,nc
    integer(kind=4), allocatable :: sort(:)
    character(len=file_l), allocatable :: tmp(:)
    integer(kind=8), allocatable :: mtime(:)
    character(len=*), parameter :: rname='IMPORT>GETSORT'
    !
    nc = len(filelist(1))
    !
    select case (sortmode)
    case (sort_none)
      return
      !
    case (sort_chro)
      ! Get the file dates
      allocate(mtime(nfile))
      do ifile=1,nfile
        ier = gag_mtime(filelist(ifile),mtime(ifile))
        if (ier.ne.0) then
          call cubeadm_message(seve%w,rname,'Error evaluating date of file '//filelist(ifile))
          mtime(ifile) = 0
        endif
      enddo
      ! Compute sorting array
      allocate(sort(nfile))
      call gi8_trie(mtime,sort,nfile,error)
      if (error)  return
      deallocate(mtime)
      ! Sort the character array
      allocate(tmp(nfile))
      call gch_sort(filelist,tmp,sort,nc,nfile)
      deallocate(sort,tmp)
      !
    case (sort_alph)
      allocate(sort(nfile))
      call gch_trie(filelist,sort,nfile,nc,error)
      if (error)  return
      deallocate(sort)
    end select
  end subroutine cubeadm_import_sort
  !
  subroutine cubeadm_import_onefile(user,filename,skipped,error)
    use gkernel_interfaces
    !-------------------------------------------------------------------
    ! Try to import the named file
    !-------------------------------------------------------------------
    type(import_user_t), intent(in)    :: user
    character(len=*),    intent(in)    :: filename
    logical,             intent(out)   :: skipped
    logical,             intent(inout) :: error
    !
    integer(kind=4) :: myseve,nc,filekind
    character(len=*), parameter :: rname='IMPORT>ONEFILE'
    !
    if (user%doverbose) then
      myseve = seve%i  ! ZZZ Put in a prog_t
    else
      myseve = seve%d
    endif
    nc = len_trim(filename)
    !
    call gag_file_guess(rname,filename,filekind,error)
    if (error) error = .false.  ! Skip errors indexing file
    !
    if (filekind.eq.1 .or. filekind.eq.2) then
      call cubeadm_import_onecube(user,filename(1:nc),skipped,error)
      if (error)  return
    else
      call cubeadm_message(myseve,rname,  &
        'Skipping non-GDF/non-FITS file '//filename(1:nc))
      skipped = .true.
    endif
  end subroutine cubeadm_import_onefile
  !
  subroutine cubeadm_import_onecube(user,filename,skipped,error)
    use gkernel_interfaces
    use cube_types
    use cubedag_allflags
    use cubedag_tuple
    use cubeio_file
    use cubetuple_format
    use cubetuple_uv
    use cubeadm_engine_types
    use cubeadm_cubeid_types
    use cubeadm_setup
    !---------------------------------------------------------------------
    !
    !---------------------------------------------------------------------
    type(import_user_t), intent(in)    :: user
    character(len=*),    intent(in)    :: filename
    logical,             intent(out)   :: skipped
    logical,             intent(inout) :: error
    !
    character(len=base_l) :: filebase,cubeid
    type(flag_t), allocatable :: baseflags(:),extflags(:),flags(:)
    type(flag_t) :: noflag(0)
    character(len=exte_l) :: fileext
    integer(kind=4) :: pos,myseve
    integer(kind=code_k) :: code_ftype
    type(cubeio_file_t), pointer :: file
    type(cube_t), pointer :: cube
    class(format_t), pointer :: fo
    class(cubedag_node_object_t), pointer :: dno
    logical :: defaul
    character(len=*), parameter :: rname='IMPORT>ONECUBE'
    !
    if (user%doverbose) then
      myseve = seve%i  ! ZZZ Put in a prog_t
    else
      myseve = seve%d
    endif
    !
    skipped = .true.
    !
    if (cubedag_dag_contains(filename)) then
      call cubeadm_message(myseve,rname,  &
        'Skipping file already in DAG '//filename)
      return
    endif
    !
    ! A word on flags associated to the imported cube. They can have
    ! several origins:
    ! 1 -  Reading the file header (CUBE writes FITS with dedicated
    !      keywords). It has precedence if available.
    ! 2a - Parsing the file base name (IMPORT /PARSE) for symetry with
    !      EXPORT,
    ! 2b - Parsing the file extention (IMPORT /MAPPING|/CLASS);
    !      2a can be combined with 2b,
    ! 4 -  Some default flag as fallback.
    !
    call sic_parse_name(filename,filebase,fileext)
    ! Flags from the basename
    if (user%doparse) then
      pos = index(filebase,user%parse_sep)
      if (pos.gt.0) then
        call cubedag_string_toflaglist(filebase(pos+1:),.true.,baseflags, &
             error,sep=user%parse_sep)
        if (error)  return
        filebase(pos:) = ''  ! Drop the parsed flags
      else
        ! filebase unchanged
        ! baseflags remains unallocated
      endif
    endif
    ! Flags from the extension
    if (user%domapping) then
       call cubedag_mapping_ext2flag(fileext,extflags,error)
       if (error) return
    else if (user%doclass) then
       call cubedag_class_ext2flag(fileext,extflags,error)
       if (error) return
    else
       ! No special flags
    endif
    ! Merge baseflags+extflags
    if (.not.allocated(baseflags))  call cubeadm_import_reallocate_flags(baseflags,noflag,error)
    if (.not.allocated(extflags))   call cubeadm_import_reallocate_flags(extflags,noflag,error)
    if (size(baseflags)+size(extflags).gt.0) then
      defaul = .false.
      call cubeadm_import_reallocate_flags(flags,[baseflags,extflags],error)
      if (error)  return
    else
      defaul = .true.
      ! Some default flag is set, only for feedback. Using 'unknown'
      ! might be misleading, use 'cube'.
      call cubeadm_import_reallocate_flags(flags,[flag_cube],error)
      if (error)  return
    endif
    ! Create family:flags string
    call cubeadm_cubeid_familyflags2string(filebase,flags,cubeid,error)
    if (error) return
    !
    file => file_allocate_new(error)
    if (error) return
    call file%read_header(filename,cubeid,error)
    if (error) return
    !
    cube => null()
    if (file%is_cube()) then
      code_ftype = code_ftype_cube
      cube => cube_allocate_new(cubset,error)
      if (error) return
      fo => cube
      if (defaul) then
        call cubeadm_import_reallocate_flags(flags,[flag_cube],error)
        if (error)  return
      endif
    elseif (file%is_uvt()) then
      code_ftype = code_ftype_uv
      fo => uv_allocate_new(cubset,error)
      if (error) return
      if (defaul) then
        call cubeadm_import_reallocate_flags(flags,[flag_uv,flag_table],error)
        if (error)  return
      endif
    else
      ! Clean before skipping
      call cubeadm_message(myseve,rname,'Skipping non-cube/non-UVT file '//filename)
      call file%close(error)
      call file%free(error)
      deallocate(file)
      return
    endif
    call fo%attach_file(file,error)
    if (error) return
    !
    ! Fix the header, if relevant
    if (associated(cube)) then
      call cube%default_order(error)
      if (error)  return
    endif
    !
    ! Attach a new cube to the DAG and set its attributes
    dno => fo
    call cubedag_dag_newbranch(dno,code_ftype,error)
    if (error) return
    call cubedag_node_set_origin(dno,code_origin_imported,error)
    if (error) return
    if (dno%node%family.ne.'') then
      ! The family name was read from the header: it has precedence
      if (user%doparse) then
        call cubeadm_message(seve%w,rname,  &
          'Family read from header; /PARSE ignored')
      endif
    else
      ! No family yet
      call cubedag_node_set_family(dno,filebase,error)
      if (error) return
    endif
    if (dno%node%flag%n.gt.0) then
      ! Some flags were read from the header: they have precedence
      if (size(baseflags).gt.0 .or. size(extflags).gt.0) then
        call cubeadm_message(seve%w,rname,  &
          'Flags read from header; /PARSE, /MAPPING, or /CLASS ignored')
      endif
    else
      ! No flags yet
      call cubedag_node_set_flags(dno,flags,error)
      if (error) return
    endif
    call cubedag_tuple_upsert(fo%node%tuple,fo%order(),code_buffer_disk,filename,error)
    if (error) return
    !
    ! Need some cleaning. At least the GIO slots. We could go through
    ! the cubeadm_finish_all at the end of the command execution, but
    ! IMPORT can open hundreds of cubes, and GIO slots are more limited
    ! than this. We have to avoid accumulating them:
    call file%close(error)
    if (error) return
    !
    call cubeadm_imported_add(dno)
    !
    call cubeadm_message(myseve,rname,'Importing file '//filename)
    skipped = .false.
    !
  end subroutine cubeadm_import_onecube
  !
  subroutine cubeadm_import_reallocate_flags(list,flags,error)
    use gkernel_interfaces
    use cubedag_flag
    !-------------------------------------------------------------------
    ! Ad-hoc subroutine which reallocates and stores a list of flags
    !-------------------------------------------------------------------
    type(flag_t), allocatable   :: list(:)
    type(flag_t), intent(in)    :: flags(:)
    logical,      intent(inout) :: error
    !
    integer(kind=4) :: nflags,ier
    character(len=*), parameter :: rname='IMPORT>REALLOCATE>FLAGS'
    !
    if (allocated(list))  deallocate(list)
    nflags = size(flags)
    allocate(list(nflags),stat=ier)  ! Size can be 0 on purpose
    if (failed_allocate(rname,'flags',ier,error)) return
    if (nflags.gt.0)  list(:) = flags(:)
  end subroutine cubeadm_import_reallocate_flags
  !
  subroutine cubeadm_imported_add(dno)
    class(cubedag_node_object_t), pointer :: dno
    logical :: error
    error = .false.
    call im%reallocate(im%n+1,error)
    im%n = im%n+1
    im%list(im%n)%p => dno
    im%flag(im%n) = 0
  end subroutine cubeadm_imported_add
  !
  subroutine cubeadm_imported_reset()
    logical :: error
    error = .false.
    call im%final(error)
  end subroutine cubeadm_imported_reset
  !
end module cubeadm_import
!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
