;-----------------------------------------------------------------------------
; NAME: READHISTORY
;
; PURPOSE: To read a HISTORY object into a string array variable
;
; CALLING SEQUENCE: Result = READHISTORY (filename, label, objindex [,/SILENT]
;
; INPUTS:
;     Filename: Scalar string containing the name of the PDS file to read
;     Label: String array containing the image header information
;     Objindex: Integer specifying the starting index of the current object
;         in the label array to be read.

; OUTPUTS:
;     Result: string array constructed from designated record
;
; OPTIONAL INPUT:
;     SILENT: suppresses any messages from the procedure
;
; PROCEDURES USED:
;     Functions: POINTPDS, PDSPAR, GET_ALL_OBJECTS
;
; MODIFICATION HISTORY:
;
;     Written by:    Lev Nagdimunov [Jan 23, 2015]
;     Last modified: Lev Nagdimunov [Mar 02, 2016]
;
;     For a complete list of modifications, see changelog.txt file.
;
;-----------------------------------------------------------------------------


;-----------------------------------------------------------------------------
; precondition: filename is a viable pds label file name for the file that contains
;               the HISTORY object, label is a viable PDS label string array,
;               objindex is an integer specifying the starting index of the 
;               HISTORY object in the label array.
; postcondition: this subroutine locates and reads the data from the filename
;                and returns the HISTORY object data as a byte array
function read_history_data, filename, label, objindex


  ; Determine object indicies
  FORWARD_FUNCTION get_all_objects
  objects = get_all_objects(label)
  
  ; Determine the pointer positions for each object
  object_pointer_pos = LON64ARR(1, objects.count, /NOZERO)

  ; Save label filename (pointpds changes it)
  label_filename = filename

  for i=0, objects.count-1 do begin
    pointer = pointpds(label, label_filename, objects.array[i])
    object_pointer_pos[i] = pointer.skip
    label_filename = filename
  endfor

  ; Determine if the HISTORY object is the last object in the file or not
  history_pointer = pointpds(label, filename, "HISTORY")

  sorted_pointer_pos = object_pointer_pos[sort(object_pointer_pos)]
  sorted_history_obj_num = where(sorted_pointer_pos eq history_pointer.skip)
  file_info = file_info(filename)

  ; If the HISTORY object is not last then read from its beginning to the beginning of the next object
  if (sorted_history_obj_num lt (objects.count-1)) then begin

    next_obj_pointer = sorted_pointer_pos[sorted_history_obj_num+1]

    ; Adjustment for detached labels. Not trivial to find whether label is detached or attached. If we cannot
    ; read to next object because of EOF, it is likely this is an deattached label (and thus does not have the
    ; next object), in which case we can read the entire file after the history object starts.
    if next_obj_pointer GT file_info.size then begin
      next_obj_pointer = file_info.size
    endif

    data = bytarr(next_obj_pointer - history_pointer.skip, 1)

    ; If the HISTORY object is last in file containing attached label then read from its beginning to the end of file
  endif else begin

    data = bytarr(file_info.size - history_pointer.skip, 1)

  endelse

  ; error protection:
  on_ioerror, endfunction

  ; Read HISTORY object from file
  openr, unit, history_pointer.datafile, /get_lun
  point_lun, unit, history_pointer.skip

  readu, unit, data

  close, unit
  free_lun, unit
  
  return, data

  endfunction:
    on_ioerror, null
    close, unit
    free_lun, unit
    return, -1

end

;-----------------------------------------------------------------------------
; precondition: filename is a viable pds label file name for the file that contains
;               the HISTORY object, label is a viable PDS label string array,
;               objindex is an integer specifying the starting index of the
;               HISTORY object in the label array, silent is a flag indicating 
;               whether to suppress informational messages.
; postcondition: this subroutine locates and reads the data from the filename
;                and returns the HISTORY object data as a string array
function readhistory, filename, label, objindex, SILENT=silent

  ; Check for keywords
  silent = keyword_set(SILENT)

  if (~silent) then begin
    print, "Now reading HISTORY object."
  endif

  ; Find and read HISTORY data from file
  data = read_history_data(filename, label, objindex)

  if (n_elements(data) EQ 1) then begin
    if (data EQ -1) then goto, endfunction
  endif

  ; Convert binary data to string array
  linebreak = string(13b) + string(10b)
  data = strsplit(string(data), linebreak, /extract)

  ; Find the last line in the HISTORY object
  endlines = where(strmatch(strtrim(data, 2), 'END') eq 1, end_count)
  if (end_count gt 0) then begin
    endline = endlines[end_count-1]
  endif else begin
    endline = -1
  endelse

  ; Add line breaks back to the data (must be after endlines)
  data = data + linebreak

  if (endline eq -1) then begin
    goto, endfunction
  endif else begin
    data = data[0:endline]
  endelse

  return, data

  endfunction:
  print, "Warning: empty or malformed HISTORY object."
  return, ''
end