; NAME:
;   h2rg::realdark   
;
; PURPOSE:
;   Reads a specified frame of an input dark current FITS file.  The zero-level
;   value of each pixel is subtracted in order to obtain total dark current +
;   read noise accumulated since the start of the dark exposure.  This value
;   is returned to the calling context. 
;   
; INPUTS:
;   framenum    Integer indicating current frame (read) of the dark current
;               image, numbered starting with 0.
;   darkimg     full path name of dark current image to read
;   medimg      pointer to value(s) of zero-level signal for pixels in 
;               dark current exposure
; 
; KEYWORDS:
;   none  
;
; OUTPUTS:
;   dkaccum      accumulated dark current, converted from ADU to electrons
;
Function h2rg::realdark, framenum, darkimg, medimg
    
    ; get the dimensions of the darkcurrent frame
    xsize = (size(*medimg))[1]
    ysize = (size(*medimg))[2]

    ; throw an error up the calling stack if the input median image 
    ; doesn't match the array dimensions
    if (xsize ne self.xsize or ysize ne self.ysize) then begin
        message, 'median dark current frame has dimensions incompatible with ' $
                + 'detector type'
    endif

    ; calculate the number of pixels in one frame
    numpix = long(xsize) * long(xsize)

    ; to find the accumulated dark current, read in the indicated frame of
    ; the dark current exposure
    fits_read, darkimg, dkaccum, dkhdr, first = (framenum) * numpix, $
            last = (framenum + 1) * numpix - 1

    ; the dark current image should have the same dimensions as the median
    ; image, but check to make sure and throw error if the check fails
    if (sxpar(dkhdr, 'naxis1') ne xsize $
            or sxpar(dkhdr, 'naxis2') ne ysize) then begin
        message, 'dark current frame has dimensions incompatible with ' $
                + 'detector type'
    endif
    
    dkaccum = reform(dkaccum, xsize, ysize, /overwrite)
    dkaccum = long(dkaccum)

    ; then subtract off the median frame
    dkaccum = temporary(dkaccum) - (*medimg)

    ; multiply by gain to convert dark current to electrons
    dkaccum = temporary(dkaccum) * self.gain

    return, dkaccum

End

; NAME:
;   h2rg::ips_function   
; PURPOSE:
;   given coordinates within a detector pixel, returns relative sensitivity
;   at that point
; INPUTS:
;   x - x coordinate within pixel
;   y - y coordinate within pixel
; PARAMETER OUTPUTS
;   none 
; RETURNS
;   relative sensitivity (value between 0.0 and 1.0)
; NOTES:
;   origin is at center of pixel, so x and y must each be in range [-0.5,0.5]
;   
Function h2rg::ips_function, x, y

;    if (abs(x) le 0.3) and (abs(y) le 0.3) then begin
;        val = 1.0
;    endif else begin
;        val = 0.0
;    endelse

;   val = exp(-1.0 * sqrt(x^2 + y^2))
;   return, val

    return, 1.0
End

; NAME:
;   h2rg::integrate   
; PURPOSE:
;   modifies accumulated signal over some time interval by the effects of
;   detector non-linearity and adds the result to the detector's integrated
;   signal pixel array
; INPUTS:
;   signal - 2d array of size equal to detector pixel array, containing signal
;            accumulated in some time interval
; PARAMETER OUTPUTS
;   none
; RETURNS
;   none
; NOTES:
;   modifies state of object by adding signal to pixel array
;   
Pro h2rg::integrate, signal

    ; make an image representing the signal for each pixel, as modified
    ; by the nonlinearity of the detector
    c_lin = 9.3d-7
    c_quad = 9.0d-12
    
    modsig = (1.0d - c_lin * (*self.pixels) - c_quad * (*self.pixels)^2) $
            * signal

    ; add the signal to the detector
    self->add, modsig

End

; NAME:
;   h2rg::ad_convert  
;
; PURPOSE:
;   Simulates conversion of detector output in electrons to 16-bit ADU
;   
; INPUTS:
;   img         floating point image read from detector
;   medimg      pointer to value(s) of zero-level signal for pixels in 
;               dark current exposure
; KEYWORDS:
;   none  
;
; OUTPUTS:
;   ADUimg      16-bit integer frame representing detector readout in ADU
;
Function h2rg::ad_convert, img, medimg


    ; simulate A-D conversion by dividing by gain and applying offset
    ADUimg = img / self.gain
    ADUimg = temporary(ADUimg) + (*medimg)

    ; find pixels above top A-D rail and below min A-D rail
    hirailed = where(ADUimg gt 32767)
    lorailed = where(ADUimg lt -32768)
 
    ; set railed pixels to the upper or lower limit 
    if (hirailed[0] ne -1) then begin
        ADUimg[hirailed] = 32767
    endif

    if (lorailed[0] ne -1) then begin
        ADUimg[lorailed] = -32768
    endif
 
    ; round to the nearest long (32-bit) integer
    ADUimg = round(ADUimg)
 
    ; change to 16-bit integer
    ADUimg = fix(ADUimg)

    return, ADUimg
End

; NAME:
;   h2rg::get_frametime  
;
; PURPOSE:
;   Return time to read out detector
;   
; INPUTS:
;   none
;
; KEYWORDS:
;   none  
;
; OUTPUTS:
;   see Purpose description
;
Function h2rg::get_frametime

    ; define time to read one quadrant (100 khz pixel read rate) in seconds
    ; this is the time to read the whole frame, as 4 quadrants are read
    ; simultaneously
    
    frametime = (long(self.xsize) * long(self.ysize) / 4l) * self.pixeltime

    return, frametime

End

; NAME:
;   h2rg::calc_readtimes  
;
; PURPOSE:
;   Calculates times at which each readout of a multi-read exposure is started.
;   
; INPUTS:
;   numsamrd        number of up-the-ramp read groups
;   numutr          number of detector readouts in each utr group
;   t_exp           total exposure time of utr image
;   t_frm           time to read one frame of detector
;
; KEYWORDS:
;   none  
;
; OUTPUTS:
;   readtimes       array containing the start times for each read
;
Function h2rg::calc_readtimes, numsamrd, numutr, t_exp, t_frm 

    ; find start time of each read (measured from pixel reset, assuming
    ; pixel-by-pixel reset)
    readtimes = fltarr(numsamrd, numutr)
    readtimes[0,*] = findgen(numutr) * t_exp / (numutr - 1) + t_frm
    if (numsamrd gt 1) then begin
        for groupnum = 0, numutr - 1 do begin
            readtimes[1:*, groupnum] = readtimes[0, groupnum] + $
                (findgen(numsamrd - 1) + 1) * t_frm
        endfor 
    endif

    readtimes = reform(readtimes, numsamrd * numutr, /overwrite)

    return, readtimes
End


; NAME:
;   h2rg__init
;
; PURPOSE:
;   constructor for h2rg object
; 
; INPUTS:
;   name            string containing identifying name of h2rg object
; 
; KEYWORDS:
;   welldepth       signal capacity of detector pixels (e-)
;   gain            conversion gain of detector (e-/ADU)
;
; OUTPUTS:
;   returns 1 to indicate successful object creation
;
Function h2rg::init, name, welldepth=welldepth, gain=gain

    ; call the constructor of the parent class.  This seems to be necessary in
    ; order to compile all of the methods defined in the detector class that
    ; are not overridden by the h2rg class.
    rval = self->detector::init()

    ; set object properties
    self.detname = name
    self.xsize = 2048
    self.ysize = 2048
    self.pix_x = 18.0
    self.pix_y = 18.0
    self.pix_z = 10.0
    
    if (keyword_set(welldepth)) then begin
        self.welldepth = welldepth
    endif

    if (keyword_set(gain)) then begin
        self.gain = gain
    endif

    self.amps = ptr_new(objarr(4))

    ; create the amps
    amp_pix = replicate({pixel}, 2, 4)
    amp_pix[0,0] = {pixel, 0, 2047}
    amp_pix[1,0] = {pixel, 511, 0}
    amp_pix[0,1] = {pixel, 1023, 2047}
    amp_pix[1,1] = {pixel, 512, 0}
    amp_pix[0,2] = {pixel, 1024, 2047}
    amp_pix[1,2] = {pixel, 1535, 0}
    amp_pix[0,3] = {pixel, 2047, 2047}
    amp_pix[1,3] = {pixel, 1536, 0}

    for i = 0, 3 do begin
        (*self.amps)[i] = obj_new('amp', 600.0, amp_pix[0,i], amp_pix[1,i])
    endfor

    self.pixeltime = 1.0e-5

    ; set science pixel boundaries.  Reference pixels for H2RG are the outer
    ; four rows and columns, so the good pixel range is [4:2043, 4:2043]
    self.scipix = [4, 2043, 4, 2043] 

    return, 1
End
