FUNCTION DI_fitDarkFunc, inst, dtctr, outFn, ERROR=error, START=start, $
	ENDDT=enddt

;;-----------------------------------------------------------------------------
;; PURPOSE:
;;	Uses all of the calibration dark frames between time START and ENDDT
;;	that exist in the SDC SQL database. The darks must have the same
;;	instrument and detector as the one asked for (TODO: What about
;;	mode??). Takes these darks and does least squares fitting to the 
;;	following function for each pixel.
;;
;;	For VIS:
;;	;;Dark(I,B) = A0*I + exp(A1 + A2/B) + A3
;;	;;Dark(I,B) = A0*I*exp(A1*B) + A3
;;	Dark(I,B) = A0*I + exp(A1+A2*B) + A3
;;
;;	For IR:
;;	TBD
;;
;;	Where:
;;	A[0..n-1] - Parameters of fitting model
;;	I - Integration time (INTTIME)
;;	B - Bench Temperature (IMGH051)
;;
;;	Then, the parameters of the fittings are stored in outFn as an IDL
;;	variable called "A", which is a [XSize,YSize,n] array with the 
;;	parameters for the pixels at (x,y) stored at A[x,y,*].
;;
;;	The function fitting is done using the routine MPFITFUN, which was 
;;	found at http://cow.physics.wisc.edu/~craigm/idl/
;;
;; CALLING SEQUENCE:
;;	flPtr = DI_fitDarkFunc(inst, dtctr[, outFn])
;;
;; REQUIRED INPUTS:
;;	inst - String specifying the instrument to look for (eg. 'HRI')
;;	dtctr - Integer specifying the instrument detector (0=VIS, 1=IR)
;;
;; OUTPUTS:
;;	RETURN - The filename of the file created. Blank sting if nothing 
;;		created
;;	ERROR - 0 if everything worked, 
;;		1 if there was an IO error,
;;		2 if the procedure call was invalid
;;		3 if there was an error calibrating the darks
;;		4 if fitting did not converge
;;		5 if no valid dark frames were found
;;
;; OPTIONAL INPUT KEYWORDS:
;;	outFn - String specifying the filename to output the A cube to. If
;;		not specified, then the output filename will be:
;;		<Start Date>-<End Date><Inst><Dtctr>.par
;;		(eg. 030227-030401HRI1.par)
;;	START - String (In YYYY-MM-DDTHH:MM format) specifying the starting 
;;		date of dark frames to use in the fitting. If not specified, 
;;		then all early dark frames will be used.
;;	ENDDT - String (In YYYY-MM-DDTHH:MM format) specifying the ending date 
;;		of dark frames to use in the fitting. If not specified, then 
;;		all late dark frames will be used
;;
;; EXAMPLE:
;;      IDL> fn = DI_fitDarkFunc( inst, dtctr, START=stDate, ENDDT=endDate)
;;
;; PROCEDURES USED (i.e. called directly!):
;;	MPFITFUN - Performs least squares fitting for arbitrary models
;;	DI_VISDarkFitModel - Contains the model evaluation needed by MPFITFUN
;;			for VIS images
;;	DI_IRDarkFitModel - Contains the model evaluation needed by MPFITFUN
;;			for IR images
;;	DI_sqlQuery - Query's a database for the images to use
;;	getLocFn - Gets pointers to the images store locally
;;	getSQLServer - Identifies the SQL server to use
;;	readFITS - Loads a FITS image
;;	DIcal_bitWeight - Calibrate the dark images
;;	DIcal_linearDN - Calibrate the dark images
;;
;; MODIFICATION HISTORY:
;;   2004-06-07  M. Desnoyer    Created
;;
;;-----------------------------------------------------------------------------
fnCreated = ''
ERROR = 0

;; Get the info to connect to the SQL server
serv = getSQLServer()
db = 'di_testing'

;; Get the table name based on instrument and detector
tblNm = inst
IF dtctr EQ 0 THEN BEGIN
	tblNm = STRUPCASE(tblNm) + 'VIS' 
	tempFld = 'CCDT'
ENDIF ELSE IF dtctr EQ 1 THEN BEGIN
	tblNm = STRUPCASE(tblNm) + 'IR' 
	tempFld = 'IRFPAT'
ENDIF ELSE GOTO, callErr

;; Determine the condition on data to return
;; TODO: Detmine if mode should always be 1
cond = "(EXPERMNT like 'DRK%') AND (IMGH030 = 1) AND (INTTIME>=0)"
IF keyword_set(start) THEN cond = cond + " AND (FNISODAT >= '"+start+"') "
IF keyword_set(enddt) THEN cond = cond + " AND (FNISODAT <= '"+enddt+"') "
cond = cond + 'order by FNISODAT'

;; Need:
;; Path - FNISODAT - INTTIME - Temperature
;; In addition, IR Needs:
;; TBD
sel = ['FILEPATH','FNISODAT','INTTIME',tempFld]
IF dtctr EQ 1 THEN sel = [sel]

;; Get the data from the SQL server
ON_IOERROR, ioErr
info = DI_sqlQuery(serv,db,tblNm,sel,cond,DIM=dim)
IF min(dim) EQ 0 THEN GOTO, findErr
fn = info[0,*]
dates = info[1,*]
drkParams = transpose(double(info[2:*,*]))

;; Get the local filenames for all the images
fn=getLocFn(fn)
IF error NE 0 THEN GOTO, ioErr

;; Figure out the size of the images
tmp = readFITS(fn[0],/SILENT)
IF size(tmp, /N_DIMENSIONS) EQ 0 THEN GOTO, ioErr
drkDim = size(tmp, /DIMENSIONS)

;; Read in all of the images
darks = intarr(drkDim[0],drkDim[1],dim[1],/NOZERO)
FOR i=0, dim[1]-1 DO BEGIN
	tmp = readFITS(fn[i],hdr,/SILENT)
	IF size(tmp, /N_DIMENSIONS) EQ 0 THEN GOTO, ioErr
	
	;; Correct each dark for uneven bit weighting and linearize
	;IF DIcal_bitWeight(tmp,hdr,tmp) NE 0 THEN GOTO, calibErr
	IF dtctr EQ 1 THEN BEGIN
	;	IF DIcal_linearDN(tmp,hdr,tmp) NE 0 THEN GOTO, calibErr
	ENDIF

	;; Store the corrected dark frame in the uber array
	darks[*,*,i] = tmp
ENDFOR

;; Set up a control for VIS vs IR
IF dtctr EQ 0 THEN BEGIN ;;VIS
	paramCnt = 4
	parinfo = replicate({VALUE:0.D,LIMITED:[0,0],LIMITS:[0.D,0.D]} $
		,paramCnt)
	;; Starting guesses for parameters
	;; Integration time scaling - Bench temp scaling -
	;; Bench Temp Exponential Scaling - Bias
	parinfo[*].value = [1.5d-5,-10.2,0.058,381]
	;; Limits on parameters
	parinfo[0].limited[0] = 1
	;; Evaluation function
	funcName = 'DI_VISDarkFitModel'
ENDIF ELSE BEGIN ;;IR
	paramCnt = 4
	parinfo = replicate({VALUE:0.D,LIMITED:[0,0],LIMITS:[0.D,0.D]} $
		,paramCnt)
	;; Starting guesses for parameters
	parinfo[*].value = [1e-5,16,-1000,500]
	;; Limits on parameters
	;; Evaluation function
	;funcName = 'DI_IRDarkFitModel'
	funcName = 'DI_VISDarkFitModel'
ENDELSE
A = dblarr(drkDim[0],drkDim[1],paramCnt,/NOZERO)

;; Determine model parameters for each pixel
FOR i=100,drkDim[0]-1 DO BEGIN
	FOR j=100, drkDim[1]-1 DO BEGIN
		Y = reform(darks[i,j,*],dim[1])
		coefs = MPFITFUN(funcName,drkParams,Y,1.0, PARINFO=parinfo, $
			AUTODERIVATIVE=0, BESTNORM=check, status=stat, $
			MAXITER=500, yfit=test,/QUIET)
		IF stat EQ 5 THEN GOTO, convErr
		A[i,j,*] = coefs
	ENDFOR
ENDFOR

;; Save the model parameters
IF n_params() EQ 2 THEN BEGIN
	;; Create default output filename
	stfn = dates[0]
	stfn = (strsplit(stfn,'T',/EXTRACT))[0]
	stfn = strsplit(stfn,'-',/EXTRACT)
	stfn = strmid(stfn[0],2)+stfn[1]+stfn[2]
	endfn = dates[dim[1]-1]
	endfn = (strsplit(endfn,'T',/EXTRACT))[0]
	endfn = strsplit(endfn,'-',/EXTRACT)
	endfn = strmid(endfn[0],2)+endfn[1]+endfn[2]
	outFn = stfn+'-'+endfn+strupcase(inst)+strtrim(string(dtctr),2)+'.par'
ENDIF
SAVE, A, FILENAME=outFn
fnCreated = outFn

GOTO, ret

ioErr:
ERROR = 1
GOTO, ret

callErr:
ERROR = 2
!ERROR_STATE.MSG = 'Invalid procedure call'
GOTO, ret

calibErr:
ERROR = 3
!ERROR_STATE.MSG = 'Dark frames could not be calibrated'
GOTO, ret

convErr:
ERROR = 4
!ERROR_STATE.MSG = 'The curve fitting did not converge for pixel:('+ $
	strtrim(string(i),2)+','+ $
	strtrim(string(j),2)+')'
GOTO, ret

findErr:
ERROR = 5
!ERROR_STATE.MSG = 'Valid dark frames could not be found'
GOTO, ret

;; Cleanup and return
ret:
files = FINDFILE('Temp/*.fit')
IF SIZE(files, /N_DIMENSIONS) GT 0 THEN FILE_DELETE, files, /QUIET
RETURN, fnCreated
END