;+
; Project     :	SOHO - CDS
;
; Name        :	RD_PLAN
;
; Purpose     :	Read a plan for a given date range.
;
; Explanation :	Extracts all the plan entries which intersect an
;		input time range. Essentially a wrapper around the LIST routines
;               written to speed things up by not re-reading what has
;               already been read.
;
; Use         :	RD_PLAN,PLAN, START, END, NOBS=NOBS
;
; Inputs      :	START, END = The range of date/time values to use in searching
;			     the database.  Can be in any standard time
;			     format.
;
; Opt. Inputs :	None.
;
; Outputs     :	PLAN = A structure array
;
; Opt. Outputs:	SOBJ_LIST - A list of science objective found in returned 
;                           plan entries
;               SPEC_LIST - A list of science specification found in returned 
;                           plan entries
;
; Keywords    :	FORCE= to force reading from DB
;               NOBS = total # of planned observations found
;               TYPE = 0,1,2,3 for DETAILS, FLAG, SCIENCE, and ALT SCIENCE  
;               (default is to read DETAILS database)
;               INST = instrument to read ['C' 'S']
;               NOPOINT = do not get pointing info
;               DAY = extra day to read on each side of START and END
;               JUMP = number of days to jump before starting a fresh read [def=10]
;               QUIET = turn off messages
;               LIST = keep -LIST extension on returned structure type name
;                      (def is to strip it off)
;
; Calls       :	LIST_DETAIL, LIST_FLAG
;
; Common      :	None.
;
; Restrictions:	None.
;
; Side effects:	modifies .SCI_SPEC field with .TITLE from GET_STUDY
;
; Category    :	Planning, Database.
;
; Prev. Hist. :	None.
;
; Written     :	Dominic Zarro (ARC),  18 September 1994
;
; Modified    : Liyun Wang, GSFC/ARC, May 24, 1995
;               Added SOBJ_LIST and SPEC_LIST keywords
;-
;============================================================================

                               
pro rd_plan,plan,cstart,cstop,force=force,nobs=nobs,type=type,inst=inst,$
    jump=jump,quiet=quiet,list=list,$
    day=day,err=err,nopoint=nopoint,sobj_list=sobj_list,spec_list=spec_list

defsysv,'!debug',exists=defined
if not defined then defsysv,'!debug',0

common rd_plan_com,sav_db

on_error,1

serr='Syntax --> rd_plan,plan,tstart,tend'
if (n_elements(cstop) eq 0) and (n_elements(cstart) eq 0) then begin
 err=serr & message,err,/cont
 return
endif

nobs=0
if n_elements(type) eq 0 then type=0
if datatype(inst) ne 'STR' then inst=which_inst() else $
 inst=get_soho_inst(inst,/short)

if (type gt 4) then begin
 err='Unsupported DB type -- '+trim(string(type)) & message,err,/cont & return
endif

;-- work out times (add +/- day to each end if user wants it)

if (n_elements(cstop) eq 0) then cstop=cstart
if (n_elements(cstart) eq 0) then cstart=cstop

secs_day=24.d*3600.d
if datatype(cstart) eq 'FLO' then cstart=double(cstart)
if datatype(cstop) eq 'FLO' then cstop=double(cstop)

err=''
tstart=anytim2tai(cstart,err=err)
if err ne '' then begin
 message,err,/cont
 return
endif

tstop=anytim2tai(cstop,err=err)
if err ne '' then begin
 message,err,/cont
 return
endif

if exist(day) then begin
 temp=tai2utc(tstart)
 temp.time=0
 temp.mjd=temp.mjd-1
 tstart=utc2tai(temp)
 temp=tai2utc(tstop) 
 if temp.time eq 0 then temp.mjd=temp.mjd+1 else begin
  temp.time=0
  temp.mjd=temp.mjd+2
 endelse
 tstop=utc2tai(temp)
 dprint,'tstart: ',anytim2utc(tstart,/ecs)
 dprint,'tstop: ',anytim2utc(tstop,/ecs)
endif

if tstop le tstart then begin
 tstop=tstart+secs_day
 message,'END time lt START time; defaulting to 1 day',/con
endif
 
;-- override with keyword inputs 

rdb=1
get_instrument,inst,desc
name=strtrim(desc.name,2)
ctype=get_plan_type(plan,inst=cinst)

if (ctype eq type) and (cinst eq inst) then rdb=0
if keyword_set(force) then rdb=1

;-- check if database changed

if datatype(sav_db) ne 'STR' then sav_db=getenv('ZDBASE')
cur_db=getenv('ZDBASE')
if cur_db ne sav_db then begin
 message,'ZDBASE changed!!!',/contin
 rdb=1 & sav_db=cur_db
endif

;-- check if jump is greater than JUMP [def = 7]
;-- in this case, read directly from DB

if n_elements(jump) eq 0 then jump=7
nsecs=jump*secs_day
if not rdb then begin
 type=get_plan_type(plan)
 if type gt -1 then begin
  itime=get_plan_itime(plan)
  mstart=min((plan.(itime)))
  mend=max((plan.(itime+1)))
  rdb=((mstart-tstop)  gt nsecs) or ((tstart-mend) gt nsecs)
  if rdb then dprint,'% RD_PLAN jumping...'
 endif
endif

;-- get list function

funct=get_plan_funct(type,/lis,err=err)
if funct eq '' then return
def=get_plan_def(type)
l2d=((type eq 0) or (type eq 1) or (type eq 3)) and (not keyword_set(nopoint))

;-- check if function supports instrument type

if (type ne 2) and (type ne 4) then begin
 if inst ne which_inst() then begin
  err='DB type '+trim(string(type))+' unsupported for '+get_soho_inst(inst)
  message,err,/cont
  return
 endif
endif

loud=1-keyword_set(quiet)
if rdb then begin
 delvarx,plan
 if loud then message,'Reading '+name+' plan from '+def+' DB...',/cont
 case type of
  2: list_plan,tstart,tstop,plan,nobs,inst=inst 
  4: list_soho_det,tstart,tstop,plan,nobs,inst=inst
  else: call_procedure,funct,tstart,tstop,plan,nobs
 endcase

;-- extract nested pointing structure

 if (nobs gt 0) and l2d then plan=call_function('list_to_detail',temporary(plan),nobs)

endif else begin 
 type=get_plan_type(plan)
 itime=get_plan_itime(plan)
 def=get_plan_def(type)
 mstart=min((plan.(itime)))
 mend=max((plan.(itime+1)))

;-- look back in time

 if tstart lt mstart then begin         
  if loud then message,'Looking back in time for '+name+' in '+def+' DB...',/cont
  case type of
   2: list_plan,tstart,mstart,pre_plan,nobs,inst=inst,err=err 
   4: list_soho_det,tstart,mstart,pre_plan,nobs,inst=inst,err=err 
   else: call_procedure,funct,tstart,mstart,pre_plan,nobs
  endcase

  if (nobs gt 0) then begin 
   if l2d then pre_plan=call_function('list_to_detail',temporary(pre_plan))
   if not exist(plan) then plan=temporary(pre_plan) else $
    plan=concat_struct(temporary(pre_plan),temporary(plan),err=err)
  endif

 endif

;-- look forward in time

 if tstop gt mend then begin
  if loud then message,'Looking ahead in time for '+name+' in '+def+' DB...',/cont
  case type of
   2: list_plan,mend,tstop,post_plan,nobs,inst=inst,err=err 
   4: list_soho_det,mend,tstop,post_plan,nobs,inst=inst,err=err 
  else: call_procedure,funct,mend,tstop,post_plan,nobs
  endcase

  if (nobs gt 0) then begin
   if l2d then post_plan=call_function('list_to_detail',temporary(post_plan))
   if not exist(plan) then plan=temporary(post_plan) else $
    plan=concat_struct(temporary(plan),temporary(post_plan),err=err)
  endif

 endif

;-- sort time entries

 nobs=n_elements(plan)
 if nobs gt 0 then begin
  plan=mk_plan_sort(temporary(plan),/uniq,/str)
  nobs=n_elements(plan)
 endif
 
endelse

nobs=n_elements(plan)
if nobs eq 0 then begin
 err='No '+name+' plan found in '+def+ ' DB for specified times  '
 if loud then message,err,/cont
 delvarx,plan
 return
endif

;-- extract SCI_SPEC 

plan.sci_spec=get_plan_spec(plan)

;-- Make list of sci_obj and sci_spec

IF tag_exist(plan,'SCI_OBJ') THEN BEGIN 
   IF N_ELEMENTS(sobj_list) EQ 0 THEN $
      sobj_list = get_uniq_list(plan.sci_obj) $
   ELSE $
      sobj_list = get_uniq_list(plan.sci_obj, orig=sobj_list) 
ENDIF

IF tag_exist(plan,'SCI_SPEC') THEN BEGIN 
   IF N_ELEMENTS(spec_list) EQ 0 THEN $
      spec_list = get_uniq_list(plan.sci_spec) $
   ELSE $
      spec_list = get_uniq_list(plan.sci_spec, orig=spec_list)
ENDIF

;-- remove any -LIST extensions from STRUCT_TYPE

if tag_exist(plan,'STRUCT_TYPE') and (not keyword_set(list)) then begin
 peek=strpos(strupcase(plan.struct_type),'-LIST')
 cfind=where(peek ne -1,cnt)
 if cnt gt 0 then $
  plan(cfind).struct_type=strmid(plan(cfind).struct_type,0,peek(cfind(0)))
endif

return & end

