;--------------------------------------------------------------------
PRO fg_bad_pix, index, data, index_out, data_out, mask,       $
                user_mask=user_mask,           nbadpix=nbadpix, $
                no_vignet=no_vignet,                            $
                verbose=verbose,               quiet=quiet,     $
                version=progver,               name=prognam,    $
                qstop=qstop,                   update=update
;+
; NAME:
;	FG_BAD_PIX
;
; PURPOSE:
;	Correct the FG CCD camera fix pattern defects. Including:
;	removed rows in partial readout frames, dead pixels, hot
;	pixels, fixed flaws on the chip such as dust.
;
; CATEGORY:
;	FITS processing
;
; SAMPLE CALLING SEQUENCE:
;       FG_BD_PIX, index, image, index_out, image_out $
;               [, /no_vignet, user_mask=user_mask, nbadpix=nbadpix]
;
; INPUTS:
;       INDEX    - an SSW header index structure for IMAGE.
;       DATA    - a 2-D or 3-D data  array from the SOT/FG CCD camera.
; 
; OUTPUTS:
;       INDEX_OUT- the SSW header index structure for the corrected image.
;       DATA_OUT- the corrected SOT/FG CCD camera data array.
;
; OUTPUTS (Optional):
;       MASK      - a 2-D image showing valid and invalid pixels. 
;
; OPTIONAL INPUT KEYWORD PARAMETERS:
;       USER_MASK: a user-supplied mask of dead and/or hot pixels. 
;                  These pixels are corrected using a interpolation
;                  from surrounding good pixels. A MASK array returned 
;                  by FG_SHIFT_PIX can be used.
;       NO_VIGNET : If set, do not mask the LHS vignetting of NFI
;       UPDATE   : If set, update history record in INDEX_OUT
;	QSTOP	 : Set to stop in this procedure for debuging purposes
;
; OPTIONAL OUTPUT KEYWORD PARAMETERS:
;       NBADPIX: the number of bad pixels corrected by the median filter.
;       VERSION: the version number of this routine.
;       NAME   : the name of this routine.
;
; COMMON BLOCKS: none.
;
; RESTRICTIONS: INDEX must be an SSW image index structure with appropriate 
;        keywords for treating the image.
;        DATA must be a 2- or 3-D image array.
;
; PROCEDURE:
;
;
; MODIFICATION HISTORY:
;v1.0  Created 1-Dec-2006 by T. Berger
;v1.1  Removed CCD readout anomaly fixes. These are now done by
;      fg_shift_pix.pro.
;v1.2  Refined central row interpolation for partial readout
;      images. TEB, 2-Apr-2007.
;v1.3  Generalized method is implemented using a 2D mask array.
;      It corrects not only missing central rows in partial read-out
;      but outer edge.   13-Apr-2007, YK
;V1.4  Added bad pixel map file to SSWDB. All 1 for
;      now. 24-Apr-2007. TEB.
;v1.5  Update to handle NFI multi-image data arrays. TEB 25-Oct-2007.
;v1.51 Minor bug fix for Q,U,V images. YK 8-Nov-2007.
;v1.52 Added a keyword NO_VIGNET to enable/disable the LHS vignetting 
;      of NFI. YK 3-Feb-2009
;v1.53 Change /EDGE to /EDGE_TRUNCATE in SMOOTH call (breaks in IDL > 8)
;      Zarro (14-Mar-2013)
;-
;-----------------------------------------------------------------------------

; Program name and version:
prognam = 'FG_BAD_PIX.PRO'
progver = 'V1.5.3'
prog_nam_ver = 'FG_BAD_PIX.PRO V1.5.3'

time0 = SYSTIME(1)

;Keyword processing
quiet = 1
loud = 1 - KEYWORD_SET(quiet)
verbose = KEYWORD_SET(verbose)
if (verbose eq 1) then loud = 1
if (loud) then MESSAGE,/INFO, 'Start  '+prognam+' '+progver

; Define teporary variable INDEX0, which is the first header index of
; INDEX (in case it is an array):
index0 = index[0]

img_nx0 = gt_tagval(index0,/naxis1)
img_ny0 = gt_tagval(index0,/naxis2)
img_ssum = gt_tagval(index0,/camssum)
img_psum = gt_tagval(index0,/campsum)
img_binx = gt_tagval(index0,/fgbinx)
img_biny = gt_tagval(index0,/fgbiny)
img_x0 = gt_tagval(index0,/fgccdix0)    ; image x0 on ccd array
img_y0 = gt_tagval(index0,/fgccdiy0)    ; image y0 on ccd array
img_roi0 = gt_tagval(index0,/roistart)  ;CCD readout codewords.
img_roi1 = gt_tagval(index0,/roistop) 

;Convert image corners to solar image orientation
x0 = (4095-img_x0)/img_psum
x1 = x0+img_nx0-1
y0 = (2047-img_y0)/img_ssum
y1 = y0+img_ny0-1
xm = 2048/img_psum

;2D x and y arr
xarr = INDGEN(img_nx0) # REPLICATE(1,img_ny0)
yarr = REPLICATE(1,img_nx0) # INDGEN(img_ny0)

;BFI or NFI data:
if gt_tagval(index0,/waveid) le 6 then nfi = 0 else nfi = 1

;if full FOV NFI, don't try to fill in the LHS vignetting:
if (not keyword_set(no_vignet)) and (img_roi0 eq 0) and (img_roi1 eq 1025) $
  and (nfi) then begin
   vign =  WHERE(xarr le 27)
   vign = [[vign],WHERE(yarr lt (120-2*xarr)) ]
   vign = [[vign],WHERE(yarr gt (953 + 1.667*xarr)) ]
end else vign=-1

; Read bad pixel data base
if N_ELEMENTS(pixdir) eq 0 then pixdir = concat_dir(getenv('SOT_SSWDB'),'pixels')
;So far, nothing there. Just make a unit mask:
mask_db = BYTE(data)*0b+1b
If N_ELEMENTS(user_mask) le 0 then user_mask=BYTE(data[*,*,0])*0b+1b
mask = mask_db * user_mask

;Determine number of images in DATA array.
nexp = fg_num_eff_exp(index0, quiet=(1-loud))
nimage = N_ELEMENTS(nexp)
; GLS - Added 2022-06-01 to handle 3D data arrays:
ndim_data = (size(data))[0]
if ndim_data eq 2 then nimage = 1
if ndim_data eq 3 then nimage = n_elements(data[0,0,*])

nbadpix = LONARR(nimage)
data_out = data
index_out = index
for i=0,nimage-1 do begin

   image = data[*,*,i]
   imask = mask[*,*,i]      

   if KEYWORD_SET(qstop) then STOP

   ; make mask for good pixels surrounding bad pixels.
                                ;This needs improvement for the
                                ;partial FOV case with the center
                                ;pixels missing. The SMOOTH makes the
                                ;good mask pick up some of the gap and
                                ;therefore the interpolation comes out
                                ;darker than it should.
   mask_good = (1b-SMOOTH(imask,[7,7],/edge_truncate)) * imask
   mask_bad  = 1b-imask
   if vign[0] ne -1 then mask_bad[vign] = 0

   ss_good = WHERE(mask_good, ns_good)
   ss_bad  = WHERE(mask_bad, ns_bad)

   ; triangulation and interpolation
   if ns_good gt 0 then begin
      if ns_bad gt 0 then begin
         TRIANGULATE, xarr[ss_good], yarr[ss_good], tri
         out = GRIDDATA(xarr[ss_good], yarr[ss_good], image[ss_good] $
                        , xout=xarr[ss_bad], yout=yarr[ss_bad] $
                        , /natural, tri=tri)
         image[ss_bad] = out>MIN(image)
      endif
         
      if (loud) then begin
         MESSAGE, /info, 'Bad pixel correction applied.'
         MESSAGE, /info, '  # of bad pixels: '+STRTRIM(ns_bad,2)
      endif
   endif else begin
      if (loud) then begin
         MESSAGE, /info, 'No good pixels found for interpolation.'
         MESSAGE, /info, 'Bad pixel correction not applied.'
      endif
   endelse  

   data_out[*,*,i]=image
   mask[*,*,i] = imask
   nbadpix[i] = ns_bad

end

run_time = SYSTIME(1) - time0
if (loud) then PRINT, 'FG_BAD_PIX took '+STRTRIM(run_time,2)+' seconds for 1 image'

; Update history record in the index if requested
if KEYWORD_SET(update) then begin
   tagval = 'Corrected bad pixels.'
   update_history,index_out,tagval,version=version
   if (loud) then MESSAGE, /INFO, 'HISTORY record updated: '+tagval
endif

if (KEYWORD_SET(qstop)) then STOP

RETURN
END
