;pro median_difference_of_reads
;
;PURPOSE:
;	To take a collection of images of a given type, i.e. a combination of 
;	a given number of reads and object type (Flat, Dark, M16,...) and get 
;	the median value of the pixels and then write them to a fits file.
;
;	The resulting file will be an Naxis1xNaxis2 image since there is 
;	only a difference of two reads and the median of this difference is 
;	taken across multiple files.
;
;OUTPUTS:
;	Median_[ObjectName]_[Filter]_[NReads].fits
;
;	The median of the difference of LASTREAD-FIRSTREAD for all
;	of the filenames corresponding to the combination of the bracketed
;	keywords above.
;
;KEYWORDS:
;	ROOTDIR: 
;	  The Directory holding the directories of Raw files
;	DATE:
;	  The Date during which they were taken.  Also the subdirectory that 
;	  the files are in.
;	REDUCEDDIR:
;	  The directory where the processed images and plots will be placed in.
;	BLOCKLENGTH:
;	  An offset for files that were written improperly.  The readu 
;	  function reads the values with this offset in place.
;	OBJECTNAME:
;	  The string that indicates what files are being sought.  The filenames
;	  should begin with this string ('Dark', 'Flat', etc.).
;	NREADS:
;	  The number of reads (NAXIS3) that are present in the file.  This
;	  is also a string in the filename that will be used as a regular
;	  expression in searching for matched files.
;	THISFILTER:
;	  The filter through which the files were taken. ('I', 'G', or 'Y')
;
;NOTE:
;	For dark exposures, the median of the zeroth read is taken and 
;	this is the first frame in the cube that is written to disk.  
;	However, for the following reads, the bias is subtracted from
;	each exposure. So the 1st through Nth frames in the cube are 
;	the median of bias-subtracted reads from individual exposures.
;
;CALLING SEQUENCE:
;
; To get the median bias from all the 30 read bias frames on 07Apr 25
;
; Median_of_all_Reads, Date='07Apr25', objectname = 'Bias', nreads = 30, $
;	ThisFilter ='Blank',/override,
;
;
;*************************************************************************
pro Median_Of_All_Reads, RootDir=RootDir, Date=Date, $
	 ReducedDir = ReducedDir, BlockLength = BlockLength, $ 
	 ObjectName=ObjectName, NReads = NReads, ThisFilter = ThisFilter,$
	 OverRide = OverRide, Rem60Hz = Rem60Hz, TvFlag = TvFlag, $
	 BiasSub = BiasSub, SubtractDark = SubtractDark, $
	 ThisNDrops = ThisNDrops
  
  Common KeyParams, KeyStr

  ;Get all of the defaults for the keywords from the KeywordStruct file
  @KeywordStruct.pro
  @PlotSettings.pro
 
  ;Swithc to the directory with the files
  cd, Rootdir+Date
  
  ;Conditional Strings and Directories
  If stregex(KeyStr.ObjectName, 'Dark', /boolean)  or $
     stregex(KeyStr.ObjectName, 'Bias', /boolean) then begin 
     KeyStr.ReducedDir = KeyStr.ReducedDir+'Darks'+KeyStr.PathDelim	
  EndIf Else if stregex(KeyStr.ObjectName, 'Flat', /boolean) then begin
     KeyStr.ReducedDir = KeyStr.ReducedDir+'Flats'+KeyStr.PathDelim
     KeyStr.TotalReads = 2
  EndIf Else begin
     KeyStr.ReducedDir = KeyStr.ReducedDir+'Sky'+KeyStr.PathDelim
     File_Mkdir, KeyStr.ReducedDir
  EndElse

  ;Check to see if 60 hz signal should be removed
  If KeyStr.Rem60Hz then begin 
     KeyStr.Rem60HzStr = '_60HzRemoved'
  EndIf else begin 
     KeyStr.Rem60HzStr = ''
  EndElse

  ;****************************************************************************
  ;Check to see if the Median Dark already exists and only write if it doesn't
  MedianFile = file_search(KeyStr.ReducedDir+'Median'+KeyStr.ObjectName+'_'+$
		KeyStr.ThisFilter+$
               '_ForEachOf_'+Strtrim(KeyStr.TotalReads,2)+'Reads.fits')

  ;If Dark does not exist, form the median and write the image
  If MedianFile(0) eq '' or OverRide then begin
    print, 'Forming Median Image for Combination of:' 
    print, 'Object: ' + KeyStr.ObjectName
    print, 'Filter: ' + KeyStr.ThisFilter
    print, '# Reads:' +  strtrim(KeyStr.TotalReads,2)  

    ;Get all of the Dark Files for this Number of Reads
    RawFiles = File_Search(KeyStr.ObjectName+'*'+strtrim(KeyStr.TotalReads,2)+$
	'_Reads*.fits')

    ;Get the files with the right filter
    RawFiles = Return_File_List(RawFiles, ThisFilter = KeyStr.ThisFilter, $
				ThisNDrops=ThisNDrops)	

    ;Update all of the elements of the key structure
    FileCheck = Return_File_Params(RawFiles(0))

    ;Form a dummy array for all of the darks of a given Naxis3 to provide the
    ;necessary keywords for a fits header
    NumRawFiles = N_elements(RawFiles)
    MedianAxes = [KeyStr.Naxis1, KeyStr.Naxis2, KeyStr.TotalReads]
    MkHdr, MedFitsHeader, Naxis, MedianAxes
    FxAddPar, MedFitsHeader, 'DIRDATE', KeyStr.Date, $
	'Date on which the images were taken'
    FxAddPar, MedFitsHeader, '60HZFIL', KeyStr.Rem60HzStr, $
	'Null String indicates no removal of Common Mode Noise'
    FxAddPar, MedFitsHeader, 'NGROUPS', KeyStr.NGroups, $
	'Number of Groups'
    FxAddPar, MedFitsHeader, 'NREADS', KeyStr.NReads, $
	'Number of Reads'
    FxAddPar, MedFitsHeader, 'NDROPS', KeyStr.NDrops, $
	'Number of Drops'
    FxAddPar, MedFitsHeader, 'FILTER', KeyStr.ThisFilter, $
	'Filter used in images of median' 
    FxAddPar, MedFitsHeader, 'BIASSUB', KeyStr.BiasSub, $
	'Individual bias frames were subtracted'
    If KeyStr.SubtractDark then $
    FxAddPar, MedFitsHeader, 'COMMENT', $
	'Frame 0 = Median of zeroth reads; Frames 1-N = Median of Bias '+$
	'subtracted reads'
    ;Put all of the filenames that were used to form the median in the header
    for FileNum = 0, NumRawFiles-1 do begin
        FxAddPar, MedFitsHeader, 'FILE'+Strtrim(FileNum, 2), $ 
	          RawFiles(FileNum), 'Name of file used in median'
    endfor
    If KeyStr.SubtractDark then begin 
       ;Check to see if we should subtract the median dark
       print, 'Using Dark : '+ KeyStr.DarkName
       Fits_Read_DataCube, KeyStr.DarkName, DarkIm, DarkHeader
       KeyStr.DarkSubStr = ''
     EndIf Else Begin
       If not Stregex(KeyStr.ObjectName, 'Bias',/boolean) and $
          not Stregex(KeyStr.ObjectName, 'Dark',/boolean) then begin
         KeyStr.DarkSubStr = 'NoDarkSubtracted'
       EndIf else begin
         KeyStr.DarkSubStr = ''
       EndElse
     EndElse

    ;Form a filename with some parameters and open the datacube
    FitsFileName = KeyStr.ObjectDir+'Median'+KeyStr.ObjectName+'_'+$
		KeyStr.ThisFilter+'_ForEachOf_'+Strtrim(KeyStr.TotalReads,2)+$
		'Reads'+$
	        KeyStr.Rem60HzStr+KeyStr.DarkSubStr+'.fits'
    Position = Fits_Open_DataCube(FitsFileName, MedFCB, MedFitsHeader, 'Write')
     
    ;Form Cube of Medians for each Read  
    for ReadNum = 0, KeyStr.TotalReads - 1 do begin
       print, 'Processing Read Number '+Strtrim(ReadNum, 2) + ' Out of ' + $
	      Strtrim(KeyStr.TotalReads,2) +' Reads'

       ;Form an array to hold the values for the median
       RawFrames = LonArr(Naxis1, Naxis2, NumRawFiles)
 
       ;Loop through files for each read and take median at end
       for FileNum = 0, NumRawFiles - 1 do begin
	
           ;Double check filter
	   Fits_Read,  RawFiles(FileNum), NoData, RawFitsHeader, /header_only
           Filter = SxPar(RawFitsHeader ,'FILTER')
	   print, RawFiles(FileNum)
	   print, 'Read: ', ReadNum, ' ' , 'File: ', FileNum, ' ', $
	           Filter 
           ;Get Bias Read of Raw Frame and subtract Ch0 if necessary
	   RawBias = long(Fits_Read_DataCube_Region($
		  RawFiles(FileNum), RawFCB, RawFitsHeader, $
		  0, KeyStr.Naxis1-1, 0, KeyStr.Naxis2-1, $
		  0, 0))
	   If KeyStr.Rem60Hz then RawBias = RefSub_Ch0(RawBias)
           ;Get Read of Dark Frames
	   RawFrames(*,*, FileNum) = long(Fits_Read_DataCube_Region($
		  RawFiles(FileNum), RawFCB, RawFitsHeader, $
		  0, KeyStr.Naxis1-1, 0, KeyStr.Naxis2-1, $
		  ReadNum, ReadNum))
           If KeyStr.Rem60Hz then RawFrames(*,*,FileNum) = $
                RefSub_Ch0(RawFrames(*,*,FileNum))

	   ;Subtract the Bias and a dark frame if requested
	   If KeyStr.BiasSub eq 1 and ReadNum gt 0 then $
		RawFrames(*,*,FileNum) = $
		RawFrames(*,*,FileNum)-RawBias

	   If KeyStr.SubtractDark and ReadNum gt 0 then begin $
		DarkFrame = long(DarkIm(*,*,ReadNum))
		RawFrames(*,*,FileNum) = $
	        RawFrames(*,*,FileNum)-DarkFrame
	        stop
	   EndIf

	   ;Default verbosity
	   print, 'Min Pixel Value',  Min(RawFrames(*,*,FileNum)), string(9B),$
                  'Max Pixel Value',  Max(RawFrames(*,*,FileNum))
           print, 'Mean Pixel Value', Mean(RawFrames(*,*,FileNum)),string(9B),$
                  'Std Dev',          StdDev(RawFrames(*,*,FileNum))

           ;Do some plotting if desired
           If KeyStr.TvFlag eq 1 then begin
             window, 0 , xpos = 2*fix(float(XScreenSize)/3), $
                         ypos = 0, $
                         xsize = fix(float(XScreenSize)/3), $
                         ysize = fix(float(YScreenSize)/2)

             tvscl, congrid(RawFrames(*,*,FileNum),512,512)
             PixHis = histogram(RawFrames(*,*,FileNum) , locations = LocPix)
             window, 1 , xpos = 2*fix(float(XScreenSize)/3), $
                         ypos = fix(float(YScreenSize)/2), $
                         xsize = fix(float(XScreenSize)/3), $
                         ysize = fix(float(YScreenSize)/2)

             Plot, LocPix, PixHis, psym = 10
           EndIf

	   ;Make sure to delete the current file control block for fits_open
	   FitsClose = Fits_Close_DataCube(RawFCB)
           Delvarx, RawFCB
 
	endfor

	;Take the median row by row across the files; memory errors otherwise
	MedianOfRead = LonArr(Naxis1, Naxis2)
        for Row = 0, KeyStr.Naxis2 -1 do begin 
          MedianOfRead(*, Row) = Long(median(RawFrames(*,Row,*), dimension =3))
	endfor
	
	;Write it to the cube and delete it afterwards to avoid crash
        DataCubeWrite = Fits_Append_DataCube(MedFCB,MedianOfRead)
	Delvarx, MedianOfRead
	Delvarx, RawFrames

    endfor	

    DataCubeClose = Fits_Close_DataCube(MedFCB)
    print, 'Median Dark Image written with filename: '
    print, KeyStr.ObjectDir+'Median'+KeyStr.ObjectName+'_'+$
	   KeyStr.ThisFilter+$
           '_ForEachOf_'+Strtrim(KeyStr.TotalReads,2)+'Reads'+$
	   KeyStr.Rem60HzStr+KeyStr.DarkSubStr+'.fits'


  EndIf else begin
        
    ;The File already exists
    print, 'Median Dark Image: '+KeyStr.ObjectDir+$
	   'Median'+KeyStr.ObjectName+'_'+$
	   KeyStr.ThisFilter+'_ForEachOf_'+Strtrim(KeyStr.TotalReads,2)+$
	  'Reads'+$
	   KeyStr.Rem60HzStr+$
	   KeyStr.DarkSubStr+'.fits'+$
	   ' already exists...continuing'
 
  EndElse

stop

end
