;+
;
;PROCEDURE:       ESC_TPLOT_RESTORE
;
;PURPOSE:         Restores tplot data, limits, name handles, options, and settings.
;                 All usage is basically idential to the original 'tplot_restore';
;                 however, it can process much faster than when tplot_restore, /append. 
;
;INPUTS:          
;KEYWORDS:
;
; FILENAMES:      File name or array of filenames to create.
;                 If no file name is chosen and "all" keyword is not set,
;                 it will look for and restore a file called saved.tplot.
;
;       ALL:      Restores all *.tplot files in the current directory (or directory specified by "directory" keyword).
;
; DIRECTORY:      Specifies a directory other than the currecnt working dir for loading all tplot files.
;
;    APPEND:      Append saved data to existing tplot variables.
;
;      SORT:      Sort data by time after loading in.
;
; GET_TVARS:      Load tplot_vars structure (the structure containing tplot options and settings
;                 even if such a structure already exists in the current session.
;                 The default is to only load these if no such structure currently exists in the session.
;
; RESTORED_VARNAME: Returns the tplot variable names for the restored data.
;
;TPLOT_NAME:      IF the (array of) tplot name(s) is set, it can only restore the user specified tplot(s).
;
;CREATED BY:      Takuya Hara (ESCAPADE-SDOC) on 2024-05-08.
;
;LAST MODIFICATION:
; $LastChangedBy: hara $
; $LastChangedDate: 2024-06-06 12:18:42 -0700 (Thu, 06 Jun 2024) $
; $LastChangedRevision: 32688 $
; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/tags/spedas_6_1/projects/escapade/misc/esc_tplot_restore.pro $
;
;-
PRO esc_tplot_restore, filenames=filenames, all=all, append=append, sort=sort,$
                       get_tvars=get_tvars, verbose=verbose, restored_varnames=restored_varnames, $
                       directory=directory, tplot_name=tplot_name

  COMPILE_OPT IDL2
  @tplot_com.pro

  tplot_quant__define
  IF KEYWORD_SET(directory) AND ~KEYWORD_SET(all) THEN BEGIN
     dprint, dlevel=0, 'Warning: directory keyword only used when /all keyword set'
  ENDIF
  IF KEYWORD_SET(directory) THEN BEGIN
     ; First check for a slash
     n = N_ELEMENTS(directory)
     IF (n EQ 0) THEN dirslash = '/' ELSE BEGIN
        dirslash = directory
        FOR j=0, n-1 DO BEGIN
           temp_string = STRTRIM(directory[j], 2)
           ll = STRMID(temp_string, STRLEN(temp_string)-1, 1)
           IF (ll NE '/' AND ll NE '\') THEN temp_string = temp_string + '/'
           dirslash[j] = TEMPORARY(temp_string)
        ENDFOR 
     ENDELSE
     restore_dir = dirslash
  ENDIF ELSE restore_dir = ''

  IF KEYWORD_SET(all) THEN filenames = FILE_SEARCH(restore_dir + '*.tplot')
  IF SIZE(/type, filenames) NE 7 THEN filenames = 'saved.tplot'

  n = N_ELEMENTS(filenames)
  restored_varnames = ''
  FOR i=0L, n[0]-1L DO BEGIN
     fi = FILE_INFO(filenames[i])
     IF fi.exists EQ 0 THEN BEGIN
        dprint, dlevel=1, 'File ' + filenames[i] + ' Does not exist! Skipping.'
        CONTINUE
     ENDIF
     dprint, dlevel=2, 'Restoring tplot file ' + file_info_string(filenames[i])
     RESTORE, filenames[i], /relaxed

     IF KEYWORD_SET(tv) THEN BEGIN
        chkverb = WHERE(TAG_NAMES(tv.options) EQ 'VERBOSE', verbosethere)
        IF NOT verbosethere THEN BEGIN
           optstruct = tv.options
           setstruct = tv.settings
           newopt = CREATE_STRUCT(optstruct, 'VERBOSE', 0)
           tv = 0
           tv = {options: newopt, settings: setstruct}
           optstruct = 0
           setstruct = 0
           newopt = 0
        ENDIF 
     ENDIF 

     IF (N_ELEMENTS(tplot_vars) EQ 0) OR KEYWORD_SET(get_tvars) THEN $
        IF KEYWORD_SET(tv) THEN tplot_vars = tv

     IF KEYWORD_SET(dq) THEN BEGIN
        IF ~undefined(tplot_name) THEN BEGIN
           FOR j=0L, N_ELEMENTS(tplot_name)-1L DO append_array, index, TRANSPOSE((dq.name).matches(tplot_name[j]))
           index = TOTAL(index, 1)
           w = WHERE(TEMPORARY(index) GT 0, nw)
           IF nw GT 0 THEN dq = dq[w]
        ENDIF 

        FOR j=0L, N_ELEMENTS(dq.name)-1L DO BEGIN
           thisdq = dq[j]
           dprint, dlevel=3, 'The tplot variable ' + thisdq.name + ' is being restored.'
           restored_varnames = [restored_varnames, thisdq.name]

           names = STRSPLIT(thisdq.name, '.')

           IF KEYWORD_SET(append) THEN BEGIN
              get_data, thisdq.name, ptr=olddata
              IF is_struct(olddata) && (~PTR_VALID(olddata.x) || ~PTR_VALID(olddata.y)) THEN BEGIN
                 dprint, dlevel=1, 'Invalid pointer to existing tplot variable (' + thisdq.name + '); Skipping...'
                 CONTINUE
              ENDIF 
           ENDIF 

           IF KEYWORD_SET(append) AND is_struct(olddata) THEN BEGIN ; olddata needs to be a structure, jmm, 2021-10-19
              IF undefined(nan) THEN IF SIZE(*olddata.y, /type) EQ 5 THEN nan = !values.d_nan ELSE nan = !values.f_nan
              IF KEYWORD_SET(*thisdq.dh) THEN BEGIN
                 IF thisdq.dtype EQ 1 THEN BEGIN
                    IF PTR_VALID((*thisdq.dh).y) THEN BEGIN
                       ; check y dimensions prior to appending, jmm, 2019-11-22
                       n1 = SIZE(*olddata.y, /n_dimen)
                       n2 = SIZE(*(*thisdq.dh).y, /n_dimen)
                       s1 = SIZE(*olddata.y, /dimen)
                       s2 = SIZE(*(*thisdq.dh).y, /dimen)
                       IF N_ELEMENTS(s1) EQ 2 THEN s12 = s1[1] > s2[1]
                       IF (n1 NE n2) || (N_ELEMENTS(s1) GT 2 && ~ARRAY_EQUAL(s1[1:*], s2[1:*])) THEN BEGIN
                          dprint, dlevel=1, 'Variable '+ thisdq.name + ' Y size mismatch; not appended'
                          CONTINUE
                       ENDIF 

                       IF tag_exist(olddata, 'tplot_restore', /quiet) THEN newy = (*olddata.tplot_restore).y ELSE newy = PTR_NEW(list())
                       IF N_ELEMENTS(s1) EQ 2 && s1[1] NE s2[1] THEN BEGIN
                          dprint, dlevel=3, 'Variable ' + thisdq.name + ' Y size mismatch; matching sizes!'
                          oldy = REPLICATE(nan, [s1[0], s12])
                          nevy = REPLICATE(nan, [s2[0], s12])
                          oldy[*, 0:s1[1]-1] = *olddata.y
                          nevy[*, 0:s2[1]-1] = *(*thisdq.dh).y

                          IF N_ELEMENTS(*newy) EQ 0 THEN (*newy).add, oldy $
                          ELSE BEGIN
                             (*newy)[-1] = TEMPORARY(oldy)
                             FOR k=0, N_ELEMENTS(*newy)-2 DO BEGIN
                                oldy = REPLICATE(nan, dimen1((*newy)[k]), s12)
                                oldy[*, 0:dimen2((*newy)[k])-1] = (*newy)[k]
                                (*newy)[k] = TEMPORARY(oldy)
                             ENDFOR 
                          ENDELSE 
                          (*newy).add, nevy
                       ENDIF ELSE BEGIN
                          IF N_ELEMENTS(*newy) EQ 0 THEN (*newy).add, *olddata.y
                          (*newy).add, *(*thisdq.dh).y
                       ENDELSE 
                    ENDIF ELSE (*newy).add, *olddata.y

                    olddy = PTR_NEW()
                    str_element, olddata, 'dy', olddy
                    IF PTR_VALID(olddy) THEN BEGIN
                       n1 = SIZE(*olddata.dy, /n_dimen)
                       n2 = SIZE(*(*thisdq.dh).dy, /n_dimen)
                       s1 = SIZE(*olddata.dy, /dimen)
                       s2 = SIZE(*(*thisdq.dh).dy, /dimen)
                       IF N_ELEMENTS(s1) EQ 2 THEN s12 = s1[1] > s2[1]
                       IF (n1 NE n2) || (N_ELEMENTS(s1) GT 2 && ~ARRAY_EQUAL(s1[1:*], s2[1:*])) THEN BEGIN
                          dprint, dlevel=1, 'Variable ' + thisdq.name + ' DY size mismatch; not appended'
                          CONTINUE
                       ENDIF 

                       IF tag_exist(olddata, 'tplot_restore', /quiet) THEN newdy = (*olddata.tplot_restore).dy ELSE newdy = PTR_NEW(list())

                       IF N_ELEMENTS(s1) EQ 2 && s1[1] NE s2[1] THEN BEGIN
                          dprint, dlevel=3, 'Variable ' + thisdq.name + ' DY size mismatch; matching sizes!'
                          olddy = REPLICATE(nan, [s1[0], s12])
                          nevdy = REPLICATE(nan, [s2[0], s12])
                          olddy[*, 0:s1[1]-1] = *olddata.dy
                          nevdy[*, 0:s2[1]-1] = *(*thisdq.dh).dy

                          IF N_ELEMENTS(*newdy) EQ 0 THEN (*newdy).add, olddy $
                          ELSE BEGIN
                             (*newdy)[-1] = TEMPORARY(olddy)
                             FOR k=0, N_ELEMENTS(*newdy)-2 DO BEGIN
                                olddy = REPLICATE(nan, dimen1((*newdy)[k]), s12)
                                olddy[*, 0:dimen2((*newdy)[k])-1] = (*newdy)[k]
                                (*newdy)[k] = TEMPORARY(olddy)
                             ENDFOR
                          ENDELSE
                          (*newdy).add, nevdy
                       ENDIF ELSE BEGIN
                          IF N_ELEMENTS(*newdy) EQ 0 THEN (*newdy).add, *olddata.dy
                          (*newdy).add, *(*thisdq.dh).dy
                       ENDELSE
                    ENDIF 

                    IF tag_exist(olddata, 'tplot_restore', /quiet) THEN newx = (*olddata.tplot_restore).x ELSE newx = PTR_NEW(list())              
                    IF PTR_VALID((*thisdq.dh).x) THEN BEGIN
                       IF N_ELEMENTS(*newx) EQ 0 THEN *newx.add, *olddata.x
                       *newx.add, *(*thisdq.dh).x
                    ENDIF ELSE *newx.add, *olddata.x

                    oldv = PTR_NEW()
                    str_element, olddata, 'v', oldv
                    IF PTR_VALID(oldv) THEN BEGIN
                       ;;  V tag is present
                       IF tag_exist(olddata, 'tplot_restore', /quiet) THEN newv = (*olddata.tplot_restore).v ELSE newv = PTR_NEW(list())
                       IF ndimen(*oldv) EQ 1 THEN BEGIN
                          ;;  1D --> no need to append
                          IF ~ARRAY_EQUAL(oldv, (*thisdq.dh).v) THEN BEGIN
                             oldw = REPLICATE(nan, [s1[0], s12])
                             nevv = REPLICATE(nan, [s2[0], s12])
                             oldw[*, 0:s1[1]-1] = REPLICATE(1., s1[0]) # (*oldv)
                             IF ndimen(*(*thisdq.dh).v) EQ 1 THEN *(*thisdq.dh).v = REPLICATE(1., s2[0]) # (*(*thisdq.dh).v)
                             nevv[*, 0:s2[1]-1] = *(*thisdq.dh).v
                             IF N_ELEMENTS(*newv) EQ 0 THEN (*newv).add, oldw
                             (*newv).add, nevv                    
                          ENDIF ELSE *newv[-1] = *oldv
                       ENDIF ELSE BEGIN
                          ;;  2D --> need to append (if present)
                          IF (struct_value((*thisdq.dh), 'v')) THEN BEGIN
                             ;;  present --> append
                             IF ndimen(*(*thisdq.dh).v) EQ 1 THEN *(*thisdq.dh).v = REPLICATE(1., s2[0]) # (*(*thisdq.dh).v)
                             IF s1[1] NE s2[1] THEN BEGIN
                                oldw = REPLICATE(nan, [s1[0], s12])
                                nevv = REPLICATE(nan, [s2[0], s12])
                                oldw[*, 0:s1[1]-1] = *oldv
                                nevv[*, 0:s2[1]-1] = *(*thisdq.dh).v

                                IF N_ELEMENTS(*newv) EQ 0 THEN (*newv).add, oldw $
                                ELSE BEGIN
                                   (*newv)[-1] = TEMPORARY(oldw)
                                   FOR k=0, N_ELEMENTS(*newv)-2 DO BEGIN
                                      oldw = REPLICATE(nan, dimen1((*newv)[k]), s12)
                                      oldw[*, 0:dimen2((*newv)[k])-1] = (*newv)[k]
                                      (*newv)[k] = TEMPORARY(oldw)
                                   ENDFOR
                                ENDELSE
                                (*newv).add, nevv
                             ENDIF ELSE BEGIN
                                IF N_ELEMENTS(*newv) EQ 0 THEN (*newv).add, *oldv
                                (*newv).add, *(*thisdq.dh).v                    
                             ENDELSE 
                          ENDIF ELSE BEGIN
                             ;;  not present --> replicate old to make dimensions correct???
                             szdox = SIZE(*olddata.x, /dimensions)
                             szdnx = SIZE(*newx, /dimensions)
                             szdo  = SIZE(*oldv, /dimensions)
                             dumb  = MAKE_ARRAY(szdnx[0], szdo[1], type=SIZE(*oldv, /type))
                             avgo  = TOTAL(*oldv, 1, /nan) / TOTAL(FINITE(*oldv), 1, /nan)
                             dumb[0L:(szdox[0] - 1L), *] = *oldv
                             FOR kk=0L, szdo[1]-1L DO dumb[szdox[0]:(szdnx[0]-1L), kk] = avgo[kk]
                             (*newv)[-1] = dumb
                          ENDELSE
                       ENDELSE

                       IF (struct_value((*thisdq.dh), 'v')) THEN PTR_FREE, (*thisdq.dh).v
                       newdata = {x: TEMPORARY(newx), y: TEMPORARY(newy), v: TEMPORARY(newv)}
                       IF ~undefined(newdy) THEN str_element, newdata, 'dy', TEMPORARY(newdy), /add
                    ENDIF ELSE BEGIN
                    ;;  V tag is not present --> Only X and Y tags should be present
                       newdata = {x: TEMPORARY(newx), y: TEMPORARY(newy)}
                       IF ~undefined(newdy) THEN str_element, newdata, 'dy', TEMPORARY(newdy), /add
                    ENDELSE 
                    olddata = 0
                 ENDIF ELSE BEGIN
                    ; I expect that this section is obsolete... (T. Hara)
                    newdata = olddata
                    dattags = TAG_NAMES(olddata)
                    FOR k=0, N_ELEMENTS(dattags)-1 DO BEGIN
                       str_element, *thisdq.dh, dattags[k], foo
                       foo = *foo
                       str_element, newdata, dattags[k], [*olddata[k], foo], /add
                    ENDFOR
                 ENDELSE 

                 dattags = TAG_NAMES(newdata)
                 IF i NE n[0]-1L THEN BEGIN
                    str_element, newdata, 'tplot_restore', newdata, /add
                    FOR k=0, N_ELEMENTS(dattags)-1 DO str_element, newdata, dattags[k], PTR_NEW((*newdata.(k))[-1]), /add_replace
                 ENDIF ELSE FOR k=0, N_ELEMENTS(dattags)-1 DO str_element, newdata, dattags[k], PTR_NEW((*newdata.(k)).toarray(/dim)), /add_replace

                 store_data, verbose=verbose, thisdq.name, data=TEMPORARY(newdata)
              ENDIF
           ENDIF ELSE BEGIN
              store_data, verbose=verbose, thisdq.name, data=*thisdq.dh, limit=*thisdq.lh, dlimit=*thisdq.dl, /nostrsw
              dprint, dlevel=3, 'The tplot variable ' + thisdq.name + ' has been restored.'
           ENDELSE 
           IF KEYWORD_SET(sort) THEN tplot_sort, thisdq.name
        ENDFOR 
        PTR_FREE, dq.dh, dq.dl, dq.lh
     ENDIF 
     dq = 0
     tv = 0
  ENDFOR

  IF (N_ELEMENTS(restored_varnames) GT 1) THEN restored_varnames = restored_varnames[1:*]

  RETURN
END