;+
; Project     :	SOHO - CDS/SUMER
;
; Name        :	READ_KAP()
;
; Purpose     :	Reads in a KAP file.
;
; Explanation :	Reads in a KAP file, and stores the information in the
;		appropriate databases.
;
; Use         :	Result = READ_KAP( FILENAME )
;
;		Result = READ_KAP( FILENAME, IGNORE='CDS')
;		Result = READ_KAP( FILENAME, IGNORE='SUMER')
;
; Inputs      :	FILENAME = The name of the file to read.
;
; Opt. Inputs :	None.
;
; Outputs     :	The result of the function is a logical value representing
;		whether or not the operation was successful, where 1 is
;		successful and 0 is unsuccessful.
;
; Opt. Outputs:	None.
;
; Keywords    :	IGNORE	 = If passed, then contains the name or code value (see
;			   GET_INSTRUMENT) of an instrument to ignore when
;			   reading in SCIPLAN entries.  This is so that one can
;			   avoid overwriting one's own SCIPLAN entries, if
;			   desired.
;
;		ERRMSG   = If defined and passed, then any error messages will
;			   be returned to the user in this parameter rather
;			   than being handled by the IDL MESSAGE utility.  If
;			   no errors are encountered, then a null string is
;			   returned.  In order to use this feature, the string
;			   ERRMSG must be defined first, e.g.,
;
;				ERRMSG = ''
;				Result = READ_KAP( FILENAME, ERRMSG=ERRMSG )
;				IF ERRMSG NE '' THEN ...
;
;               NOPURGE  = set to not purge the DB's each time
;                          (useful when calling the routine in a loop)
;
;               NOSET     = skip updating KAP version file
;
;               NORES     = skip updating resource DB
;
; Calls       :	OPEN_KAP, READ_KAP_ITEM, CLR_RESOURCE, CLR_TEL_MODE,
;		CLR_TEL_SUBMODE, CLR_OTHER_OBS, ADD_RESOURCE, ADD_TEL_MODE,
;		ADD_TEL_SUBMODE, ADD_OTHER_OBS, UPD_PLAN, UPD_SOHO_DET,
;		PRG_PLAN, PRG_SOHO_DET, LAST_KAP_VERS, SET_KAP_VERS
;
; Common      :	None.
;
; Restrictions:	When using the CDS database system, !PRIV must be 3 or greater
;		to use this routine.  This restriction is enforced except in
;		VMS, where it is assumed that the Oracle-based SUMER system is
;		used instead.
;
; Side effects:	None.
;
; Category    :	Planning, science.
;
; Prev. Hist. :	None.
;
; Written     :	William Thompson, GSFC, 3 April 1995
;
; Modified    :	Version 1, William Thompson, GSFC, 10 April 1995
;		Version 2, William Thompson, GSFC, 11 April 1995
;			Added IGNORE keyword
;		Version 3, William Thompson, GSFC, 12 April 1995
;			Added support for PROGRAM item.
;		Version 4, William Thompson, GSFC, 13 April 1995
;			Added support for OTHER_OBS item.
;		Version 5, William Thompson, GSFC, 19 May 1995
;			Modified to ignore MDI's "Struct_Prog" program which
;			overlaps other MDI programs.
;		Version 6, William Thompson, GSFC, 22 May 1995
;			Modified to write to database at end, to speed up.
;		Version 7, William Thompson, GSFC, 24 May 1995
;			Added called to PRG_ routines.
;			Added call to SET_KAP_VERS.
;		Version 8, William Thompson, GSFC, 8 August 1995
;			Modified to ignore MDI's "FD_Mag" program which
;			overlaps other MDI programs.
;		Version 9, Dominic Zarro, GSFC, 8 March 1996
;			Added reading of DELAYED commanding DB
;               Version 10, Dominic Zarro, GSFC, 16 June 1996
;                       Added NOPURGE keyword and clearing of SCI and DET
;                       databases
;               Version 11, Dominic Zarro, GSFC, 10 January 1997
;                       Centralized clearing and adding of resources
;                       Made IGNORE a vector
;
; Version     :	Version 10
;-
;

;-----------------------------------------------------------------------------

pro get_kap_times,item,start_time,end_time,err=err   ;--- determine date of ITEM

err=''
if datatype(item) ne 'STC' then begin
 err='Input ITEM not a structure'
 message,err,/cont
 return
endif
if datatype(start_time) ne 'STR' then start_time=''
itime=get_plan_itime(item)
start_time=trim2(start_time)

if start_time eq '' then begin
 itime=get_plan_itime(item)
 if itime lt 0 then chk=tag_exist(item,'START_TIME',index=itime)
 if itime gt -1 then begin
  if trim2(item(0).(itime)) eq '' then begin
   err='START_TIME field is blank'
   message,err,/cont
   return
  endif
  err=''
  tstart=anytim2utc(item(0).(itime),err=err)
  if (err ne '')  then begin
   message,err,/cont
   return
  endif
  tstart.time=0
  tend=tstart
  tend.mjd=tend.mjd+1
  start_time=anytim2utc(tstart,/ecs,/date)
  end_time=anytim2utc(tend,/ecs,/date)
 endif
 message,'Inferred start_time,end_time: '+start_time+', '+end_time,/cont
 stop
endif
return & end

;-----------------------------------------------------------------------------
FUNCTION READ_KAP, FILENAME, ERRMSG=ERRMSG, IGNORE=IGNORE, NOPURGE=NOPURGE,$  
                   NOSET=NOSET,NORES=NORES

;
;  Make sure that UNIT is initialized to -1 so that errors can be handled
;  correctly.
;
	UNIT = -1
;
;  Check the number of parameters.
;
	IF N_PARAMS() NE 1 THEN BEGIN
		MESSAGE = 'Syntax:  Result = READ_KAP( FILENAME )'
		GOTO, HANDLE_ERROR
	ENDIF
;
;  Make sure that FILENAME is a character string scalar.
;
	IF N_ELEMENTS(FILENAME) NE 1 THEN BEGIN
		MESSAGE = 'FILENAME must be a scalar'
		GOTO, HANDLE_ERROR
	ENDIF ELSE BEGIN
          IF DATATYPE(FILENAME,1) NE 'String' THEN BEGIN
		MESSAGE = 'FILENAME must be a character string'
		GOTO, HANDLE_ERROR
	  ENDIF
        ENDELSE
        FILENAME=TRIM2(FILENAME)
;
;  Make sure that one has sufficient privilege to run the software.
;
	IF !VERSION.OS NE 'vms' THEN BEGIN
	  TEST = EXECUTE('PRIV = !PRIV')
	    IF PRIV LT 3 THEN BEGIN
		MESSAGE = '!PRIV must be 3 or greater to run this routine'
		GOTO, HANDLE_ERROR
	    ENDIF
	ENDIF
;
;  If the IGNORE keyword was passed, then determine which instrument this
;  refers to.
;
        INS_IGNORE='None'
	IF EXIST(IGNORE) THEN BEGIN
             FOR J=0,N_ELEMENTS(IGNORE)-1 DO BEGIN
                ERRMSG=''
		GET_INSTRUMENT, IGNORE(J), INS, ERRMSG=ERRMSG
		IF ERRMSG EQ '' THEN INS_IGNORE = [INS_IGNORE,INS.CODE]
             ENDFOR
	ENDIF
;
;  Extract a list of all resource types.
;
	LIST_RES_TYPE, RES_TYPES
;
;  Open the input file.
;
        ERRMSG=''
	OPEN_KAP, UNIT, FILENAME, HEADER, ERRMSG=ERRMSG
	IF UNIT LT 0 THEN BEGIN
	 MESSAGE = 'Unable to open file ' + FILENAME
	 GOTO, HANDLE_ERROR
	ENDIF
	MESSAGE, 'Reading file ' + FILENAME,/CONT

;
;  Get the start and end times, and clear the relevant databases.
;
	START_TIME = ''
	END_TIME = ''
	FOR I=0,N_ELEMENTS(HEADER)-2 DO BEGIN
	 LINE = HEADER(I)
	 SEP = STRPOS(LINE,'=')
	 IF (TRIM2(LINE) NE '') THEN BEGIN
          IF ((SEP LE 0) OR (SEP GE STRLEN(LINE))) THEN BEGIN
           err='Header line is not in keyword=value format'
           message,err,/cont
          ENDIF ELSE BEGIN
	   KEYWORD = STRTRIM( STRMID(LINE,0,SEP), 2)
	   VALUE   = STRTRIM( STRMID(LINE,SEP+1, STRLEN(LINE)-SEP-1), 2)
	   IF KEYWORD EQ 'STARTIME' THEN START_TIME = VALUE
	   IF KEYWORD EQ 'ENDTIME'  THEN END_TIME   = VALUE
          ENDELSE
         endif
	ENDFOR
;

        START_TIME=TRIM2(START_TIME)
	IF START_TIME EQ '' THEN BEGIN
         MESSAGE,'Start time not found in header',/cont
        ENDIF ELSE BEGIN
         ERR=''
         TSTART=ANYTIM2UTC(START_TIME,/ECS,/DATE,ERR=ERR)
         IF ERR EQ '' THEN START_TIME=TSTART ELSE START_TIME=''
        ENDELSE

;-- IAP files are always in units of 1 day

        IF START_TIME NE '' THEN BEGIN
         TSTART=ANYTIM2UTC(START_TIME)
         TEND=TSTART
         TEND.MJD=TEND.MJD+1
         END_TIME=ANYTIM2UTC(TEND,/ECS,/DATE)
        ENDIF
;
;  Keep track of how many items of each type have been read in.
;
	N_SCIPLAN = 0
	N_PROGRAM = 0
	N_TLM_MODE = 0
	N_TLM_SUBMODE = 0
	N_RESOURCE = 0
	N_NRT_RESERVED = 0
	N_DELAYED_CMD = 0
	N_OTHER_OBS = 0
;
;  Read in the KAP file item by item until the end is reached.
;
	TYPE = 'Test'
	WHILE TYPE NE '' DO BEGIN
                ERRMSG=''
		READ_KAP_ITEM, UNIT, TYPE, ITEM, ERRMSG=ERRMSG
		IF ERRMSG NE '' THEN GOTO, HANDLE_ERROR
;
;  Collect all the SCIPLAN entries.  However, ignore any MDI entries with the
;  mnemonic "Struct_Prog", or entries for the instrument that was selected to
;  be ignored.
;
		IF TYPE EQ 'SCIPLAN' THEN BEGIN

                    ILOOK=WHERE(ITEM.INSTRUME EQ INS_IGNORE,ICOUNT)
		    IF (ICOUNT EQ 0) AND $
                       (ITEM.START_TIME LT  ITEM.END_TIME) AND $
			    ((ITEM.INSTRUME NE 'M') OR			$
			    ((ITEM.MNEMONIC NE 'Struct_Prog') AND	$
			    (ITEM.MNEMONIC NE 'FD_Mag'))) THEN BEGIN
			IF N_SCIPLAN EQ 0 THEN SCIPLAN = ITEM ELSE	$
				SCIPLAN = [SCIPLAN, ITEM]
			N_SCIPLAN = N_SCIPLAN + 1
		    ENDIF
		ENDIF
;
;  Collect all the PROGRAM entries.
;
		IF TYPE EQ 'PROGRAM' THEN BEGIN
                    ILOOK=WHERE(ITEM.INSTRUME EQ INS_IGNORE,ICOUNT)
		    IF (ICOUNT EQ 0) AND $
                       (ITEM.DATE_OBS LT  ITEM.DATE_END) THEN BEGIN
           	        IF N_PROGRAM EQ 0 THEN PROGRAM = ITEM ELSE	$
			        PROGRAM = [PROGRAM, ITEM]
		        N_PROGRAM = N_PROGRAM + 1
                    ENDIF
		ENDIF
;
;  Collect all the TLM_MODE and TLM_SUBMODE entries.
;
		IF TYPE EQ 'TLM_MODE' THEN BEGIN
		    IF N_TLM_MODE EQ 0 THEN TLM_MODE = ITEM ELSE	$
			    TLM_MODE = [TLM_MODE, ITEM]
		    N_TLM_MODE = N_TLM_MODE + 1
		ENDIF
;
		IF TYPE EQ 'TLM_SUBMODE' THEN BEGIN
		    IF N_TLM_SUBMODE EQ 0 THEN TLM_SUBMODE = ITEM ELSE	$
			    TLM_SUBMODE = [TLM_SUBMODE, ITEM]
		    N_TLM_SUBMODE = N_TLM_SUBMODE + 1
		ENDIF
;
;  Collect all the general SOHO resource entries.
;
		IF (WHERE(TYPE EQ RES_TYPES))(0) NE -1 THEN BEGIN
		    IF N_RESOURCE EQ 0 THEN RESOURCE = ITEM ELSE	$
			    RESOURCE = [RESOURCE, ITEM]
		    N_RESOURCE = N_RESOURCE + 1
		ENDIF

;
;  Collect all the INST_NRT_RESERVED entries.
;
		IF TYPE EQ 'INST_NRT_RESERVED' THEN BEGIN
		    IF N_NRT_RESERVED EQ 0 THEN NRT_RESERVED = ITEM ELSE $
			    NRT_RESERVED = [NRT_RESERVED, ITEM]
		    N_NRT_RESERVED = N_NRT_RESERVED + 1
		ENDIF

;
;  Collect all the INST_DELAYED_CMD entries.
;
		IF TYPE EQ 'INST_DELAYED_CMD' THEN BEGIN
		    IF N_DELAYED_CMD EQ 0 THEN DELAYED_CMD = ITEM ELSE $
			    DELAYED_CMD = [DELAYED_CMD, ITEM]
		    N_DELAYED_CMD = N_DELAYED_CMD + 1
		ENDIF
;
;
;  Collect all the OTHER_OBS entries.
;
		IF TYPE EQ 'OTHER_OBS' THEN BEGIN
		    IF N_OTHER_OBS EQ 0 THEN OTHER_OBS = ITEM ELSE	$
			    OTHER_OBS = [OTHER_OBS, ITEM]
		    N_OTHER_OBS = N_OTHER_OBS + 1
		ENDIF
;
	ENDWHILE
;
;-- Update SCIENCE and DETAILED Plans for those instruments that submitted
;   IAP's. Make sure that old plans are removed.

        inst=get_soho_inst(/short)
        ninst=n_elements(inst)
        
        for k=0,1 do begin
         if k eq 0 then np=n_sciplan else np=n_program
 	 if np gt 0 then begin
          if k eq 0 then begin
           rplans=sciplan & ptype=2 & rtype='science'
           get_kap_times,rplans,start_time,end_time,err=err
           if (start_time ne '') and (err eq '') then begin
            list_plan,start_time,end_time,plans,nplans
            dstart=str_format(anytim2tai(start_time))
            dend=str_format(anytim2tai(end_time))
            if nplans gt 0 then begin
             pkeep=where( (str_format(plans.start_time) ge dstart) and $
                          (str_format(plans.start_time) lt dend),nplans)
             if nplans gt 0 then plans=plans(pkeep)
            endif
           endif
          endif else begin
           rplans=program & ptype=4 & rtype='program'
           get_kap_times,rplans,start_time,end_time,err=err
           if (start_time ne '') and (err eq '') then begin
            list_soho_det,start_time,end_time,plans,nplans
            dstart=str_format(anytim2tai(start_time))
            dend=str_format(anytim2tai(end_time))
            if nplans gt 0 then begin
             pkeep=where( (str_format(plans.date_obs) ge dstart) and $
                          (str_format(plans.date_obs) lt dend),nplans)
             if nplans gt 0 then plans=plans(pkeep)
            endif
           endif
          endelse
          rinst=rplans.instrume
          chk=where_vector(rinst,inst,count)
          if count gt 0 then begin
           inst=inst(chk) & ninst=n_elements(inst)
           for i=0,ninst-1 do begin
            delvarx,old_plans,new_plans
            ilook=where(rplans.instrume eq inst(i),icount)
            if icount gt 0 then begin
             dprint,'% READ_KAP: Updating '+rtype+' plan for '+get_soho_inst(inst(i))
             def_inst_plan,new_plans,inst=inst(i),type=ptype,rep=icount,/list
             copy_struct,rplans(ilook),new_plans
             if nplans gt 0 then plook=where(plans.instrume eq inst(i),pcount) else pcount=0
             if pcount gt 0 then old_plans=plans(plook)
             blank=where(trim2(new_plans.sci_obj) eq '',bcount)
             if bcount gt 0 then new_plans(blank).sci_obj='Undefined SCI_OBJ'
             mk_plan_change,new_plans,newer_plans,err=err
             if err(0) ne '' then print,'% READ_KAP: '+err
             mk_plan_write,newer_plans,old_plans,/retry,/noloop,/list,/truncate
            endif
           endfor
          endif
	 endif
        endfor

;
       IF NOT KEYWORD_SET(NORES) THEN BEGIN
        ERRMSG=''
	IF N_TLM_MODE GT 0 THEN BEGIN
         GET_KAP_TIMES,TLM,START_TIME,END_TIME,err=err
         if err eq '' then begin
          MESSAGE,'Updating telemetry modes',/CONT
 	  IF CLR_TEL_MODE(START_TIME, END_TIME, ERRMSG=ERRMSG) THEN BEGIN
	   IF NOT ADD_TEL_MODE(TLM_MODE, ERRMSG=ERRMSG) THEN $
	    MESSAGE,'Unable to insert telemetry mode change',/CONT
          ENDIF ELSE MESSAGE,'Unable to clear telemetry mode database',/CONT
         endif
        ENDIF
;
	IF N_TLM_SUBMODE GT 0 THEN BEGIN
         GET_KAP_TIMES,TLM_SUBMODE,START_TIME,END_TIME,err=err
         if err eq '' then begin
          MESSAGE,'Updating telemetry submodes',/CONT
          IF CLR_TEL_SUBMODE(START_TIME, END_TIME, ERRMSG=ERRMSG) THEN BEGIN
	   IF NOT ADD_TEL_SUBMODE(TLM_SUBMODE, ERRMSG=ERRMSG) THEN $
	    MESSAGE,'Unable to insert telemetry submode change',/CONT
          ENDIF ELSE MESSAGE,'Unable to clear telemetry submode database',/CONT
         endif
        ENDIF
;
	IF N_RESOURCE GT 0 THEN BEGIN
         GET_KAP_TIMES,RESOURCE,START_TIME,END_TIME,err=err
         if err eq '' then begin
 	  MESSAGE,'Updating resources',/CONT
          IF CLR_RESOURCE(START_TIME, END_TIME, ERRMSG=ERRMSG) THEN BEGIN
	   IF NOT ADD_RESOURCE(RESOURCE, ERRMSG=ERRMSG) THEN $
	    MESSAGE,'Unable to insert resource',/CONT
          ENDIF ELSE MESSAGE,'Unable to clear resource database',/CONT
         endif
        ENDIF
;
	IF N_NRT_RESERVED GT 0 THEN BEGIN
         GET_KAP_TIMES,NRT_RESERVED,START_TIME,END_TIME,err=err
         if err eq '' then begin
          MESSAGE,'Updating NRT reserved times',/CONT
          IF CLR_NRT_RES(START_TIME, END_TIME, ERRMSG=ERRMSG) THEN BEGIN
  	   IF NOT ADD_NRT_RES(NRT_RESERVED, ERRMSG=ERRMSG) THEN $
	    MESSAGE,'Unable to insert NRT reserved time',/CONT
	  ENDIF ELSE MESSAGE,'Unable to clear NRT reserved database',/CONT
         endif
	ENDIF
;
	IF N_DELAYED_CMD GT 0 THEN BEGIN
 	 IF WHICH_INST() NE 'S' THEN BEGIN
          GET_KAP_TIMES,DELAYED_CMD,START_TIME,END_TIME,err=err
          if err eq '' then begin
           MESSAGE,'Updating Delayed commanding times',/CONT
           IF CALL_FUNCTION('CLR_INST_DLYD',START_TIME, END_TIME,ERRMSG=ERRMSG)  THEN BEGIN
   	    IF NOT ADD_INST_DLYD(DELAYED_CMD, ERRMSG=ERRMSG) THEN $
	     MESSAGE,'Unable to insert Delayed commanding time',/CONT
	   ENDIF ELSE MESSAGE,'Unable to clear Delayed commanding database',/CONT
          endif
         ENDIF
        ENDIF
;
	IF N_OTHER_OBS GT 0 THEN BEGIN
         GET_KAP_TIMES,OTHER_OBS,START_TIME,END_TIME,err=err
         if err eq '' then begiun
 	  MESSAGE,'Updating other observatories',/CONT
   	  IF CLR_OTHER_OBS(START_TIME, END_TIME, ERRMSG=ERRMSG) THEN BEGIN
	   IF NOT ADD_OTHER_OBS(OTHER_OBS, ERRMSG=ERRMSG) THEN $
	    MESSAGE,'Unable to insert item for another observatory',/CONT
          ENDIF ELSE MESSAGE,'Unable to clear other observatories database',/CONT
         endif
       ENDIF

;
;  Purge the appropriate databases.
;
        IF NOT KEYWORD_SET(NOPURGE) THEN BEGIN
         MESSAGE=''
         MESSAGE,'Purging databases',/CONT
	 IF NOT PRG_PLAN    (ERRMSG=MESSAGE) THEN GOTO, HANDLE_ERROR
	 IF NOT PRG_SOHO_DET(ERRMSG=MESSAGE) THEN GOTO, HANDLE_ERROR
        ENDIF
;
;  Parse the filename to determine the version number, assuming a filename of
;  the form ECSyyyymmddvvv.KAP.
;
	IF (NOT KEYWORD_SET(NOSET)) AND (START_TIME NE '') THEN BEGIN
         VERS = KAP_VERS(FILENAME)
	 IF VERS GE 0 THEN BEGIN
	    CUR_VERS = LAST_KAP_VERS(START_TIME)
	    IF NOT SET_KAP_VERS(START_TIME, VERS) THEN BEGIN
		MESSAGE = 'Unable to change version from ' + TRIM(CUR_VERS) + $
			' to ' + TRIM(VERS) + ' for date ' + START_TIME
	    ENDIF
         ENDIF
	ENDIF
;
;  Signal success.
;
	RESULT = 1
	GOTO, FINISH
;
;  Error handling point.
;
HANDLE_ERROR:
	IF UNIT GT 0 THEN FREE_LUN, UNIT
	IF N_ELEMENTS(ERRMSG) EQ 0 THEN MESSAGE, MESSAGE, /CONTINUE	$
		ELSE IF ERRMSG EQ '' THEN ERRMSG = 'READ_KAP: ' + MESSAGE
	RESULT = 0
;
;  Return whether successful or not.
;
FINISH:	
	RETURN, RESULT
	END
