;----------------------------------------------------------------------------------------
; NAME: PDSPAR
;
; PURPOSE: Obtain the value of a parameter in a PDS header
;
; CALLING SEQUENCE:
; result = PDSPAR( lbl, name [, ABORT, OBJECT=, MVAL=, COUNT=, INDEX=])
;
; INPUTS:
;    Lbl:  PDS header array, (e.g. as returned by SXHREAD or READPDS)
;       string array, each element should have a length of 80
;       characters
;    Name: String name of the parameter to return.
;
; OUTPUTS:
;    result: value of parameter in header. If parameter is double
;       precision, float, long or string, the result is of that type.
;
; OPTIONAL INPUTS:
;    OBJECT: string specifying object name and narrowing PDSPAR to
;       return parameters only found inside that object
;    ABORT: string specifying that PDSPAR should do a RETALL
;       if a parameter is not found.  ABORT should contain
;       a string to be printed if the keyword parameter is not found.
;       If not supplied PDSPAR will return with a negative
;       !err if a keyword is not found.
;
; OPTIONAL OUTPUTS:
;     COUNT: Optional keyword to return a value equal to the number of
;        parameters found by PDSPAR, integer scalar
;     MVAL: Optional keyword to return the value of requested keyword
;        that exceeds the normal allowable string size that can be
;        printed by the PRINT function. The 'zeroth' record of MVAL-
;        MVAL(*,0) contains the number of following records that
;        contain meaningful information.
;     INDEX: Optional keyword to return an array of the line numbers
;        where the values being returned were found in the PDS label.
;
; SIDE EFFECTS:
;    Keyword COUNT returns the number of parameters found.
;    !err is set to -1 if parameter not found, 0 for a scalar
;    value returned.
;
;
; EXAMPLES:
;    Given a PDS header, h, return the values of the axis dimension
;    values. Then return the number of sample bits per pixel.
;
;    IDL> x_axis = pdspar( h ,' LINES')         ; Extract Xaxis value
;    IDL> y_axis = pdspar( h ,' LINE_SAMPLES')  ; Extract Yaxis value
; 
;    ; Extracts bits/pixel value for the IMAGE object
;    IDL> bitpix = pdspar( h ,' SAMPLE_BITS', OBJECT='IMAGE')   
; 
;
; PROCEDURE:
;    Each element of lbl is searched for a '=' and the part of each
;    that preceeds the '=' is saved in the variable 'keyword', with
;    any line that contains no '=' also saved in keyword. 'keyword'
;    is then searched for elements that exactly match Name, if none
;    are found then 'keyword' is searched for elements that contain Name.
;    If either search succeeds then the characters that follow the '='
;    in the matching lines are returned.
;
;    An error occurs if both above searches fail.
;
;    The values returned are converted to numeric value, if possible,
;    by the STR2NUM function.
;
;    NOTE:
;
;    PDSPAR requires that the label being searched has records of
;    standard 80 byte length (or 81 bytes for UNIX stream files).
;
; PROCEDURES USED:
;    Functions: GET_INDEX
;
; MODIFICATION HISTORY:
;    Written by:     J. Koch       [Jul 01, 1994]
;                    Some sections adapted from SXPAR.PRO by DMS.
;    Last modified:  L. Nagdimunov [Jan 23, 2015]
;
;    For a complete list of modifications, see changelog.txt file.
;
;----------------------------------------------------------------------

;Added for 06 Aug 2008 Fix
function get_matching_char, ipchar
        CASE ipchar OF
             '"': return,'"'
             '(': return,')'
             '{': return,'}'
             '[': return,']'
            ELSE: return,'"'
        ENDCASE
end

; Added by L.Nagdimunov 23Jan2015 (modified 14Dec2015)
; Returns an array of the lbl lines on which the END_OBJECT statement occurs for a given object name inside lbl
function find_object_end, lbl, object_name
  objects = pdspar(lbl, "OBJECT", INDEX=obj_indx)
  obj_mtch_indx = where(objects eq object_name, num_obj_mtch)

  if (num_obj_mtch eq 0) then begin
    print, 'Error: No object named ' + strtrim(object_name) + ' found.'
    return, -1
  endif

  obj_start_indx = (obj_indx[obj_mtch_indx])

  for i=0, n_elements(obj_start_indx)-1 do begin
    new_end_idx = get_index(lbl, obj_start_indx[i])
    end_idx = (n_elements(end_idx) eq 0) ? [new_end_idx] : [end_idx, new_end_idx]
  endfor
    
  return, end_idx
end

function PDSPAR, lbl, name, abort, OBJECT=object, MVAL=mvalue, COUNT=matches, INDEX = nfound

 params = N_params()
 if params LT 2 then begin
    print,'Syntax - result = pdspar(lbl,name [,abort,OBJECT=,MVAL=,COUNT=,INDEX= ])'
    return, -1
 endif

 value = 0
 
 if params LE 2 then begin
    abort_return = 0
    abort = 'PDS Label'
 endif else begin
    abort_return = 1
 endelse
 
 if abort_return then On_error,1 else On_error,2

;Check for valid header

 s = size(lbl)          ;Check header for proper attributes.
 if (s[0] NE 1) or (s[2] NE 7) then begin
    message,abort+' (first parameter) must be a string array'
 endif

;Copy name, make upper case  ;line100

 nam = strtrim(strupcase(name),2)

;Loop on lines of the header

  ; Added by L.Nagdimunov 23Jan2015 (modified 14Dec2015)
  ; Added OBJECT keyword
  lbl_search = lbl
  if keyword_set(object) then begin
    objarray = pdspar(lbl, "OBJECT", INDEX=objarray_indicies)

    objarray_matches = where(strupcase(objarray) eq strupcase(object))

    ; If no matching objects found (then we replace entire label with a blank
    ; so no results for anything can be found)
    if (n_elements(objarray_matches) eq 1) then begin
      if (objarray_matches eq -1) then lbl_search = ['']

    ; For matching objects found
    endif else begin

      obj_start_indx = objarray_indicies[objarray_matches]
      obj_end_indx = find_object_end(strupcase(lbl), strupcase(object))
      num_matching_objects = n_elements(objarray_matches)
  
      for i=0, num_matching_objects-1 do begin
  
        ; Replace label content to be searched outside of OBJECTs of interest with blanks
        if i eq 0 then begin
          if obj_start_indx[i] gt 0 then lbl_search[0:obj_start_indx[i]-1] = ''
        endif else begin
          lbl_search[obj_end_indx[i-1]+1:obj_start_indx[i]-1] = ''
        endelse
        
        if i eq (num_matching_objects-1) then begin
          if obj_end_indx[i] lt n_elements(lbl) then lbl_search[obj_end_indx[i]+1:*] = ''
        endif
      endfor
      
    endelse
    
  endif

;Modified A.Cardesin 2006Feb13: changed ' = ' into '='
 
 key_end = strpos(lbl_search,'=')                       ;find '=' in all lines of lbl
 r = size(key_end)
 stopper = r[r[r[0]-1]]
 keyword = strarr(stopper)
 for j = 0,stopper-1 do begin
     if key_end[j] LT 0 then keyword[j] = '*' $
     else keyword[j]=strtrim(strmid(lbl_search[j],0,key_end[j]),2)
 endfor

;Added for 05 Jul 2008 Fix
 nfound = where(keyword EQ "DESCRIPTION", matches)
 srch = '"'
 if matches GT 0 then begin
  for j = 0, matches - 1 do begin
    res1 = strpos(lbl[nfound[j]],srch)
    res2 = strpos(lbl[nfound[j]],srch,res1+1)
    if (res2 EQ -1) then begin
       start=nfound[j]+1
       while (strpos(lbl[start],srch) EQ -1) do begin
            keyword[start] = '*'
            start += 1
       endwhile
       keyword[start] = '*'
    endif
  endfor
 endif

 nfound = where(keyword EQ nam, matches) ; index where the keyword matches nam
 
 if matches EQ 0 then begin
    nfound = where(strpos(keyword,nam) GT -1,matches)
 endif

; Process string parameter and use STR2NUM to obtain numeric value

 if matches GT 0 then begin
    line = lbl[nfound]
    nfd = size(nfound)
    quitter = nfd[nfd[nfd[0]-1]]
    svalue = strarr(quitter)
    mvalue = strarr(quitter,100)
    value = svalue
    i = 0
    while i LT quitter do begin

          n = nfound[i]
          knd = key_end[n]

          retrn = strpos(line[i],string(10b))
          if retrn EQ -1 then retrn = 80

          ;Modified A.Cardesin 2006Feb13: knd+1 (for '=') instead of knd+2 (for ' = ')
          svalue[i] = strtrim(strmid(line[i],knd+1,retrn-knd-2),2)
          spot = strpos(svalue[i],string(10b))
          if spot GT 0 then svalue[i]=strtrim(strmid(svalue[i],0,spot-1),2)
          
          ; Modified by L.Nagdimunov 14Dec2015
          ; Look for cases where check values (e.g. quotes) do not start on same line as '='
          if svalue[i] eq '' then begin
            temp_svalue = svalue
            
            ; Loop over all lines following the keyword, looking for a value
            for a=nfound[i]+1, n_elements(lbl)-1 do begin
              
              ; Stop search if a new keyword is found
              if (strpos(lbl[a], '=') gt -1) then break

              temp_retrn = strpos(line[i],string(10b))
              if temp_retrn EQ -1 then temp_retrn = 80

              temp_svalue[i] = strtrim(strmid(lbl[a], 0,temp_retrn),2)
              spot = strpos(temp_svalue[i],string(10b))
              if spot GT 0 then temp_svalue[i]=strtrim(strmid(temp_svalue[i],0,spot-1),2)
              
              ; Stop search if found value
              if temp_svalue[i] ne '' then begin
                svalue[i] = temp_svalue[i]
                n = a
                break
              endif
              
            endfor
          endif
                
          check = stregex(svalue[i],'["([{]')
          if check GT -1 then begin

               char_start = stregex(svalue[i],'["([{]',/extract)
               char_end = get_matching_char(char_start)

             k = n
             c=strpos(svalue[i],char_end,check+1)
             if c GT -1  then value[i]=strtrim(svalue[i],2) else begin
                 for a = 0, key_end[n]+1 do value[i]=value[i]+' '
                 value[i] = value[i] + svalue[i]
                   endelse

             m = 0
             m2 = 0

             while c LT 0 do begin
               k = k+1
                   m = m+1
                   m2=fix(m/24)
                     if m2 EQ 0 then value[i]=value[i] + ' ' + strtrim(lbl[k],2) $
                     else if m2 GT 0 then mvalue[i,m2]=mvalue[i,m2]+' '+strtrim(lbl[k],2) $
                     else print,'Illegal value of variable m2 ='+m2
                   c = strpos(lbl[k],char_end)
  ;                if (c GT -1) then if(keyword[k+1] EQ '*') then c = -1
             endwhile

             mvalue[i,0]=fix(m2[0])

          endif else begin
            
            value[i]=str2num(strtrim(svalue[i],2))
          endelse
          
          i = i + 1
    endwhile
    
 endif  else begin
   if abort_return then message,'Keyword '+nam+' not found in '+abort ;150
   !ERR = -1
 endelse

;       To print value and mvalue after running pdspar use:
;           print,value(*)
;           for d = 1,mvalue(*,0) do print,mvalue(*,d)
;       where '*' is any number valid for value(*)
 
 return,value

end