;==============================================================================
; Cleanup pro
pro ng5CalibData::cleanup
compile_opt idl2

ptr_free, self.pData,self.pEfp,self.pEtran,self.pSen

end

;==============================================================================
; Read calibration data file
function ng5CalibData::readFile
compile_opt idl2

;begin error handler------------------------------------------------------------
defsysv,'!debug',exist=debugExist
if (debugExist && (!debug eq 0)) then begin
    catch, catchError
    if (catchError ne 0) then begin
        ;;print, 'Error handled!'
        eTitle = 'Error encountered in ng5CalibData::isNG5Calib()'
        eMsg = 'An error or unusual condition was encountered!'
        eMsg = [eMsg,'Please, report the following to the DAVE team:']
        eMsg = [eMsg,!error_state.msg]
        void = dialog_message(/error,eMsg,title=eTitle)
        free_lun,lun,/force ; close file, if open
        catch, /cancel
        return, 0
    endif
endif
;end error handler-------------------------------------------------------------

filename = self.filename
openr, lun,filename,/get_lun
buffer = strarr(13)
readf, lun, buffer

;nDat = fix(strmid(buffer[0],65,4))
nDat = fix((strsplit(buffer[0],' ',/extract))[7])
Ef = float((strsplit(buffer[7],' ',/extract))[2])
nPix = fix((strsplit(buffer[11],' ',/extract))[2])

colTitles = strsplit(buffer[12],' ',/extract,count=nCol)
eIndex = (where(colTitles eq 'E',found))[0]
if (~found) then begin
  print, 'Energy transfer column not found'
  return, 0
endif

E = fltarr(nDat)
data = fltarr(nDat,nPix)
buffer1 = fltarr(nCol)
buffer2 = fltarr(nPix)
x = findgen(nPix)+1
i = 0

while not eof(lun) do begin
  readf,lun,buffer1,buffer2
  E[i] = buffer1[eIndex]
  data[i,*] = buffer2
  
  ; identify peak intensities and keep rolling sum
  peak_loc = get_peak_pos(x,buffer2,1,fwhm=fwhm,indices=indices)
  if (indices gt 0 and fwhm gt 0.0) then begin
    peakInt = (n_elements(peakInt) gt 0)? [peakInt,buffer2[indices]] : buffer2[indices]
  endif

  i++
endwhile
free_lun,lun,/force

; Determine standard deviation of peak intensities
if (n_elements(peakInt) ge 2) then begin 
  self.sigmaInt = stddev(peakInt) 
  self.meanInt = mean(peakInt)
endif

if (i ne nDat) then begin
  E = E[0:i-1]
  data = data[0:i-1,*]
endif

self.nDat = i
self.nPix = nPix
self.Ef = Ef
self.pData = ptr_new(data,/no_copy)
self.pEtran = ptr_new(E,/no_copy)

return, 1
end

;==============================================================================
; Determine if this is an NG5 (SPINS) data file with PSD used in a+ mode
; where pixels are integrated in the vertical direction.
function ng5CalibData::isNG5CalibFile
compile_opt idl2

;begin error handler------------------------------------------------------------
defsysv,'!debug',exist=debugExist
if (debugExist && (!debug eq 0)) then begin
    catch, catchError
    if (catchError ne 0) then begin
        ;;print, 'Error handled!'
        eTitle = 'Error encountered in ng5CalibData::isNG5Calib()'
        eMsg = 'An error or unusual condition was encountered!'
        eMsg = [eMsg,'Please, report the following to the DAVE team:']
        eMsg = [eMsg,!error_state.msg]
        void = dialog_message(/error,eMsg,title=eTitle)
        catch, /cancel
        return, 0
    endif
endif
;end error handler-------------------------------------------------------------

filename = self.filename
openr, lun,filename,/get_lun
buffer = strarr(12)
readf, lun, buffer
free_lun,lun,/force

; It must be an ICP Q-buffer file: line 1, col 37 should be letter Q
if (~strcmp(strmid(buffer[0],36,1),'Q')) then return, 0

; Is there a '#ASD' entry on line twelve? If so, this is a+ mode SPINS data file
if (~strcmp(strmid(strtrim(buffer[11],2),0,4),'#ASD')) then return, 0

; Measurement must have been performed in fixed-final energy mode
if (~strcmp(strmid(buffer[8],27,8),'EA fixed')) then return, 0

return, 1
end

;==============================================================================
pro ng5CalibData::getProperty,Efix=Efix,nDat=nDat,nPix=nPix $
    ,Etran=eTran, Efp=Efp, sen=sen,data=data,meanInt=meanInt,sigmaInt=sigmaInt
compile_opt idl2

if (arg_present(Efix)) then begin
  Efix = self.Ef
endif
if (arg_present(nDat)) then begin
  nDat = self.nDat
endif
if (arg_present(nPix)) then begin
  nPix = self.nPix
endif
if (arg_present(filename)) then begin
  filename = self.filename
endif
if (arg_present(meanInt)) then begin
  meanInt = self.meanInt
endif
if (arg_present(sigmaInt)) then begin
  sigmaInt = self.sigmaInt
endif
if (arg_present(Etran)) then begin
  eTran = (ptr_valid(self.pEtran))? (*self.pEtran) : 0.0
endif
if (arg_present(Efp)) then begin
  Efp = (ptr_valid(self.pEfp))? (*self.pEfp) : 0.0
endif
if (arg_present(sen)) then begin
  sen = (ptr_valid(self.pSen))? (*self.pSen) : 0.0
endif
if (arg_present(data)) then begin
  data = (ptr_valid(self.pData))? (*self.pData) : 0.0
endif

end 

;==============================================================================
pro ng5CalibData::setProperty,Ef=Ef,nDat=nDat,nPix=nPix $
    ,Etran=eTran, Efp=Efp, sen=sen,data=data
compile_opt idl2

if (n_elements(Ef) eq 1) then begin
  self.Ef = Ef
endif

if (n_elements(nDat) eq 1) then begin
  self.nDat = nDat
endif

if (n_elements(nPix) eq 1) then begin
  self.nPix = nPix
endif

if (n_elements(eTran) gt 0) then begin
  if (ptr_valid(self.pEtran)) then $
    (*self.pEtran) = eTran $
  else $
    self.pEtran = ptr_new(eTran)
endif

if (n_elements(Efp) gt 0) then begin
  if (ptr_valid(self.pEfp)) then $
    (*self.pEfp) = Efp $
  else $
    self.pEfp = ptr_new(Efp)  
endif

if (n_elements(sen) gt 0) then begin
  if (ptr_valid(self.pSen)) then $
    (*self.pSen) = sen $
  else $
    self.pSen = ptr_new(sen)
endif

if (n_elements(data) gt 0) then begin
  if (pr_valid(self.pData)) then $
    (*self.pData) = data $
  else $
    self.pData = ptr_new(data)
endif

end

;==============================================================================
function ng5CalibData::init, filename
compile_opt idl2

; filename parameter must be present
if (n_params() lt 1) then begin
  print, 'A calibration data filename is required'
  return, 0
endif

; check filename exist
finfo = file_info(filename)
if (finfo.read ne 1) then begin
  print,filename,' is not found or cannot be read'
  return, 0
endif

self.filename = filename

; Is this a proper ng5 calibration file?
if (~self->isNg5CalibFile()) then begin
  print,filename,' is not an appropriate SPINS calibration data file'
  return, 0
endif

; Read the data and init data structure
void = self->readFile()

return, 1
end

;==============================================================================
pro ng5CalibData__Define
compile_opt idl2

struct = {ng5CalibData $
          ,filename:'' $
          ,Ef:0.0 $           ; Fixed analyzer final energy
          ,nDat:0 $           ; nos of data points
          ,nPix:0 $           ; nos of pixels
          ,meanInt:0.0 $      ; mean of peak intensities
          ,sigmaInt:0.0 $     ; std deviation of peak intensities
          ,pEtran:ptr_new() $ ; Energy transfer for each data point
          ,pEfp:ptr_new() $   ; Calculated final energy for each pixel
          ,pSen:ptr_new() $   ; Calc. sensitivity for each pixel
          ,pData:ptr_new() $  ; Calibration counts nDat x nPix
          } 
end