;-------------------------------------------------------------
;+
; NAME:
;       STRESS
; PURPOSE:
;       String edit by sub-string. Precede, Follow, Delete, Replace.
; CATEGORY:
; CALLING SEQUENCE:
;       new = stress(old,cmd,n,oldss,newss,ned)
; INPUTS:
;       old = string to edit.                               in
;       cmd = edit command:                                 in
;         'P' = precede.
;         'F' = follow.
;         'D' = delete.
;         'R' = replace.
;       n = occurrence number to process (0 = all).         in
;       oldss = reference substring.                        in
;       oldss may have any of the following forms:
;         1. s	  a single substring.
;         2. s...    start at substring s, end at end of string.
;         3. ...e    from start of string to substring e.
;         4. s...e   from subs s to subs e.
;         5. ...     entire string.
;       newss = substring to add. Not needed for 'D'        in
; KEYWORD PARAMETERS:
; OUTPUTS:
;       ned = number of occurrences actually changed.       out
;       new = resulting string after editing.               out
; COMMON BLOCKS:
; NOTES:
;       Notes: oldss and newss may be arrays.
; MODIFICATION HISTORY:
;       Written by R. Sterner, 6 Jan, 1985.
;       Johns Hopkins University Applied Physics Laboratory.
;       RES --- 23 May, 1988 fixed a bug in SSTYP = 2.
;       Converted to SUN 13 Aug, 1989 --- R. Sterner. (FOR loop change).
;       --- 8 Dec, 1992 added recursion so that OLDSS and NEWSS may be arrays
;       T.J.Harris, University of Adelaide.
;       R. Sterner, 2010 Apr 29 --- Converted arrays from () to [].
;       R. Sterner, 2010 Dec 20 --- Added some comments.
;       R. Sterner, 2013 Dec 12 --- Now checks occurrence number.
;       R. Sterner, 2013 Dec 12 --- Added error flag.
;       R. Sterner, 2013 Dec 12 --- Now input may be an array.
;       R. Sterner, 2013 Dec 12 --- Added /DOTS keyword.
;
; Copyright (C) 1985, Johns Hopkins University/Applied Physics Laboratory
; This software may be used, copied, or redistributed as long as it is not
; sold and this copyright notice is reproduced on each copy made.  This
; routine is provided as is without any express or implied warranties
; whatsoever.  Other limitations apply as described in the file disclaimer.txt.
;-
;-------------------------------------------------------------
 
	function stress,strng,cmdx,n,old_in,new_in,ned, error=err, $
          dots=dots, help=hlp
 
	if (n_params(0) lt 3) or keyword_set(hlp) then begin
	  print,' String edit by sub-string. Precede, Follow, Delete, Replace.'
	  print,' new = stress(old,cmd,n,oldss,newss,ned)'
	  print,'   old = string to edit.                               in'
          print,'     May be an array.'
	  print,'   cmd = edit command:                                 in'
	  print,"     'P' = precede."
	  print,"     'F' = follow."
	  print,"     'D' = delete."
	  print,"     'R' = replace."
	  print,'   n = occurrence number to process (0 = all).         in'
	  print,'   oldss = reference substring.                        in'
	  print,'   oldss may have any of the following forms:'
	  print,'     1. s	  a single substring.'
	  print,'     2. s...    start at substring s, end at end of string.'
	  print,'     3. ...e    from start of string to substring e.'
	  print,'     4. s...e   from subs s to subs e.'
	  print,'     5. ...     entire string.'
	  print,"   newss = substring to add. Not needed for 'D'        in"
	  print,'   ned = number of occurrences actually changed.       out'
	  print,'   new = resulting string after editing.               out'
          print,'         Original string if an error.'
          print,' Keywords:'
          print,'   ERROR=err, Error flag, 0=ok.'
          print,'     Original string returned on error.'
          print,'   /DOTS means treat ... in oldss as literal dots.'
          print,' Notes: The input string to edit may be an array of strings.'
          print,'   The same edit will be done to each element for an input'
          print,'   array.  The old and new substrings (oldss and newss) may'
          print,'   be arrays.  If they are arrays then oldss is replaced'
          print,'   by newss element by element if they are the same size.'
          print,'   The last element of newss is reused if newss is smaller'
          print,'   then oldss.  The number edited, ned will be an array if'
          print,'   the input was an array'
	  return, ''
	endif
 
        ;------------------------------------------------------
        ;  Handle array of strings to edit
        ;------------------------------------------------------
        n_strng = n_elements(strng)     ; # elements in input.
        if n_strng gt 1 then begin      ; If an array ...
          strng_out = strarr(n_strng)   ; Returned edited strings.
          nedout = intarr(n_strng)      ; Number of edits for each string.
          for i=0L, n_strng-1L do begin ; Loop over array elements.
            txt = stress(strng[i],cmdx,n,old_in,new_in,nedt,$  ; Edit next.
              err=err,dots=dots)
            if err ne 0 then return,strng ; Abort on any errors.
            strng_out[i] = txt          ; Save edited element.
            nedout[i] = nedt            ; # of edits for element.
          endfor
          ned = nedout                  ; Return # of edits.
          return, strng_out             ; Return edited array.
        endif


        err = 0

        ;---  Check if occurrence number given correctly  ---
        if n_elements(n) ne 1 then begin
          print, ' Error in stress: Occurrence number, n, must be a scalar.'
          err = 1
          return, strng
        endif
 
	;--- If old_in an array then do the first element then call recursively
	old = old_in[0]
	if (n_elements(new_in) Gt 0) then new = new_in[0]
 
        ;---  Determine old substring form as listed in the help text above  ---
	cmd = strupcase(cmdx)                   ; Upper case command.
	pdot = strpos(old,'...')                ; Position of any ...
	ssl = strlen(old)                       ; Length of oldss.
	sstyp = 0                               ; oldss form unknown.
	pos1 = -1                               ; ?
	pos2 = -1                               ; ?
	rstr = strng                            ; Working copy of string to edit.
	if (pdot eq -1) then sstyp = 1                  ; s 
	if (pdot gt 0) and (pdot eq ssl-3) then sstyp=2 ; s...
	if (pdot eq 0) and (ssl gt 3) then sstyp=3      ; ...e
	if (pdot gt 0) and (pdot lt ssl-3) then sstyp=4 ; s...e
	if (pdot eq 0) and (ssl eq 3) then sstyp=5      ; ...

        ;---  Treat dots (...) as literal if set  ---
        if keyword_set(dots) then sstyp=1       ; Simple substring.

	ned = 0		; Number of occurrences actually changed.
 
 
	case sstyp of                   ; Pick off start and end of subnstring.
1:	  begin                                 ; s
	    s = old
	    e = ''
	  end
2:	  begin                                 ; s...
	    s = strsub[old,0,ssl-4]
	    e = ''
    	  end
3:  	  begin                                 ; ...e
	    s = ''
	    e = strsub[old,3,ssl-1]
	  end
4:  	  begin                                 ; s...e
	    s = strsub[old,0,pdot-1]
	    e = strsub[old,pdot+3,ssl-1]
	  end
5:  	  begin                                 ; ...
	    s = ''
	    e = ''
	  end
else: 	  begin
            print, ' Error in stress: Error in oldss, unknown form.'
            err = 1
            return, rstr
          end
	endcase
 
 
;---------------  Find substring # N start  ---------------
	pos = -1
	nfor = n>1
loop:
	for i = 1, nfor do begin
	  pos = pos + 1
	  case sstyp of
    1:      pos = strpos(rstr,s,pos)    ; s
    2:      pos = strpos(rstr,s,pos)    ; s...
    3:      pos = strpos(rstr,e,pos)    ; ...e
    4:      pos = strpos(rstr,s,pos)    ; s...e
    5:      pos = 0                     ; ...
	  endcase
  	  if pos lt 0 then goto, done
	endfor
 
;----------  Find substring # N END  ----------------
    	case sstyp of
1:  	  begin                         ; s
	    pos1 = pos
	    pos2 = pos + strlen(s) - 1
	  end
2:  	  begin                         ; s...
	    pos1 = pos
	    pos2 = strlen(rstr) - 1
	  end
3:  	  begin                         ; ...e
	    pos1 = 0
	    pos2 = pos + strlen(e) - 1
	  end
4:  	  begin                         ; s...e
	    pos1 = pos
	    pos2 = strpos(rstr,e,pos+1)
	    if (pos2 lt 0) then goto, done
	    pos2 = pos2 + strlen(e) - 1
	  end
5:  	  begin                         ; ...
	    pos1 = 0
	    pos2 = strlen(rstr) - 1
	  end
	endcase
 
;------------  edit string  --------------
    	case cmd of
'P':  	  begin
	    rstr = strep(rstr,cmd,pos1,new)
	    pos = pos + strlen(new)
	  end
'F':  	  begin
	    rstr = strep(rstr,cmd,pos2,new)
	    pos = pos + strlen(new)
	  end
'R':  	  begin
	    rstr = strep(rstr,'D',pos1,pos2-pos1+1)
	    if (pos1 gt 0) then $
	      rstr = strep(rstr,'F',pos1-1,new)
	    if (pos1 eq 0) then $
	      rstr = strep(rstr,'P',0,new)
	    pos = pos + strlen(new) - 1
	  end
'D':  	  begin
	    rstr = strep(rstr,cmd,pos1,pos2-pos1+1)
	    pos = pos - 1
	  end
else: 	  begin
	    print, 'Error in stress: unknown command.  Given command: '+cmd
            err = 1
	    return,rstr
	  end
endcase
 
	ned = ned + 1
	if sstyp eq 5 then return,rstr
	if n eq 0 then goto, loop
 
done:
 
	;--- if old_in an array then do the first element then call recursively
	;--- and accumulate the results
	if (n_elements(old_in) gt 1) then begin	;call again until done all
		old = old_in[1:*]
		if (n_elements(new_in) gt 1) then new = new_in[1:*]
		tmp = 0
		rstr = stress(rstr,cmdx,n,old,new,tmp,err=err)
		ned = ned+tmp
	endif
	return, rstr
	end