forWARD_FUNCTION DIcalVIS_DNtoRadIF, getVISCalConst
;;-----------------------------------------------------------------------------
;; PURPOSE:
;;	Used in the DI Calibration Pipeline.
;;	Converts the VIS image from raw values to radience and/or I/F values.
;;	The returned headers are in fitsHdr which is now a structure with two
;;	fields: 'rad' and 'ioverf'. If one output is not specified, then the
;;	image is not converted to that unit and the appropriate field contains
;;	zero or null strings.
;;
;; CALLING SEQUENCE:
;;	out = DIcalVIS_DNtoRad(in, fitsHdr)
;;
;; REQUIRED INPUTS:
;;	in - The image to which this pipeline element is going to be applied
;;	fitsHdr - The FITS header for the image
;;
;; OUTPUTS:
;;	RETURN - A structure containing the image in both radiance and I/F
;;		units. There are two fields: 'rad' and 'ioverf'
;;
;; OPTIONAL INPUT KEYWORDS:
;;	FN - Filename of the file containing the calibration constant. The
;;		constant should be saved as a variable named "visConst" using
;;		the IDL SAVE command. If this is not specified, it is found
;;		using a database.
;;	RAD - Return the radience image?
;;	IOVERF - Return the I/F image?
;;
;; EXAMPLE:
;;      IDL> outImg = DIcalVIS_DNtoRad(imgIn, fitsHdr, /RAD)
;;
;; PROCEDURES USED (i.e. called directly!):
;;	SXPAR - get a FITS header item
;;	getCalConst - determine the calibration constant
;;
;; MODIFICATION HISTORY:
;;   2004-10-18  M. Desnoyer    Created
;;   2005-04-12  M. Desnoyer    Reordered functions
;;
;;-----------------------------------------------------------------------------

;;-----------------------------------------------------------------------------
;; PURPOSE:
;;	Determines the VIS calibration constant based on the filter used. If
;;	both the Rad and I/F constants are requested, they are returned in
;;	a structure with fields called: 'rad' and 'ioverf'
;;
;; CALLING SEQUENCE:
;;	const = getVISCalConst(filter, inst, date, FN=fn, RAD=rad, IOVERF=ioverf)
;;
;; REQUIRED INPUTS:
;;	filter - Integer specifying the actual filter used
;;	inst - The instrument used
;;	date - The date of the image
;;
;; OUTPUTS:
;;	RETURN - The calibration constant
;;
;; OPTIONAL INPUT KEYWORDS:
;;	FN - Filename of the save file specifying the calibration constant
;;
;; EXAMPLE:
;;      IDL> calConst = getVISCalConst(filter, inst, date)
;;
;; PROCEDURES USED (i.e. called directly!):
;;
;; MODIFICATION HISTORY:
;;   2004-07-21  M. Desnoyer    Created
;;
;;-----------------------------------------------------------------------------
FUNCTION getVISCalConst, filter, inst, date, FN=fn

ON_ERROR,2

;; Get the filename
IF NOT keyword_set(FN) THEN BEGIN
	;; Get the real filter number
	filter = imgh036ToFilter(filter,inst,date)

	serv = getSQLserver()
	db = 'di_calib'
	tbl = 'VIS_ABSCAL'
	sel = ['Filepath']
	cond = 'Instrument = "'+inst+'" AND Date <= "'+date+$
		'" AND Filter = '+strtrim(filter,2)+$
		' order by Date desc, Version desc limit 1'

	webfn = di_sqlquery(serv, db, tbl, sel, cond, dim=dim)

	IF min(dim) EQ 0 THEN message, 'Could not find calibration file'

	fn1 = getLocFn(webFn, subdir='VIS_ABSCAL')
ENDIF ELSE fn1=fn

calConst = readFITS(fn1[0], /silent) ;; This will be a 2 element array
IF n_elements(calConst) NE 2 THEN $
	message, 'Invalid VIS calibration constants'

RETURN, {rad:calConst[0], ioverf:calConst[1]}

END

;;-----------------------------------------------------------------------------
;; Main function
;;-----------------------------------------------------------------------------
FUNCTION DIcalVIS_DNtoRadIF, in, fitsHdr, FN=fn, RAD=rad, IOVERF=ioverf


;; Do error handling
;CATCH, error
error=0

IF error NE 0 THEN BEGIN
	CATCH, /CANCEL
	message, 'Convert to Radience Units - ' + !ERROR_STATE.MSG, /NONAME
ENDIF

;; Check to make sure at least one of rad and ioverf is present
outrad = keyword_set(rad)
outif = keyword_set(ioverf)
IF NOT (outrad OR outif) THEN message, 'No output type specified', /NONAME

;; Get the integration time in milliseconds
intTime = SXPAR(fitsHdr, 'INTTIME', COUNT=c1)

;; Get the filter
filter = SXPAR(fitsHdr, 'IMGH036', COUNT=c2)

;; Get the units of the image
units = SXPAR(fitsHdr, 'BUNIT', COUNT = c3)

;; Get the instrument
inst = SXPAR(fitsHdr, 'INSTRUME', COUNT=c4)

;; Get the date
date = SXPAR(fitsHdr, 'OBSDATE', COUNT=c5)

;; Make sure all the header items exist
IF (c1 EQ 0) OR (c2 EQ 0) OR (c3 EQ 0) OR (c4 EQ 0) OR (c5 EQ 0) THEN $
	message, 'Invalid FITS Header', /NONAME

;; Check the units of the file to see if this can be applied
IF strtrim(units,2) NE 'DATA NUMBER' THEN $
	message, 'Image must be in DN units to convert'

;; Figure out where the bias columns are so we don't convert them
tmp = getBiasCols(fitsHdr,COMPLEMENT=imgCols)

;; Identify which data to output
IF outif THEN BEGIN
	out = {rad:double(in),ioverf:double(in)}
	fitsHdr = {rad:fitsHdr,ioverf:fitsHdr}
ENDIF ELSE BEGIN
	out = {rad:double(in),ioverf:0}
	fitsHdr = {rad:fitsHdr,ioverf:''}
ENDELSE

;; Identify the proper calibration constant based on the filter used
calConst = getVISCalConst(filter, inst, date, FN=fn)

;; Get the effective wavelength of the filter
wl = di_filt2wl(filter,inst,date,/includeif)

;; Convert integration time to seconds
intTime = intTime*1d-3

;; Convert to radiance units
;; The calibration constant is in [W/(m^2 sr um)]/[DN/s]
out.rad[imgCols[0]:imgCols[1],*] = out.rad[imgCols[0]:imgCols[1],*] * $
		(calConst.rad/intTime)
tmp = fitsHdr.rad
FXADDPAR, tmp, 'BUNIT', 'W/[m^2 sr um]'
FXADDPAR, tmp, 'RADCAL', 'T'
FXADDPAR, tmp, 'RADCALV', calConst.rad
FXADDPAR, tmp, 'RADCALW', wl[0]
fitsHdr.rad = tmp

;; Convert to I/F units
;; The calibration constant is in (W/[m^2 sr um] @ 1AU)
IF outif THEN BEGIN
	D = getSunTgtDist(fitsHdr.ioverf)
	out.ioverf[imgCols[0]:imgCols[1],*] = out.rad[imgCols[0]:imgCols[1],*]*$
		(!dpi*(D^2)/calConst.ioverf)
	tmp = fitsHdr.rad
	FXADDPAR, tmp, 'BUNIT', 'I/F'
	FXADDPAR, tmp, 'IOFCAL', 'T'
	FXADDPAR, tmp, 'IOFCALV', calConst.ioverf
	FXADDPAR, tmp, 'IOFCALW', wl[1]
	FXADDPAR, tmp, 'IOFCALD', D
	fitsHdr.ioverf = tmp
ENDIF

;; Finish
RETURN, out

END