; Routines in the file: make_32, op_time_sort, op_same_time, op_edit
; Last change was  12-mar-97
;- ------------------------------------------------------------------------------------
function make_32, event
;+
; NAME:
;   make_32
; PURPOSE:
;   Align the event times on the nearest 32 sec boundaries.
;   Adjust the offset times.
; INPUTS:
;   event	= The event structure from op_get_event
; RETURNS:
;   A new event structure with modified times.
; MODIFICATION HISTORY:
;   12-oct-93, JRL, Written.
;   21-feb-97, JRL, Changed calls to addtime to be with the /sec switch set
;-
; zero out the msec of event2(0) -- round off to nearest sec
event2 = event

i0 = 0
event2(i0).timarr = addtime(event2(i0).timarr,del=500.d0/1000.,/sec)
event2(i0).timarr(3) = 0

for i=i0+1,n_elements(event2)-1 do begin
  diff = addtime(event2(i).timarr,diff=event2(i0).timarr,/sec)	; Get the difference (sec)
  n32  = long((diff+16.) / 32.)			; Number of 32 sec intervals
  Temp_timarr = event2(i).timarr
  event2(i).timarr = addtime(event2(i0).timarr,del=n32*32.d0,/sec)
  event2(i).offset = event2(i).offset + addtime(event2(i).timarr,diff=Temp_timarr)
endfor

return,event2
end					; End of make_32
;- ------------------------------------------------------------------------------------
function op_time_sort, event, no32=no32
;+
; NAME:
;   op_time_sort
; PURPOSE:
;   Time order the event structure
;   Also, call make_32 to align to 32s boundaries
; INPUTS:
;   event	= The event structure from op_get_event
; RETURNS:
;   A new event structure with modified times.
; OPTIONAL INPUT KEYWORDS:
;   no32	= If set, don't call make_32
; MODIFICATION HISTORY:
;   25-feb-97, JRL, Changed calls to addtime to be with the /sec switch set
;-

  ex2int,event.timarr,msod,DS79		; Convert to internal format

  Day = DS79-min(DS79)
  T_sec = msod/1000L+Day*24L*3600

  event = event(bsort(T_sec))		; Don't re-order identical times
  if not keyword_set(no32) then event = make_32( event )	; Align to 32s boundaries

  return,event
end					; End of op_time_sort
;- ------------------------------------------------------------------------------------
pro op_start_end, event, og_table, istart, iend, dn, rate, 	$
	contact=contact, timarr=timarr, jint=jint, 		$
	station=station, nstn1=nstn1, nstn2=nstn2, k1=k1, k2=k2
;NAME:
;  op_start_end
;PURPOSE:
;  Return the start and stop events of BDR intervals
;  Also time order event (but don't align to 32s boundaries)
;
;OPTIONAL INPUT KEYWORDS:
;  contact	- If set, give the actual start and stop of both
;		  KSC and DSN contacts.  This is changes the search
;		  from DSN REPRO to DSN AOS
;  timarr	- External time:  If specified, routine will return
;		  the appropriate interval in jint
;  station	- If set, return nst1 and nst2 (number of KSC
;		  stations on 1st and 2nd days).  Note: If /station
;		  is specified, it is as if /contact is also
;		  specified.  Also, iend will start with the first
;		  KSC AOS in this case.  In this case, istart and
;		  iend will be the indices of nstn1 and nstn2
;OPTIONAL OUTPUT KEYWORDS:
;  jint		- Interval corresponding to timarr.  If jint is 
;		  negative, timarr is outside of the range of 
;		  istart and iend
;  nstn1,nstn2	- Number of KSC station contacts on days 1 and 2
;HISTORY: 
;  26-Feb-97, J. R. Lemen, Written
;   1-Mar-97, JRL, Added the contact, timarr and jint keywords
;  11-Mar-97, JRL, Added station keyword
;-

; Do a time sort first (we could have added a QT/H og)

event = op_time_sort( event, /no32 )	; Don't do the 32s alignment

; The interval starting event is an LOS

istart = where(event.og eq og_table(15).og or $	; KSC LOS (QT H)
               event.og eq og_table(16).og or $	; KSC LOS (QT M)
               event.og eq og_table(22).og or $	; DSN LOS (QT H)
               event.og eq og_table(23).og)	; DSN LOS (QT M)

; The interval ending event is a KSC AOS or a DSN REP (contact=0)
; or  interval ending event is a KSC AOS or a DSN AOS (/contact)

if keyword_set( contact ) or keyword_set(station) then $	; /contact
  iend = where(event.og eq og_table(8).og  or $	; KSC AOS-A-DAY
               event.og eq og_table(9).og  or $	; KSC AOS-B-DAY
               event.og eq og_table(10).og or $	; KSC AOS-A-NT
               event.og eq og_table(11).og or $	; KSC AOS-B-NT
               event.og eq og_table(17).og or $ ; DSN AOS-A
               event.og eq og_table(18).og)   $	; DSN AOS-B
  else $							; contact=0
  iend = where(event.og eq og_table(8).og  or $	; KSC AOS-A-DAY
               event.og eq og_table(9).og  or $	; KSC AOS-B-DAY
               event.og eq og_table(10).og or $	; KSC AOS-A-NT
               event.og eq og_table(11).og or $	; KSC AOS-B-NT
               event.og eq og_table(19).og)   	; DSN REPRO

if keyword_set(station) then begin
  delvarx, dn, rate, jint	; Let's not confuse anyone
  jj = where(strmid(strtrim(event(iend).station),0,1) eq 'U',njj)
  nstn1 = 0
  nstn2 = 0
  nstn = njj
  if nstn gt 0 then begin
     jj = iend(jj)
     tims = addtime(event(iend).timarr,diff=event(iend(0)).timarr)
     kk = where(tims lt 12*60. and 	$
	strmid(strtrim(event(iend).station),0,1) eq 'U', nstn1) 
     if nstn1 gt 0 then k1 = kk else k1 = 0
     kk = where(tims gt 12*60. and	$
	strmid(strtrim(event(iend).station),0,1) eq 'U', nstn2) 
     if nstn2 gt 0 then k2 = kk else k2 = 0
  endif
  return
endif

iend = iend(1:*)		; AOS is a KSC contact

; Make a sanity check

if n_elements(istart)-1 ne n_elements(iend) or min(iend-istart) le 0 then $
	message,'Problem with detection of LOS/AOS/DSN Repro events'
get_dn_rate, event, og_table, dn, rate, saa	; Get dn and rate

ij = where(dn eq -1, nij)
if nij gt 0 then dn(ij) = event(ij).dn		; In case it was defined before

if keyword_set(timarr) then begin	; timarr is defined 
  np = n_elements(iend)
  diff0 = addtime(event(istart(0:np-1)).timarr,diff=event(istart(0)).timarr,/sec)
  diff1 = addtime(event(iend).timarr,diff=event(istart(0)).timarr,/sec)

  diff2 = addtime(timarr,diff=event(istart(0)).timarr,/sec)
  jint = (where(diff2 ge diff0 and diff2 lt diff1))(0)
endif

end
;- ------------------------------------------------------------------------------------
pro op_edit,	orbit, og_table, op_rules, event, event2,		$
		dsn_num, dsn_select, DSNr=DSN, 				$
		dsn_str_select = dsn_str_select,			$
		KSC_tim1=KSC_tim1, KSC_tim2=KSC_tim2,			$
		ksc_str_remove=ksc_str_remove,pass_sum=pass_sum,	$
		comment = comment, contacts=contacts, 			$
		term_max=term_max, qrate_change=qrate_change,		$
		verbose=verbose, ksc_pass_num=ksc_pass_num, 		$
		spec_times=spec_times, spec_og=spec_og, 		$
		qbdr_opt=qbdr_opt, day_og=day_og
;+
;  NAME:
;    op_edit
;
;  PURPOSE:
;    Select the orbital events for the Yohkoh op command list.
;
;  History:
;  15-nov-91, Written, J. Lemen
;  10-dec-91, Updated, J. Lemen -- Retain KSC los at the end; add pass_sum
;  11-jan-92, Modified,J. Lemen -- Bug fixed to remove Night og's
;   6-jul-92, Modified, JRL     -- Fixed bug where 1st og was sometimes 
;						day.  Now it forces NOP.
;  13-oct-93, JRL, Added terminator image option
;  30-nov-93, JRL, Moved code to eliminate pre- and post-KSC events 
;			to valid_pass4.  Added call to op_same_time
;  14-jun-94, JRL, Added qrate_change keyword
;  29-jun-94, JRL, Pass og_table to op_same_time
;  30-jul-94, JRL, Pass ksc_str_remove to valid_pass4\
;   6-oct-94, JRL, Add spec_times, spec_og for special OG
;  28-mar-95, JRL, Call op_get_event twice to get Wallops passes
;  29-aug-95, JRL, Added a time sort before putting in the opstop command
;  25-feb-97, JRL, Added qbdr_opt switch
;   8-mar-97, JRL, Changed terminator keyword to term_max; added day_og keyword
;-

if n_elements(DSN) eq 0 then DSN=0
if n_elements(KSC_tim1) eq 0 then KSC_tim1 = intarr(7)
if n_elements(KSC_tim2) eq 0 then KSC_tim2 = intarr(7)

op_get_event, orbit, og_table, op_rules, event, DSN=DSN	; Get the raw events

; If this is a new style structure, then append the 2nd field passes
if (size(orbit.station))(0) eq 2 then begin
  op_get_event, orbit, og_table, op_rules, event1, DSN=DSN, Field=1	; Get the raw events for Wallops
  jj = where(event1.pass_num ge 0,nc)
  if nc gt 0 then begin			; Concatenate / Renumber the station pass_num
     event1 = event1(jj)
     i0 = where(event.pass_num ge 0)	; Get station contacts
     i1 = where(event1.pass_num ge 0)	; Get station contacts
     event1(i1).pass_num = event1(i1).pass_num + max(event(i0).pass_num) + 1
     event = [event,event1]

     event = op_time_sort(event,/no32)	; Time sort. Don't align to 32s boundaries

;;     i0 = where((event.og ge og_table(8).og and  $	; KSC AOS-A-DAY ...
;;		 event.og le og_table(11).og) or $	; KSC AOS-B-NT
;;		(event.og ge og_table(17).og and $	; DSN AOS-A
;;		 event.og le og_table(18).og),nc)	; DSN AOS-B	       
  endif
endif

event2 = event			; Don't change the original

;  Select the valid station contacts:

event2 = valid_pass(event2,op_rules)

;  If dsn_select is present, then also select dsn only if it is with in
;  dsn_time minutes of the list given in the structure dsn_select:

if n_elements(dsn_num) eq 0 then dsn_num = -1
event2 = valid_pass2(event2,dsn_num,dsn_select,	$
		op_rules.dsn_time.a,og_table,str_select=dsn_str_select)

; Eliminate KSC passes that fall between KSC_tim1 and KSC_tim2
event2 = valid_pass3(event2, KSC_tim1, KSC_tim2, str_remove=ksc_str_remove)

jj = where (event2.og ge 0) 
event2 = event2(jj) 			; Remove eliminated passes

; ---------------------------------------------------------------
event2 = op_time_sort( event2, /no32 )	; Time sort. Don't align to 32s boundaries
if keyword_set( DSN ) then return	; Don't change start/stop times or add opstop

; ---------------------------------------------------------------
; Remove 6th (or 1st) KSC contact if requested
; Change QT H to QT M if time to next contact exceeds op_rules.min_sun
; Summarize the station contacts (KSC and DSN)

event2 = valid_pass4( event2, og_table, op_rules, qrate_change=qrate_change, 	$
		str_remove=ksc_str_remove, ksc_pass_num=ksc_pass_num,		$
		qbdr_opt=qbdr_opt )
; ---------------------------------------------------------------
;  Add the terminator images
; ---------------------------------------------------------------
  if n_elements(term_max) eq 0 then term_max = -1
  if term_max ne 0 then $
	event2 = op_terminator(event2,og_table,num_term,term_max=term_max)

; ------------------------------------------------------------------
; Add special op commands if op_special exists and times are entered
; ------------------------------------------------------------------
event2 = op_add_special( event2, og_table, op_rules, spec_times, spec_og )
event2 = op_time_sort( event2 )		; Time sort. Align to 32s boundaries

; Add an opstop command

npts = n_elements(event2)
timarr = addtime(event2(npts-1).timarr,del=32.,/sec)	; Add 32 s
save_event,npts,og_table,timarr,127,		$
	event2(npts-1).station,' ',-1,event2(npts-1).pass_num,event2

; --------------------------------------
; Fix events that come at identical times
; --------------------------------------

event2 = op_same_time( event2, og_table, verbose=verbose ) ; Resolve conflicting time OG's
contacts = contact_sum( event2, og_table )	; Get the contact information
pass_sum = fmt_pass( contacts )		; Pass summary information
comment  = contacts(0).passid + ' OP'	; Set up the comment
; ---------------------------------------------------------------
;  Remove the night OG's:

  jj = where(event2.og eq 5)		; Get the 5's (night)
  event2(jj).og = -event2(jj).og	; This will remove the nights
 ; ---------------------------------------------------------------
; Remove out of range og's:

jj = where((event2.og ge 0) and (event2.og le 127))
event2 = event2(jj)

; Start with the NOP command (eliminate the ksc aos)

day_og = 0	; day_og = the DAY OG if it falls between 
		; KSC AOS and the NOP in the first pass
;		; This day_og must be added to the pass sheet.
while( event2(0).og ne 0 ) do begin
  if event2(0).og eq og_table(55).og then begin
      tbeep,5
      print,'  Warning:  Must add DAY OG to Pass 1!!!'
      day_og = event2(0)
  endif
  event2 = event2(1:*)			; 0 = NOP
endwhile

end
