;+
; NAME:
;     INSERT_REC
; PURPOSE:
;     Inserts records (generally calibration segments) into a data (.ARC) file
;     to replace all segments of the same type.  If the segment to be inserted
;     is longer than the segments to be replaced, the output file grows accordingly.
; CATEGORY:
;     OVRO APC FILE
; CALLING SEQUENCE:
;     insert_rec[,orec=orec]
; INPUTS:
; OPTIONAL (KEYWORD) INPUT PARAMETERS:
;     orec    output record number to insert the record at.  Care must
;               be taken to ensure that this is the correct record.
; ROUTINES CALLED:
;     CREATE_INDEX
; OUTPUTS:
; COMMENTS:
; SIDE EFFECTS:
;     The input data (.ARC) file is changed, or optionally a new data (.ARC)
;     file is written.
; RESTRICTIONS:
; MODIFICATION HISTORY:
;     Written  12-Apr-2001 by Dale E. Gary
;     28-Jun-2003  DG
;       Change filter to *.rec for "record" file name.  Add keyword
;       to select the output record to replace.  Make the default
;       output filename the same as the input filename.
;     24-Aug-2005  DG
;       When a new output file is created (because new records are needed),
;       the INDEX record must be updated, too.  Added code to do this.
;     05-Sep-2005  DG
;       Fixed slight bug in which changes introduced last week did not work
;       unless file was updated.
;-

pro insert_rec,orec=orec

   ; Get source .ARC filename
   file = dialog_pickfile(path=!defaults.datadir,filter='*.arc',$
       title='Choose file to insert record into.')
   if (file eq '') then return
   break_file,file,disk,dir,stem,ext
   destfile = stem+ext

   ; Get source CAL filename
   recfile = dialog_pickfile(path=!defaults.ephemdir,filter='*.rec',$
       title='Choose record to insert.')
   if (recfile eq '') then return

ask:
   ; Get destination .ARC filename (may be the same as source)
   outfile = dialog_pickfile(path=!defaults.workdir,filter='*.arc',file=destfile,$
       /write,title='Enter filename for output.')
   if (outfile eq '') then return

   ; Open the files
   if (oktowrite(outfile) eq 'Yes') then begin
      ; See if the source and destination are the same
      if (file eq outfile) then begin
         ; Source and destination are the same so set UPDATE=1 to indicate this.
         ; Open the destination file as U (opens file for updating)
         openu,/get_lun,outlun,outfile
         update = 1
         fs = fstat(outlun)
         nrec = fs.size/2048.
      endif else begin
         ; Source and destination are different, so set UPDATE=0
         ; Open the destination file as W (creates a new file)
         update = 0
         openw,/get_lun,outlun,outfile
      endelse
      ; In either case, the destination file has associated variable B
      b = assoc(outlun,intarr(1024))
   endif else goto,ask

   ; If source and destination are different, then open source file
   ; with associated variable A
   if (update eq 0) then begin
      lun = openarc(file,a,nrec)
      ; Get index structure from source file
      idx = ovsa_get_index(a,nrec)
      if (size(idx,/type) ne 8) then begin
         print,'INSERT_REC: Error, input file has no index.  Please run OVSA_MAKE_INDEX first.'
         free_lun,lun,outlun
         return
      endif
   endif

   ; Open the source CAL file, and set to associated variable CAL
   openr,/get_lun,reclun,recfile
   cal = assoc(reclun,intarr(1024))
   fs = fstat(reclun)
   nrecal = fs.size/2048.       ; Number of records in CAL file
   ; Create an array to hold the contents of the source CAL file, and read
   ; the CAL file
   calrec = intarr(1024,nrecal)
   for i = 0, nrecal-1 do calrec[*,i] = cal(i)
   calsegtype = ishft(uint(calrec[2,0]),-8)     ; Integer giving the SEGMENTCODE
   free_lun,reclun

   inrec = 0
   outrec = 0
   id = progmeter(/init)
   ; Loop over source .ARC records
   while (inrec lt nrec) do begin
      res = progmeter(id,float(inrec)/nrec)
      ; Get data from source .ARC file for this record and check the SEGMENTCODE
      if (update eq 0) then data = a[inrec] else data = b[inrec]
      segtype = ishft(uint(data[2]),-8)

      ; If the output record was specified, then skip replacement
      ; unless orec = inrec+1
      if (n_elements(orec) ne 0) then begin
         if (orec ne (inrec+1)) then begin
            goto,skip
         endif else begin
            print,'Found desired record, segment type: ',(tag_names(!segm))[segtype-1]
         endelse
      endif

      if (segtype eq calsegtype) then begin
         ; The SEGMENTCODE matches, so write out records from the source CAL file
         for i = 0, nrecal-1 do begin
            inskip = 1
            if (i gt 0) then begin
               ; Get next data record from source .ARC file and again check the SEGMENTCODE
               if (update eq 0) then data = a[inrec] else data = b[inrec]
               if (ishft(uint(data[2]),-8) ne calsegtype) then begin
                  ; Oh-oh, the next SEGMENTCODE does not match, meaning that the
                  ; number of records in the source .ARC file for this SEGMENT type is
                  ; different than the number of records in the source CAL file.  This
                  ; can happen if the segment contents have been changed (as with TPCAL
                  ; segments, which went from 1 to 2 records after some older data were
                  ; written).  We will just write the extra record without advancing the
                  ; source .ARC file pointer, and carry on from there.  However, this
                  ; only works if UPDATE is 0.
                  if (update ne 0) then begin
                     ans = dialog_message(['Segment being replaced in source .ARC file has fewer records',$
                                           'than that being inserted.  You must give a different destination',$
                                           'filename.'],/error)
                     goto,bail
                  endif
                  inskip = 0     ; Signifies that OUTREC is advanced, but not INREC
                  ; Add 1 to all INDEX record numbers greater than OUTREC
                  incr = where((*idx.pscan).srec gt outrec,nincr)
                  if (nincr ne 0) then (*idx.pscan)[incr].srec = (*idx.pscan)[incr].srec + 1
                  incr = where((*idx.psegs).srec gt outrec,nincr)
                  if (nincr ne 0) then (*idx.psegs)[incr].srec = (*idx.psegs)[incr].srec + 1
                  for k = 0, n_elements(*idx.pscan)-1 do begin
                     incr = where((*idx.pscan)[k].recs gt outrec,nincr)
                     if (nincr ne 0) then (*idx.pscan)[k].recs[incr] = (*idx.pscan)[k].recs[incr] + 1
                  endfor
               endif
            endif
            ; Replace CALREC record number with OUTREC record number
            calrec[0,i] = outrec+1
            ; Replace CALREC nrs (number of record in segment) number with INREC nrs number
            calrec[2,i] = (calrec[2,i] and 'ff00'x) + (data[2] and 'ff'x)
            ; Write out this record
            b[outrec] = calrec[*,i]
            outrec = outrec+1                 ; Advance outfile record pointer
            if (inskip eq 1) then begin
               ; The normal case, advance infile record pointer
               inrec = inrec+1
               inskip = 1
            endif
         endfor
      endif else begin
skip:
         if (update eq 0) then begin
            ; Change record number in DATA to OUTREC (in case it is different from INREC)
            data[0] = outrec+1
            b[outrec] = data
         endif
         ; Advance both infile and outfile pointers
         inrec = inrec+1
         outrec = outrec+1
      endelse
   endwhile

   ; Presumably it worked, so update the index record if we wrote a new file
   if (update eq 0) then begin
      ; Find the INDEX segment
      iidx = find_index(b,outrec)-1
      idxrecs = intarr(1024,10)
      if (iidx ne -1) then begin
         ; Read the 10 records of the INDEX
         for i = 0, 9 do begin
            idxrecs[*,i] = b(iidx+i)
         endfor
         ; Replace the index records with the contents of the changed index structure, IDX
         if (idx_encode(idxrecs,idx) ne 0) then begin
            ; IDX contents have updated the records, so write them out again
            for i = 0, 9 do begin
               b(iidx+i) = idxrecs[*,i]
            endfor
            goto, bail  ; Success!
         endif
      endif else begin
         print,'INSERT_REC: Error, index record could not be updated'
      endelse
   endif

bail:
   res = progmeter(id,/destroy)

   if (update eq 0) then free_lun,lun
   free_lun,outlun

return
end