
FUNCTION eis_slot_map, file, wvl_input, clean=clean, trim=trim, int_scale=int_scale, $
                       calib=calib, ref_wvl=ref_wvl, iexp_prp=iexp_prp, bg48=bg48, $
                       quiet=quiet, i_exp=i_exp

;+
; NAME:
;     EIS_SLOT_MAP
;
; PURPOSE:
;     Converts a slot raster into an IDL map.
;
; CATEGORY:
;     Hinode/EIS; slot; image; map.
;
; CALLING SEQUENCE:
;     Result = EIS_SLOT_MAP( File, Wvl_Input )
;
; INPUTS:
;     File:  Name of an EIS file containing a slot raster.
;
; OPTIONAL INPUTS:
;     Wvl_Input:  If the value is larger than 100, then it is assumed
;                 to be a wavelength in angstroms. If less than 100,
;                 then it is assumed to be the index of wavelength
;                 window (first window is zero). If no input is given,
;                 then the routine will ask the user which window is
;                 required.
;     Int_Scale:  This is for a very particular case, when a slot
;                 raster was partially in the orbit twilight
;                 period. Int_scale is used to multiply the image of
;                 each exposure by a factor. It should be an array of
;                 same size as the no. of exposures in the raster.
;     Trim:  A 2-element array giving the trim pixels. The default is
;            to choose the central pixels, which are printed to the
;            screen.
;     Ref_Wvl:  A scalar that specifies the reference wavelength of
;               the line of interest. This is used in case the user
;               has specified Wvl_Input as an index, rather than a
;               wavelength. It is used to identify the center of the
;               slot image.
;     Iexp_Prp: If nexp_prp>1, then this specifies the exposure time
;               to use.
;     I_exp:    For sit-and-stare observations, this chooses the
;               exposure for the map.
;     Calib: This allows the EIS calibration to be modified, changing
;            the output intensity and error arrays. One of the
;            following values should be set:

;            0 - no effect
;            1 - Del Zanna (2013) calibration is implemented.
;            2 - Del Zanna (2013) calibration, and the
;                /correct_sensitivity correction is "undone".
;            3 - Warren et al. (2014) calibration is implemented.
;            4 - Warren et al. (2014) calibration, and the
;                /correct_sensitivity correction is "undone". 
;
;            WARNING: before using this keyword, the user should know
;            what calibration options were applied in the original
;            call to eis_prep. See the EIS wiki for more details
;            (http://solarb.mssl.ucl.ac.uk:8080/eiswiki/Wiki.jsp?page=EISCalibration)
;
; KEYWORD PARAMETERS:
;     CLEAN:  Cleans the exposures with clean_exposure. Only applied
;             if a level-0 file has been specified.
;     BG48:   For windows with 48 pixels, setting this keyword
;             subtracts a background that is obtained by taking the
;             minimum intensity in the 0th and 47th columns.
;     QUIET:  If set, then non-essential text messages will not be
;             printed to IDL window.
;
; OUTPUTS:
;     An IDL map containing the slot raster image. Note that the
;     pointing is corrected for the AIA-EIS offset. If a problem is
;     found, then -1 is returned.
;
;     The output map structure contains the non-standard tag 'trim'
;     which is a 2-element integer array giving the trim pixels that
;     have been applied to the data.
;
; EXAMPLE:
;     IDL> file=eis_find_file('6-jun-2012 00:39',/level1)
;     IDL> map=eis_slot_map(file,195.12)
;     IDL> p=plot_map_obj(map,/log,rgb_table=aia_rgb_table(193))
;
; MODIFICATION HISTORY:
;     Ver.1, 09-Oct-2020, Peter Young
;     Ver.2, 16-Aug-2021, Peter Young
;        Added CALIB= keyword.
;     Ver.3, 21-Aug-2021, Peter Young
;        Removed rogue print statement; modified how exposure time
;        obtained.
;     Ver.4, 17-Sep-2021, Peter Young
;        Now handles full-CCD case correctly and also nexp_prp>1
;        cases; adjusted default TRIM to better avoid slot edges.
;     Ver.5, 09-Feb-2022, Peter Young
;        Fixed bug associated with iexp_prp.
;     Ver.6, 18-Feb-2022, Peter Young
;        Added /bg48; fixed bug with fmirr_ss implementation.
;     Ver.7, 28-Feb-2022, Peter Young
;        Added the 'trim' tag to the output map; implemented /quiet
;        keyword.
;     Ver.8, 02-Mar-2022, Peter Young
;        Modified how /bg48 works; now checks slit_ind to make sure it
;        is a slot dataset.
;     Ver.9, 03-Mar-2022, Peter Young
;        Added slit_ind to map and fixed bug with ref_wvl.
;     Ver.10, 23-Apr-2022, Peter Young
;        Made some modifications to handle 266" slot data; introduced
;        i_exp= keyword to select exposures for sit-and-stare data.
;-


IF n_params() LT 1 THEN BEGIN
   print,'Use:  IDL> map=eis_slot_map(file,wvl_input [,trim=, /clean, calib=, int_scale=, ref_wvl='
   print,'                            iexp_prp=, /quiet, /bg48, i_exp= ])'
   return,-1
ENDIF 


swtch=0
IF datatype(file) NE 'OBJ' THEN BEGIN
  swtch=1
  data=obj_new('eis_data',file,datasource='fits')
ENDIF ELSE BEGIN
  data=file
ENDELSE

missing=-100.


lev_num=data->getinfo('DATA_LEV')
sit_stare=data->getsit_AND_stare()
nexp_prp=data->getnexp_prp()
nexp=(data->getnexp())/nexp_prp


IF sit_stare EQ 1 AND nexp GT 1 AND n_elements(i_exp) EQ 0 THEN BEGIN
  print,'% EIS_SLOT_MAP: this is a sit-and-stare observation with '+trim(nexp)+' exposures. Please choose an'
  print,'                exposure with the I_EXP= optional input. Returning...'
  return,-1
ENDIF 
  
;
; Check the slit index to make sure we have slot data.
;
slit_ind=data->getinfo('SLIT_IND')
IF slit_ind EQ 0 OR slit_ind EQ 2 THEN BEGIN
  print,'% EIS_SLOT_MAP: the specified file does not contain slot data (slit_ind='+trim(slit_ind)+'). Returning...'
  return,-1
ENDIF 

mirrpos=*(data->getaux_data()).fmirr

xpos=data->getxpos()
ypos=data->getypos()

hdr=data->gethdr()
id = hdr[0]-> getline_id()


IF n_elements(wvl_input) EQ 0 THEN BEGIN 
  i=where(id NE '')
  nwind=n_elements(id[i])

  ; -----------------------------------<
  ; Choose which wavelength window needs to be looked at
  ;
  PRINT,''
  PRINT,'Choose a wavelength window to analyse:'
  PRINT,''
 ;
  FOR i=0,nwind-1 DO PRINT,i+1,'.  ',trim(id[i])
 ;
  READ,choice
  iwin=FIX(choice-1)
 ; -----------------------------------<
ENDIF ELSE BEGIN
  IF wvl_input GE 100. THEN iwin=data->getwindx(wvl_input) ELSE iwin=fix(wvl_input)
ENDELSE 


wd=data->getvar(iwin)
IF n_elements(wd) EQ 1 THEN BEGIN
  print,'% EIS_SLOT_MAP: wavelength window not found. Returning...'
  return,-1
ENDIF 

;
; Need to re-form wd if nexp_prp > 1.
;
s=size(wd,/dim)
nx=s[0]
ny=s[1]
n=s[2]

IF nexp_prp GT 1 THEN BEGIN
  wd2=fltarr(nx,ny,nexp,nexp_prp)
  FOR i=0,nexp_prp-1 DO BEGIN
    j=indgen(nexp)+i
    wd2[*,*,*,i]=wd[*,*,j]
  ENDFOR
  wd=temporary(wd2)
ENDIF ELSE BEGIN
  iexp_prp=0
ENDELSE


IF keyword_set(sit_stare) THEN wd=wd[*,*,i_exp]

s=size(wd)
nx=s[1]
ny=s[2]
IF s[0] EQ 3 THEN n=s[3] ELSE n=1


wvl=data->getlam(iwin)


IF lev_num EQ 0 THEN eis_debias,wd

plot_title=trim(id[iwin])



;
; Get mean wavelength for window. Need to treat full-CCD data as
; special case.
;
IF nx EQ 1024 THEN BEGIN
   IF n_elements(ref_wvl) EQ 0 AND wvl_input LT 100. THEN BEGIN
      message,'This is a full-CCD data-set. Please use REF_WVL= to specify the wavelength you want. Returning...',/cont
      return,-1
   ENDIF
   IF n_elements(ref_wvl) EQ 0 THEN ref_wvl=wvl_input
ENDIF ELSE BEGIN 
   cen=mean(wvl)
   ref_wvl=cen
ENDELSE 



; Intensity calibration adjustment (CALIB keyword).
;
IF n_elements(calib) NE 0 THEN BEGIN
   date_obs=data->getinfo('DATE_OBS')
   CASE calib OF 
    1: calib_factor=eis_ltds(date_obs,ref_wvl)
    2: calib_factor=eis_ltds(date_obs,ref_wvl,/undecay)
    3: calib_factor=eis_recalibrate_intensity(date_obs,ref_wvl,1)
    4: calib_factor=eis_recalibrate_intensity(date_obs,ref_wvl,1,/undecay)
    ELSE: calib_factor=1.0
  ENDCASE 
 ;
 ; Output of eis_ltds is an array, so need to convert to scalar
  calib_factor=calib_factor[0]
ENDIF ELSE BEGIN
  calib_factor=1.0
ENDELSE 



;
; Missing exposures can get assigned strange times, so I perform a
; check here on missing exposures.
;
imiss=bytarr(n)
FOR i=0,n-1 DO BEGIN
  exp=wd[*,*,i]
  IF mean(exp) LE -98 THEN imiss[i]=1b
ENDFOR 

;
; The slot window width (nx) will typically be 40 or 48 pixels (has to be
; multiples of 8).
;
; The step size between slot positions (nw) will often be smaller than the
; slot width, in order to ensure some overlap. The following code
; works out nw, and then sets the 2-element array TRIM to set how the
; slot window will be trimmed down to the step size.
;
;fmir_ss=data->getinfo('FMIR_SS')
fmir_ss=*(data->getaux_data()).fmirr
IF n_elements(fmir_ss) EQ 1 OR sit_stare EQ 1 THEN BEGIN
  getmin=min(abs(wvl-ref_wvl),imin)
  print,imin
   IF n_elements(trim) EQ 0 THEN BEGIN
     IF slit_ind EQ 3 THEN BEGIN
       trim=[max([0,imin-18]),min([nx-1,imin+22])]
     ENDIF ELSE BEGIN
       trim=[max([0,imin-133]),min([nx-1,imin+132])]
     ENDELSE 
   ENDIF 
   nw=trim[1]-trim[0]+1
ENDIF ELSE BEGIN 
   nw=(fmir_ss[1]-fmir_ss[0])/4
   diff=(nx-nw)/2 > 0
   IF n_elements(trim) EQ 0 THEN trim=[diff,nw-1+diff]
ENDELSE 


IF NOT keyword_set(quiet) THEN BEGIN
  print,''
  print,'% EIS_SLOT_MAP: Window is '+trim(nx)+' pixels wide, step size is '+trim(nw)+' pixels.'
  IF n LT nx THEN BEGIN
    print,'                TRIM has been set to ['+trim(trim[0])+','+trim(trim[1])+']'
    print,'                Use keyword TRIM= to modify this.'
  ENDIF
ENDIF

;
; Handle multiple exposures per raster position
;
;
eis_get_exposure_info,data,exp_times=exptime
exptime=exptime[0:nexp_prp-1]
IF nexp_prp GT 1 THEN BEGIN 
   getmin=min(exptime,imin)
   IF n_elements(iexp_prp) EQ 0 THEN BEGIN
      iexp_prp=imin
      print,'% EIS_SLOT_MAP: There are '+trim(nexp_prp)+' exposures per raster position. '
      print,'                Choosing exposure with shortest exposure time ('+trim(iexp_prp)+').'
      print,'                Use the input IEXP_PRP to choose a different one.'
   ENDIF
ENDIF 


n_is=n_elements(int_scale)
IF n_is NE 0 THEN BEGIN
   IF n_is NE n THEN BEGIN
      print,'% EIS_SLOT_MAP: the number of elements of int_scale should be '+trim(n)+'.'
      print,'                Returning...'
      return,-1
   ENDIF 
ENDIF 

;
; Define size of the image.
;
im=fltarr(nw*n,ny)

info_swtch=0b
FOR i=0,n-1 DO BEGIN
 ;
 ; If /bg48 is set and windows has 48 pixels, then I set the
 ; background to the minimum of the values in columns 0 and 47.
 ; Note that I set missing data to NaN so that I can use the /nan
 ; keyword for MIN.
 ;
  wdi_bg=fltarr(nw,ny)
  IF keyword_set(bg48) AND nx EQ 48 THEN BEGIN
    bg_arr=reform(wd[[0,47],*,i,iexp_prp])
    k=where(bg_arr EQ missing,nk)
    IF nk NE 0 THEN bg_arr[k]=bg_arr[k]*!values.f_nan
    bg=min(bg_arr,dim=1,/nan)*calib_factor
;    bg=reform(wd[0,*,i,iexp_prp])*calib_factor
    FOR j=0,nw-1 DO wdi_bg[j,*]=bg
    info_swtch=1b
  ENDIF
 ;
  wdi=wd[trim[0]:trim[1],*,i,iexp_prp]*calib_factor - wdi_bg
  IF lev_num EQ 0 THEN BEGIN 
    clean_im=clean_exposure(wdi)
    wdi=clean_im
  ENDIF
  IF n_is NE 0 THEN BEGIN
    k=where(wdi NE missing,nk)
    IF nk NE 0 THEN wdi[k]=wdi[k]*int_scale[i]
  ENDIF 
  im[nw*(n-i-1):nw*(n-i)-1,*]=reverse(wdi,1)
ENDFOR 


IF NOT keyword_set(quiet) AND info_swtch EQ 1 THEN print,'% EIS_SLOT_MAP: background has been subtracted.'


;
; Set image scale.
;
dx=1.0
dy=1.0


;
; Derive date_obs by taking the mid-time of each exposure and finding
; average. I avoid using missing exposures when calculating the
; mid-time. 
;
k=where(imiss EQ 0b)
ti1=data->getti_1()
ti2=data->getti_2()
midti=mean((ti2[k]-ti1[k])/2.+ti1[k])
t_tai=data->ti2tai(midti)
date_obs=anytim2utc(t_tai,/ccsds)


;
; Derive xcen and ycen values. Note that EIS-AIA offset is applied.
;
xy=eis_aia_offsets(date_obs)
xpos=data->getxpos() + xy[0]
ypos_wvl=ref_wvl
ypos=data->getypos(ypos_wvl) + xy[1]
xcen=mean(xpos)
ycen=mean(ypos)


obj_destroy,data


outmap=make_map(im,xc=xcen, yc=ycen, dx=dx, dy=dy, time=date_obs, id=plot_title, $
                missing=missing,dur=exptime,wavelength=ref_wvl, $
                slit_ind=fix(slit_ind), trim=trim)



return,outmap


END
