pro IRISl12_SHIFTAIA, files, loud=loud, retry=retry, reforce=reforce

;+
; NAME:
;       IRISl12_shiftaia
;
; PURPOSE:
;       IRISl12_shiftaia corrects the pointing information in the L2 headers and the time dependent
;       extension using the AIA cross-correlation fitting results in the OBSFIT structure
;
; CATEGORY:
;       IRIS Data processing
;
; CALLING SEQUENCE:
;       IRISl12_shiftaia, files
;
; INPUTS:
;       files: list of IRIS l2 files
;
; OUTPUTS:
;       The headers and image extension for time-dependent keywords of the L2 files will be modified
;
; PROCEDURE:
;       If this correction already has been applied to an input file (according to HISTORY
;       keyword), the file will be ignored
;       Keywords edited in the main header are XCEN, YCEN, and (SJI only:) CRVAL1, CRVAL2.
;       Keywords edited in the extensions of the SG windows are CRVAL2, CRVAL3.
;       Data in the image extension for the time-dependent XCEN, YCEN will be edited.
;       Information of this correction will be written into the HISTORY keyword.
;
; KEYWORD PARAMETERS;
;		/loud: If set then some diagnostic information is printed
;		/retry: If set then it attempts to apply the correlation again even if the header
;			indicates that it tried and failed before (but NOT if it tried and succeeded!)
;		/reforce: If set, then it attempts the correlation even if it tried and either
;			failed or succeeded previously
;
; MODIFICATION HISTORY:
;       2018-11-19: Jean-Pierre Wuelser, based on Martin Wiesmann's irisl12_shiftwave.pro
;       2020-04-27: Paul Boerner, updated to pass single images (incl. PC matrices) to 
;					IRIS_AIA_CORR, and added /retry keyword and additional history
;					details
;
; $Id: $  ;


indfits = where(strmatch(files, '*.fits') eq 1, count)
if count eq 0 then begin
    box_message, 'need fits files in input (*.fits)'
    return
endif
loud = keyword_set(loud)
retry = keyword_set(retry)
reforce = keyword_set(reforce)
if reforce then retry = 1

file = files[indfits]

for ifile=0,N_ELEMENTS(file)-1 do begin
    ;read mainheader
    fits_open,file[ifile],io,/update    ;Faster to explicity open (for extensions)
    fits_read,io,0,h,/header_only,exten_no=0
       
    ;check whether change has been applied already 
    ; (note that if it has been applied successfully, OR if it has been requested
    ; but not applied and the retry keyword is not set, then this routine will skip 
    ; the file)
    hist = fxpar(h, 'history')
    ind = where(strmatch(hist, '*Pointing corr. w/AIA correl*') eq 1, applcount)
    ind = where(strmatch(hist, '*Pointing corr. w/AIA requested but*') eq 1, failcount)    
    ; if (applcount gt 0) or ((failcount gt 0) and (retry eq 0)) then begin
    if ((applcount gt 0) and (reforce eq 0)) or ((failcount gt 0) and (retry eq 0)) then begin
      box_message, ['pointing correction already applied', file[ifile]]
      fits_close, io                    ; making sure to close the file
      continue                          ; move on to the next file
    endif 

    date_obs = fxpar(h,'DATE_OBS')
    instrume = strtrim(fxpar(h,'INSTRUME'),2)
    nwin     = fxpar(h,'NWIN')

    ;get obsfit file
    if STRTRIM(date_obs) eq '' then begin  ; Handle missing header data
       date_obs = file2time(strmid(file_basename(file[ifile]), 8, 15))
    endif
    if size(obsfit,/type) ne 8 then begin
       obsfit = iris_prep_obsfit_reader({t_obs:date_obs})
    endif else begin
       t0 = anytim(date_obs)
       ts = anytim(obsfit.obs.date_obs)-100.
       te = anytim(obsfit.obs.date_end)+100.
       if t0 lt ts or t0 gt te then $
          obsfit = iris_prep_obsfit_reader({t_obs:date_obs})
    endelse

    ; read the extension for time-variable keywords
    if instrume eq 'SJI' then extno=1 else extno=nwin+1  ; ext. # for t-var. keywords
    fits_read,io,dext,hext,exten_no=extno,/No_PDU       ; get that extension
  
    ;    ; get the time vector (ccsds format)
    ;    t_indx = fxpar(hext,'TIME')  ; Seconds since start of OBS
    ;    tvec = anytim(anytim(obsfit.aia.tstart) + reform(dext[t_indx,*]),/ccsds)
    ;
    ;    ; get the pointing correction
    ;    xy_off = iris_align_aia(tvec,obsfit,msg=aiamsg)

    pc11s = REFORM(dext[fxpar(hext,'PC1_1IX'), *])
    pc12s = REFORM(dext[fxpar(hext,'PC1_2IX'), *])
    pc21s = REFORM(dext[fxpar(hext,'PC2_1IX'), *])
    pc22s = REFORM(dext[fxpar(hext,'PC2_2IX'), *])
    tvec = anytim(anytim(obsfit.aia.tstart) + reform(dext[fxpar(hext,'TIME'),*]),/ccsds)
    nimg = N_ELEMENTS(pc11s)
    xy_off = FLTARR(2,nimg)
    aiamsgs=['']
    for i=0, nimg-1 do begin
        thisoindx = CREATE_STRUCT('t_obs', tvec[i], $
                                'xdisp_rot', 0d, 'ydisp_rot', 0d, $
                                'pc1_1', pc11s[i], 'pc1_2', pc12s[i], $
                                'pc2_1', pc21s[i], 'pc2_2', pc22s[i])
        thisnindx = IRIS_ALIGN_AIA(thisoindx, obsfit, msg=aiamsg, flag=flag)
        xy_off[0,i] = thisnindx.xdisp_rot
        xy_off[1,i] = thisnindx.ydisp_rot
        aiamsgs = [aiamsgs, aiamsg]
    endfor
    aiamsg = aiamsgs[1:-1]

    ; get the info for the middle (used for other headers)
    midt = (n_elements(tvec)-1)/2
    x_off = xy_off[0,midt]
    y_off = xy_off[1,midt]
    m_aiamsg = aiamsg[midt < (n_elements(aiamsg)-1)/2] ; Fit message for the middle file
    f_aiamsg = aiamsg[0] ; Fit message for the first file

    if flag then begin
      ;change main header
      xcen = fxpar(h,'XCEN')
      ycen = fxpar(h,'YCEN')
      sxaddpar,h,'XCEN',xcen+x_off
      sxaddpar,h,'YCEN',ycen+y_off

      ;for SJI also change CRVAL1,2
      if instrume eq 'SJI' then begin
        crval1 = fxpar(h,'CRVAL1')
        crval2 = fxpar(h,'CRVAL2')
        sxaddpar,h,'CRVAL1',crval1+x_off
        sxaddpar,h,'CRVAL2',crval2+y_off
      endif
  
      ;add info to history
      get_utc,utc,/ccsds,/date_only
      sxaddhist, f_aiamsg,h
      sxaddhist, 'Middle image: ' + m_aiamsg,h
      sxaddhist,'Pointing corr. w/AIA obsfit applied post-level1to2 on '+utc, h

      ;modify mainheader
      modfits,io,0,h,exten_no=0

      ; change headers of spectral windows (if a raster file)
      if instrume eq 'SPEC' then begin
        for i=1,nwin do begin
          ;read and change header of extensions
          fits_read,io,0,hexw,/header_only,exten_no=i,/No_PDU ;Get header (for extensions)
          crval2 = fxpar(hexw, 'CRVAL2')
          crval3 = fxpar(hexw, 'CRVAL3')
          sxaddpar, hexw, 'CRVAL2', crval2+y_off
          sxaddpar, hexw, 'CRVAL3', crval3+x_off
          modfits,io,0,hexw,exten_no=i                ;Update header
        endfor
      endif

      ; modify pointing information in the extension for time-variable keywords
      xcenix = fxpar(hext,'XCENIX')
      ycenix = fxpar(hext,'YCENIX')
      dext[xcenix,*] = dext[xcenix,*] + xy_off[0,*]
      dext[ycenix,*] = dext[ycenix,*] + xy_off[1,*]
  
      ; re-write data portion of extension
      modfits,io,dext,exten_no=extno
  
      if loud then print, 'modified pointing of ' + file[ifile]
    endif else begin
        ;add info to history
        get_utc,utc,/ccsds,/date_only
        sxaddhist,m_aiamsg,h
        sxaddhist,'Pointing corr. w/AIA obsfit failed on '+utc, h
        if loud then print, 'Failed to modify pointing of ' + file[ifile]
        modfits,io,0,h,exten_no=0
    endelse
    fits_close, io
endfor

end
