	FUNCTION UPD_SOHO_DET, DEF, ERRMSG=ERRMSG
;+
; Project     :	SOHO - CDS
;
; Name        :	UPD_SOHO_DET()
;
; Purpose     :	Adds a SOHO detailed science plan record to the database
;
; Explanation :	This procedure takes a SOHO detailed science plan entry and
;		adds it to the database "soho_details".  This database contains
;		a series of such entries, making a historical list.  Anything
;		already in the database is overwritten.
;
; Use         :	Result = UPD_SOHO_DET( DEF )
;
;		IF NOT UPD_SOHO_DET( DEF ) THEN ...
;
; Inputs      :	DEF = This is an anonymous structure containing the following
;		      tags:
;
;			INSTRUME     = Single letter code specifying the
;				       instrument.
;			DATE_OBS     = Date/time of beginning of observation,
;				       in TAI format
;			DATE_END     = Date/time of end of observation, in TAI
;				       format
;			SCI_OBJ      = Science objective
;			SCI_SPEC     = Specific science objective
;			OBS_PROG     = Observing program that will be run
;			PROG_ID	     = Program ID, linking one or more studies
;				       together
;			CMP_NO	     = Campaign number
;			OBJECT	     = Code for object planned to be observed
;			OBJ_ID	     = Object identification
;			XCEN	     = Center(s) of instrument field-of-view
;				       along X axis
;			YCEN	     = Center(s) of instrument field-of-view
;				       along Y axis
;			ANGLE	     = Rotation angle(s) of field-of-view
;				       relative to solar north
;			IXWIDTH	     = Width(s) of field-of-view in instrument
;				       X direction
;			IYWIDTH	     = Width(s) of field-of-view in instrument
;				       Y direction
;			DISTURBANCES = Description of any disturbances
;			JITTER_LIMIT = Jitter limit in 1/10 arcsec units
;
;		      It can also be an array of such structures.
;
; 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    :
;       ERRMSG    = If defined and passed, then any error messages will be
;                   returned to the user in this parameter rather than
;                   depending on the MESSAGE routine in IDL.  If no errors are
;                   encountered, then a null string is returned.  In order to
;                   use this feature, ERRMSG must be defined first, e.g.
;
;                       ERRMSG = ''
;                       Result = UPD_SOHO_DET( ERRMSG=ERRMSG, ... )
;                       IF ERRMSG NE '' THEN ...
;
;
; Calls       :	DATATYPE, DBOPEN, DBBUILD, DBCLOSE, TRIM, GET_INSTRUMENT,
;		GET_OBJECT, GET_CAMPAIGN, DBFIND
;
; Common      :	None.
;
; Restrictions:	Only this routine can be used to add or delete detailed science
;		plan descriptions to or from the database.  Modifying the
;		database by hand could corrupt its integrity.
;
;		The data types and sizes of the structure elements must match
;		the definitions in the database.
;
;		!PRIV must be 2 or greater to use this routine.
;
; Side effects:	None.
;
; Category    :	Planning, Databases.
;
; Prev. Hist. :	None.
;
; Written     :	William Thompson, GSFC, 12 April 1995
;
; Modified    :	Version 1, William Thompson, GSFC, 12 April 1995
;		Version 2, William Thompson, GSFC, 19 May 1995
;			Fixed bug when new entry would overlap more than one
;			old ones.
;			Changed way DBFIND is called, to speed up.
;			Modified to take into account DELETED field.
;		Version 3, William Thompson, GSFC, 22 May 1995
;			Modified to allow the input parameter to be an array.
;		Version 4, William Thompson, GSFC, 3 August 1995
;			Fixed bug when only one instrument referred to in list
;			of entries.
;		Version 5, William Thompson, GSFC, 15 August 1995
;			Modified to make more efficient.
;			Ignore overlapping entries rather than exit
;               Version 6, Zarro, ARC, 30 August 1996
;                       Ignore ill-defined CAMPAIGN and OBJECT ID's rather
;                       than exit 
;
; Version     :	Version 6
;-
;
	ON_ERROR, 2
;
;  Initialize RESULT to represent non-success.  If the routine is successful,
;  this value will be updated below.
;
	RESULT = 0
;
;  Check the input parameters
;
	IF N_PARAMS() NE 1 THEN BEGIN
	   MESSAGE = 'Syntax:  Result = UPD_SOHO_DET(DEF)'
	   GOTO, HANDLE_ERROR
	ENDIF
;
;  Make sure that the user has privilege to write into the database.
;
	IF !PRIV LT 2 THEN BEGIN $
	   MESSAGE = '!PRIV must be 2 or greater to write into the database'
	   GOTO, HANDLE_ERROR
	ENDIF
;
;  Check each of the structure components to verify that it is of the correct
;  type and size.
;
	DEF0 = DEF(0)
;
	IF DATATYPE(DEF0.INSTRUME,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag INSTRUME must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.INSTRUME) NE 1 THEN BEGIN
	   MESSAGE = 'Tag INSTRUME must be a scalar'
	   GOTO, HANDLE_ERROR
	ENDIF
	MAXLEN = MAX(STRLEN(DEF.INSTRUME), MIN=MINLEN)
	IF (MAXLEN NE 1) OR (MINLEN NE 1) THEN BEGIN
	   MESSAGE = 'Tag INSTRUME must be a single character'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.DATE_OBS,1) NE 'Double' THEN BEGIN
	   MESSAGE = 'Tag DATE_OBS must be a double precision number'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.DATE_OBS) NE 1 THEN BEGIN
	   MESSAGE = 'Tag DATE_OBS must be a scalar'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.DATE_END,1) NE 'Double' THEN BEGIN
	   MESSAGE = 'Tag DATE_END must be a double precision number'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.DATE_END) NE 1 THEN BEGIN
	   MESSAGE = 'Tag DATE_END must be a scalar'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.SCI_OBJ,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag SCI_OBJ must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.SCI_OBJ) NE 1 THEN BEGIN
	   MESSAGE = 'Tag SCI_OBJ must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.SCI_OBJ)) GT 50 THEN BEGIN $
	   MESSAGE = 'Tag SCI_OBJ must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.SCI_SPEC,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag SCI_SPEC must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.SCI_SPEC) NE 1 THEN BEGIN
	   MESSAGE = 'Tag SCI_SPEC must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.SCI_SPEC)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag SCI_SPEC must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.OBS_PROG,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag OBS_PROG must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.OBS_PROG) NE 1 THEN BEGIN
	   MESSAGE = 'Tag OBS_PROG must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.OBS_PROG)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag OBS_PROG must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.PROG_ID,1) NE 'Integer' THEN BEGIN
	   MESSAGE = 'Tag PROG_ID must be a short integer'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.PROG_ID) NE 1 THEN BEGIN
	   MESSAGE = 'Tag PROG_ID must be a scalar'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.CMP_NO,1) NE 'Integer' THEN BEGIN
	   MESSAGE = 'Tag CMP_NO must be a short integer'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.CMP_NO) NE 1 THEN BEGIN
	   MESSAGE = 'Tag CMP_NO must be a scalar'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.OBJECT,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag OBJECT must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.OBJECT) NE 1 THEN BEGIN
	   MESSAGE = 'Tag OBJECT must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.OBJECT)) GT 3 THEN BEGIN
	   MESSAGE = 'Tag OBJECT must be 3 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.OBJ_ID,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag OBJ_ID must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.OBJ_ID) NE 1 THEN BEGIN
	   MESSAGE = 'Tag OBJ_ID must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.OBJ_ID)) GT 6 THEN BEGIN
	   MESSAGE = 'Tag OBJ_ID must be 6 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.XCEN,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag XCEN must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.XCEN) NE 1 THEN BEGIN
	   MESSAGE = 'Tag XCEN must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.XCEN)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag XCEN must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.YCEN,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag YCEN must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.YCEN) NE 1 THEN BEGIN
	   MESSAGE = 'Tag YCEN must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.YCEN)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag YCEN must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.ANGLE,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag ANGLE must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.ANGLE) NE 1 THEN BEGIN
	   MESSAGE = 'Tag ANGLE must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.ANGLE)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag ANGLE must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.IXWIDTH,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag IXWIDTH must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.IXWIDTH) NE 1 THEN BEGIN
	   MESSAGE = 'Tag IXWIDTH must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.IXWIDTH)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag IXWIDTH must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.IYWIDTH,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag IYWIDTH must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.IYWIDTH) NE 1 THEN BEGIN
	   MESSAGE = 'Tag IYWIDTH must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.IYWIDTH)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag IYWIDTH must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.DISTURBANCES,1) NE 'String' THEN BEGIN
	   MESSAGE = 'Tag DISTURBANCES must be a character string'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.DISTURBANCES) NE 1 THEN BEGIN
	   MESSAGE = 'Tag DISTURBANCES must be a scalar'
	   GOTO, HANDLE_ERROR
	END ELSE IF MAX(STRLEN(DEF.DISTURBANCES)) GT 50 THEN BEGIN
	   MESSAGE = 'Tag DISTURBANCES must be 50 characters or less'
	   GOTO, HANDLE_ERROR
	ENDIF
;
	IF DATATYPE(DEF0.JITTER_LIMIT,1) NE 'Integer' THEN BEGIN
	   MESSAGE = 'Tag JITTER_LIMIT must be a short integer'
	   GOTO, HANDLE_ERROR
	END ELSE IF N_ELEMENTS(DEF0.JITTER_LIMIT) NE 1 THEN BEGIN
	   MESSAGE = 'Tag JITTER_LIMIT must be a scalar'
	   GOTO, HANDLE_ERROR
	ENDIF
;
;  Make sure that the instrument code is valid.
;
	FOR I = 0, N_ELEMENTS(DEF)-1 DO BEGIN
            ERR=''
	    GET_INSTRUMENT, DEF(I).INSTRUME, TEMP,ERR=ERR
	    IF TEMP.CODE EQ '' THEN BEGIN
	        MESSAGE = 'Instrument ' + DEF(I).INSTRUME + $
			' not found in database'
	        MESSAGE,MESSAGE,/CONT
	    ENDIF
	    IF I EQ 0 THEN INS = REPLICATE(TEMP,N_ELEMENTS(DEF)) ELSE	$
		INS(I) = TEMP
;
;  Make sure that the campaign number matches an entry in the SOHO campaign
;  database.
;

	    IF DEF(I).CMP_NO NE 0 THEN BEGIN
                ERR='' & ICMP=DEF(I).CMP_NO
		GET_CAMPAIGN, ICMP, TEMP,ERR=ERR
		IF (TEMP.CMP_NO LE 0) and (ICMP NE 1) THEN BEGIN
		    MESSAGE = 'Campaign number ' + STRTRIM(DEF(I).CMP_NO,2) + $
			    ' not found in database'
		    MESSAGE,MESSAGE,/CONT
		ENDIF
	    ENDIF
;
;  Make sure that the object code matches an entry in the database.
;
            ERR=''
	    GET_OBJECT, DEF(I).OBJECT, TEMP,ERR=ERR
	    IF TEMP.OBJECT EQ '' THEN BEGIN
		MESSAGE = 'Object code ' + DEF(I).OBJECT + $
			' not found in database'
		MESSAGE,MESSAGE,/CONT
	    ENDIF
	    IF I EQ 0 THEN OBJ = REPLICATE(TEMP,N_ELEMENTS(DEF)) ELSE	$
		OBJ(I) = TEMP
;
;  Make sure that the stop date is greater than the start date.
;
	    IF DEF(I).DATE_END LE DEF(I).DATE_OBS THEN BEGIN
	       MESSAGE = 'The stop date must be after the start date'
	       GOTO, HANDLE_ERROR
	    ENDIF
	ENDFOR
;
;  Make sure that the proposed entries don't overlap with each other.
;
	I = 0
	WHILE I LT N_ELEMENTS(DEF) DO BEGIN
	    W = WHERE((DEF(I).DATE_OBS LT DEF.DATE_END) AND	$
		    (DEF(I).DATE_END GT DEF.DATE_OBS) AND	$
		    (INS(I).CODE EQ INS.CODE), COUNT)
	    IF COUNT GT 1 THEN BEGIN
		MESSAGE, 'Proposed ' + INS(I).NAME + ' entries at time ' + $
			TAI2UTC(DEF(I).DATE_OBS,/ECS,/TR) + ' to ' +	$
			TAI2UTC(DEF(I).DATE_END,/ECS,/TR) + ' and ' +	$
			TAI2UTC(DEF(W(1)).DATE_OBS,/ECS,/TR) + ' to ' +	$
			TAI2UTC(DEF(W(1)).DATE_END,/ECS,/TR) +		$
			' overlap each other.', /CONTINUE
		BELL
		REMOVE, W(1:*), DEF, INS, OBJ
	    ENDIF
	    I = I + 1
	ENDWHILE
;
;  Open the science plan database for write access.
;
	DBOPEN, 'soho_details', 1
;
;  Step through all the instruments.  First determine a unique set of all the
;  instruments which have been referred to.
;
	ALL_INS = INS.CODE
	IF N_ELEMENTS(ALL_INS) GT 1 THEN BEGIN
		ALL_INS = ALL_INS(SORT([ALL_INS]))
		ALL_INS = ALL_INS(UNIQ([ALL_INS]))
	ENDIF
	FOR J = 0,N_ELEMENTS(ALL_INS)-1 DO BEGIN
;
;  Find any existing entries which overlap with the proposed entries.
;
	    W = WHERE(INS.CODE EQ ALL_INS(J))
	    MIN_DATE_OBS = MIN(DEF(W).DATE_OBS)
	    MAX_DATE_END = MAX(DEF(W).DATE_END)
	    ENTRIES = DBFIND('DATE_END>' + TRIM(MIN_DATE_OBS,'(F15.3)') + $
		    ',DATE_OBS<' + TRIM(MAX_DATE_END,'(F15.3)') +	$
		    ',INSTRUME=' + ALL_INS(J) + ',DELETED=N', /SILENT)
	    IF !ERR EQ 0 THEN BEGIN
		N_FOUND = 0
	    END ELSE BEGIN
		ENTRIES = ENTRIES(UNIQ([ENTRIES]))
		N_FOUND = N_ELEMENTS([ENTRIES])
		DBEXT, ENTRIES, 'date_obs,date_end', DATE_OBS, DATE_END
	    ENDELSE
;
;  It's okay if it only touches the entries in the database.  Otherwise, delete
;  that entry.
;
	    IF N_FOUND GT 0 THEN BEGIN
		IF N_FOUND GT 1 THEN BEGIN
			S = SORT(DATE_OBS)
			ENTRIES  = ENTRIES(S)
			DATE_OBS = DATE_OBS(S)
			DATE_END = DATE_END(S)
		ENDIF
		IF DATE_END(0) EQ MIN_DATE_OBS THEN BEGIN
		    N_FOUND = N_FOUND - 1
		    IF N_FOUND GT 0 THEN BEGIN
			ENTRIES = ENTRIES(1:*)
			DATE_OBS = DATE_OBS(1:*)
			DATE_END = DATE_END(1:*)
		    ENDIF
		ENDIF
		IF N_FOUND GT 0 THEN BEGIN
		    IF DATE_OBS(N_FOUND-1) EQ MAX_DATE_END THEN BEGIN
			N_FOUND = N_FOUND - 1
			IF N_FOUND GT 0 THEN BEGIN
			    ENTRIES = ENTRIES(0:N_FOUND-1)
			    DATE_OBS = DATE_OBS(0:N_FOUND-1)
			    DATE_END = DATE_END(0:N_FOUND-1)
			ENDIF
		    ENDIF
		ENDIF
		IF N_FOUND GT 0 THEN DBUPDATE, ENTRIES, 'deleted',	$
			REPLICATE('Y', N_ELEMENTS(ENTRIES))
	    ENDIF
	ENDFOR
;
;  Add the entries.
;
	DELETED = REPLICATE('N', N_ELEMENTS(DEF))
	DBBUILD, INS.CODE, DEF.DATE_OBS, DEF.DATE_END, DEF.SCI_OBJ,	$
		DEF.SCI_SPEC, DEF.OBS_PROG, DEF.PROG_ID, DEF.CMP_NO,	$
		OBJ.OBJECT, DEF.OBJ_ID,	DEF.XCEN, DEF.YCEN, DEF.ANGLE,	$
		DEF.IXWIDTH, DEF.IYWIDTH, DEF.DISTURBANCES, DEF.JITTER_LIMIT, $
		DELETED, STATUS=STATUS
	IF STATUS EQ 0 THEN BEGIN
	   MESSAGE = 'Write to soho_details database was not successful'
	   GOTO, HANDLE_ERROR
	ENDIF
;
;  Signal success.
;
	RESULT = 1
	GOTO, FINISH
;
;  Error handling point.
;
HANDLE_ERROR:
	IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = 'UPD_SOHO_DET: ' + MESSAGE $
		ELSE MESSAGE, MESSAGE, /CONTINUE
;
;  Close the database, and return whether the routine was successful or not.
;
FINISH:
	DBCLOSE
;
	RETURN, RESULT
	END
