;+
; PROJECT:
;       SOHO - CDS
;
; NAME:
;       ADD_CAMPAIGN()
;
; PURPOSE:
;       Adds a CDS campaign record to the database
;
; CATEGORY:
;       Planning, Databases
;
; EXPLANATION:
;       This procedure takes a CDS campaign entry and adds it to the
;       database table CAMPAIGN.  This database contains a series of such
;       entries, making a historical list.
;
; SYNTAX:
;       Result = add_campaign(DEF)
;
; INPUTS:
;       DEF = This is an anonymous structure containing the following tags:
;
;             CMP_NO   = Unique identifier number.  If no matches
;                        are found, then a simpler structure is
;                        returned with this set to -1.
;             CMP_NAME = Name of the campaign.
;	      CMP_TYPE = Campaign type, e.g. JOP, Intercal, etc.
;             CMP_DESC = Up to five lines of text (400 characters)
;                        describing the campaign.
;             DATE_OBS = Starting date for the observing campaign
;             DATE_END = Ending data for the campaign
;             OBSERVER = Observer in overall charge of the campaign
;	      COMMENT  = A comment associated with the campaign
;	      INSTITUTES = Structure containing information about the
;			 institutes involved, with the following tags:
;
;			INSTITUT = The name of the institute.
;			OBSERVER = The name of the observer at that institute
;
;
; OPTIONAL 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.
;
; OPTIONAL 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 = ADD_CAMPAIGN( ERRMSG=ERRMSG, ... )
;                       IF ERRMSG NE '' THEN ...
;
; COMMON:
;       None.
;
; RESTRICTIONS:
; 	Only this routine and MOD_CAMPAIGN can be used to add or update
;	SOHO campaigns 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.
;
; SIDE EFFECTS:
;	The dates in the structure are rounded off to millisecond
;	accuracy.
;
; HISTORY:
;       Version 1, 10-Sep-1996, William Thompson, GSFC
;		Converted from SUMER version by Liyun Wang
;	Version 2, 23-Sep-1996, William Thompson, GSFC
;		Added campaign type, changed string lengths.
;	Version 3, 22-Nov-1996, Zarro, GSFC
;		Added call to TRIM_CAMPAIGN
;
; CONTACT:
;       WTHOMPSON
;-
;

FUNCTION add_campaign, def, errmsg=errmsg

   ON_ERROR, 1

;---------------------------------------------------------------------------
;  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
      msg = 'Syntax:  Result = add_campaign(def)'
      GOTO, handle_error
   ENDIF
;
;  Make sure that the user has privilege to write into the database.
;
	IF !PRIV LT 2 THEN BEGIN $
           MSG = '!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.
;---------------------------------------------------------------------------
   type = datatype(def.cmp_no, 2)
   IF (type LT 2) OR (type GT 3) THEN BEGIN
      msg = 'Tag CMP_NO must be an integer'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.cmp_no) NE 1 THEN BEGIN
      msg = 'Tag CMP_NO must be a scalar'
      GOTO, handle_error
   ENDIF

   IF datatype(def.cmp_name, 1) NE 'String' THEN BEGIN
      msg = 'Tag CMP_NAME must be a character string'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.cmp_name) NE 1 THEN BEGIN
      msg = 'Tag CMP_NAME must be a scalar'
      GOTO, handle_error
   END ELSE IF STRLEN(def.cmp_name) GT 120 THEN BEGIN
      def.cmp_name = STRMID(def.cmp_name, 0, 120)
      MESSAGE, 'Tag CMP_NAME trimmed to 120 characters long.', /cont
   ENDIF

   IF datatype(def.cmp_type, 1) NE 'String' THEN BEGIN
      msg = 'Tag CMP_TYPE must be a character string'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.cmp_type) NE 1 THEN BEGIN
      msg = 'Tag CMP_TYPE must be a scalar'
      GOTO, handle_error
   END ELSE IF STRLEN(def.cmp_type) GT 20 THEN BEGIN
      def.cmp_type = STRMID(def.cmp_type, 0, 20)
      MESSAGE, 'Tag CMP_TYPE trimmed to 20 characters long.', /cont
   ENDIF

   IF datatype(def.observer, 1) NE 'String' THEN BEGIN
      msg = 'Tag OBSERVER must be a character string'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.observer) NE 1 THEN BEGIN
      msg = 'Tag OBSERVER must be a scalar'
      GOTO, handle_error
   END ELSE IF STRLEN(def.observer) GT 120 THEN BEGIN
      def.observer = STRMID(def.observer, 0, 120)
      MESSAGE, 'Tag OBSERVER trimmed to 120 characters long.', /cont
   ENDIF

   IF datatype(def.cmp_desc, 1) NE 'String' THEN BEGIN
      msg = 'Tag CMP_DESC must be a character string'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.cmp_desc) GT 5 THEN BEGIN
      msg = 'Tag CMP_DESC must have no more than 5 elements'
      GOTO, handle_error
   END ELSE IF MAX(STRLEN(def.cmp_desc)) GT 80 THEN BEGIN
      MSG = 'Each element of tag PROGDESC must be 80 characters or less'
      GOTO, HANDLE_ERROR
   ENDIF

   IF datatype(def.date_obs, 1) NE 'Double' THEN BEGIN
      msg = 'Tag DATE_OBS must be a double precision number'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.date_obs) NE 1 THEN BEGIN
      msg = 'Tag DATE_OBS must be a scalar'
      GOTO, handle_error
   ENDIF

   IF datatype(def.date_end, 1) NE 'Double' THEN BEGIN
      msg = 'Tag DATE_END must be a double precision number'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.date_end) NE 1 THEN BEGIN
      msg = 'Tag DATE_END must be a scalar'
      GOTO, handle_error
   ENDIF

   IF datatype(def.comment, 1) NE 'String' THEN BEGIN
      msg = 'Tag COMMENT must be a character string'
      GOTO, handle_error
   END ELSE IF N_ELEMENTS(def.comment) NE 1 THEN BEGIN
      msg = 'Tag COMMENT must be a scalar'
      GOTO, handle_error
   END ELSE IF STRLEN(def.comment) GT 80 THEN BEGIN
      def.comment = STRMID(def.comment, 0, 80)
      MESSAGE, 'Tag COMMENT trimmed to 80 characters long.', /cont
   ENDIF

   FOR I=0,N_ELEMENTS(DEF.INSTITUTES)-1 DO BEGIN
	INST = DEF.INSTITUTES(I)

	IF datatype(inst.institut, 1) NE 'String' THEN BEGIN
	      msg = 'Subtag INSTITUT must be a character string'
	      GOTO, handle_error
	END ELSE IF N_ELEMENTS(inst.institut) NE 1 THEN BEGIN
	      msg = 'Subtag INSTITUT must be a scalar'
	      GOTO, handle_error
	END ELSE IF STRLEN(inst.institut) GT 80 THEN BEGIN
	      inst.institut = STRMID(inst.institut, 0, 80)
	      MESSAGE, 'Subtag INSTITUT trimmed to 80 characters long.', /cont
	ENDIF

	IF datatype(inst.observer, 1) NE 'String' THEN BEGIN
	      msg = 'Subtag OBSERVER must be a character string'
	      GOTO, handle_error
	END ELSE IF N_ELEMENTS(inst.observer) NE 1 THEN BEGIN
	      msg = 'Subtag OBSERVER must be a scalar'
	      GOTO, handle_error
	END ELSE IF STRLEN(inst.observer) GT 120 THEN BEGIN
	      inst.observer = STRMID(inst.observer, 0, 120)
	      MESSAGE, 'Subtag OBSERVER trimmed to 120 characters long.', /cont
	ENDIF

	DEF.INSTITUTES(I) = INST
   ENDFOR

;---------------------------------------------------------------------------
;  Make sure that the stop date is greater than the start date
;---------------------------------------------------------------------------
   if def.date_end lt def.date_obs then begin
      msg = 'The stop date must be greater or equal to the start date'
      GOTO, handle_error
   ENDIF

;---------------------------------------------------------------------------
;  Reformat the times to millisecond accuracy.  This is necessary so that
;  the times are written out in a controlled way.
;---------------------------------------------------------------------------
   def.date_obs = DOUBLE(STRING(def.date_obs, FORMAT='(f15.3)'))
   def.date_end = DOUBLE(STRING(def.date_end, FORMAT='(f15.3)'))

;-- Trim all string blanks

   trim_campaign,def

;
;  Concatenate the multiline campaign description into a single string.
;
	CMP_DESC = STRING(REPLICATE(32B,400))
	FOR I=0,N_ELEMENTS(DEF.CMP_DESC)-1 DO	$
		STRPUT,CMP_DESC,(DEF.CMP_DESC)(I),80*I
;
;  Open the campaign database for write access.
;
	DBOPEN, 'campaign', 1
;
;  Add the entries.
;
	IF TRIM(DEF.COMMENT) EQ '' THEN COMMENTS = 'N' ELSE COMMENTS = 'Y'
	DBBUILD, FIX(DEF.CMP_NO), DEF.CMP_NAME, DEF.CMP_TYPE, CMP_DESC, $
		DEF.DATE_OBS, DEF.DATE_END, DEF.OBSERVER, COMMENTS,	$
		STATUS=STATUS
	IF STATUS EQ 0 THEN BEGIN
           MSG = 'Write to campaign database was not successful'
           GOTO, HANDLE_ERROR
	ENDIF
;
;  Add the comment to the database, if any.
;
	IF COMMENTS EQ 'Y' THEN BEGIN
	    DBCLOSE
	    DBOPEN, 'campaign_c', 1
	    DBBUILD, DEF.CMP_NO, 1, DEF.COMMENT
	    IF STATUS EQ 0 THEN BEGIN
		MSG = 'Write to campaign comments database was not successful'
		GOTO, HANDLE_ERROR
	    ENDIF
	ENDIF
;
;  Add any institute information to the database.
;
	INST = DEF.INSTITUTES(0)
	IF TRIM(INST.INSTITUT) NE '' OR TRIM(INST.OBSERVER) NE '' THEN BEGIN
	    DBCLOSE
	    DBOPEN, 'institutes', 1
	    N_INST = N_ELEMENTS(DEF.INSTITUTES)
	    DBBUILD, REPLICATE(DEF.CMP_NO, N_INST), INDGEN(N_INST)+1,	$
		    DEF.INSTITUTES.INSTITUT, DEF.INSTITUTES.OBSERVER,	$
		    REPLICATE('N', N_INST), STATUS=STATUS
	    IF STATUS EQ 0 THEN BEGIN
        	MSG = 'Write to institutes database was not successful'
	        GOTO, HANDLE_ERROR
	    ENDIF
	ENDIF
;
;  Signal success.
;
	RESULT = 1
	GOTO, FINISH

;---------------------------------------------------------------------------
;  Error handling point
;---------------------------------------------------------------------------
handle_error:
   IF N_ELEMENTS(errmsg) NE 0 THEN $
      errmsg = 'Add_campaign: ' + msg $
   ELSE $
      MESSAGE, msg, /continue

finish:
   DBCLOSE
   RETURN, result

END
