;+
; Project     :	SOHO - CDS     
;                   
; Name        :	WRITE_IAP
;               
; Purpose     :	Write out the IAP from the science plan.
;               
; Explanation :	Writes out the Instrument Activity Plan file using the keyword
;		format from the Interface Control Document, based on the
;		information in the science plan database.
;               
; Use         :	Result = WRITE_IAP( OP_DAY )
;
;		IF WRITE_IAP('1995/03/30') THEN ...
;    
; Inputs      :	OP_DAY	= Operational day in any CDS UTC format.  Only the UTC
;			  date will be used--any time-of-day information will
;			  be ignored.
;               
; Opt. Inputs :	None.
;               
; Outputs     :	The IAP is written to a file in the directory given by the
;		environment variable CDS_IAP_W.  The filename has the format
;		"CDSyyyymmddvvv.IAP", where the number is chosen to make the
;		filename unique.
;
;		The result of the function is 1 for successful and 0 for
;		unsuccessful. 
;               
; Opt. Outputs:	None.
;               
; Keywords    :	OBSERVER = Name to place in the OBSERVER field in the output
;			   file.  If not passed, then "CDS Staff" is used.
;		COMMENT	 = Optional string array containing comments to put in
;			   the file header.
;		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.  In
;			   order to use this feature, ERRMSG must be defined
;			   first, e.g.
;
;				ERRMSG = ''
;				Result = WRITE_IAP(OP_DAY, ERRMSG=ERRMSG)
;				IF ERRMSG NE '' THEN ...
;
;		FILE    = output IAP file
;
; Calls       :	LIST_PLAN, TRIM, BREAK_FILE, CONCAT_PNT
;
; Common      :	None.
;               
; Restrictions:	Env. var. ZDBASE must point to directory containing the dbase.
;               
; Side effects:	Even if this routine is successful, it will return a non-null
;		value for ERRMSG.
;               
; Category    :	Planning, Science
;               
; Prev. Hist. :	None
;
; Written     :	William Thompson, 15 November 1994
;               
; Modified    :	Version 1, William Thompson, GSFC, 5 April 1995
;               Version 2, Dominic Zarro, GSFC, 1 May 1995 
;                - Added FILE keyword
;		Version 3, William Thompson, GSFC, 2 May 1995
;			Modified ORIG_ID to work in csh, made an email address.
;		Version 4, William Thompson, GSFC, 3 May 1995
;			Added pointing keywords to output
;		Version 5, William Thompson, GSFC, 9 May 1995
;			Added INST_IIE_RECEIVER item to output.
;		Version 6, William Thompson, GSFC, 26 May 1995
;			Fixed bug with writing INST_IEE_RECEIVER items
;		Version 7, William Thompson, GSFC, 1-Aug-1995
;			Changed output filenaming convention
;		Version 8, William Thompson, GSFC, 11 October 1995
;			Added INST_IIE_MASTER item to output
;			Refined INST_IIE_RECEIVER item.
;			Added XCEN, YCEN to SCIPLAN entries.
;		Version 9, William Thompson, GSFC, 18 October 1995
;			Changed environment variable to CDS_IAP_W
;               Version 10, Zarro, GSFC, 7 December 1995
;                       Added check for non-existent FLAG entries
;               Version 11, Zarro, GSFC, 20 November 1996
;                       Made CMP_NO=0 a valid number
;               Version 12, Zarro, GSFC, 20 January 1997
;                       Converted to using GET_CDS_STUDY in place of GET_STUDY
;               Version 13, Zarro, GSFC, 8 July 1997
;                       Added /NOTRUNCATE keyword
;               Version 14, Zarro, GSFC, 28 July 1997
;                       Changed to remove double underscores
;               Version 15, Zarro, GSFC, 31 Aug 1997
;                       Added /NOCONCAT keyword to inhibit
;                       concatanating raster pointings
;		Version 16, 28-May-1998, William Thompson, GSFC
;			Prepend X to science plan mnemonic if first character
;			would be an integer.
;
; Version     :	Version 16, 28-May-1998
;-
;
;-------------------------------------------------------------------------------

                PRO CONCAT_IAP,DET,UNIT    ;-- concatanate PLAN pointings

		PNT = GET_CDS_POINT(DET)
		N_POINTINGS = 0
;
;  First, extract all the fixed pointings.
;
		IF PNT.N_RASTERS GT 0 THEN BEGIN
		    W = WHERE(PNT.RASTERS.POINTING EQ 0, COUNT)
		    IF COUNT GT 0 THEN BEGIN
			INS_X  = PNT.RASTERS(W).INS_X
			INS_Y  = PNT.RASTERS(W).INS_Y
			WIDTH  = PNT.RASTERS(W).WIDTH
			HEIGHT = PNT.RASTERS(W).HEIGHT
			N_POINTINGS = COUNT
		    ENDIF
;
;  If the first pointing is fixed, then find any pointings relative to it.
;
		    IF PNT.RASTERS(0).POINTING EQ 0 THEN BEGIN
			INS_X1 = PNT.RASTERS(0).INS_X
			INS_Y1 = PNT.RASTERS(0).INS_Y
			W = WHERE(PNT.RASTERS.POINTING EQ -1, COUNT)
			IF COUNT GT 0 THEN BEGIN
			    INS_X1  = INS_X1 + PNT.RASTERS(W).INS_X
			    INS_Y1  = INS_Y1 + PNT.RASTERS(W).INS_Y
			    WIDTH1  = PNT.RASTERS(W).WIDTH
			    HEIGHT1  = PNT.RASTERS(W).HEIGHT
			    INS_X  = [INS_X,  INS_X1(*)]
			    INS_Y  = [INS_Y,  INS_Y1(*)]
			    WIDTH  = [WIDTH,  WIDTH1(*)]
			    HEIGHT = [HEIGHT, HEIGHT1(*)]
			    N_POINTINGS = N_POINTINGS +	$
				    COUNT * PNT.N_POINTINGS
			ENDIF
		    ENDIF
;
;  Next, extract all the deferred pointings.  There's a separate entry for each
;  raster and target combination.
;
		    IF PNT.N_POINTINGS GT 0 THEN BEGIN
			W = WHERE(PNT.RASTERS.POINTING EQ 1, COUNT)
			IF COUNT GT 0 THEN BEGIN
			    INS_X1  = REPLICATE(1,COUNT) #		$
				    (PNT.POINTINGS.INS_X)(*)
			    INS_Y1  = REPLICATE(1,COUNT) #		$
				    (PNT.POINTINGS.INS_Y)(*)
			    WIDTH1  = (PNT.RASTERS.WIDTH)(W) #		$
				    REPLICATE(1,PNT.N_POINTINGS)
			    HEIGHT1  = (PNT.RASTERS.HEIGHT)(W) #	$
				    REPLICATE(1,PNT.N_POINTINGS)
			    IF N_POINTINGS EQ 0 THEN BEGIN
				INS_X  = INS_X1(*)
				INS_Y  = INS_Y1(*)
				WIDTH  = WIDTH1(*)
				HEIGHT = HEIGHT1(*)
				N_POINTINGS = COUNT * PNT.N_POINTINGS
			    END ELSE BEGIN
				INS_X  = [INS_X,  INS_X1(*)]
				INS_Y  = [INS_Y,  INS_Y1(*)]
				WIDTH  = [WIDTH,  WIDTH1(*)]
				HEIGHT = [HEIGHT, HEIGHT1(*)]
				N_POINTINGS = N_POINTINGS +	$
					COUNT * PNT.N_POINTINGS
			    ENDELSE
			ENDIF
;
;  If the first pointing is deferred, then find all the pointings relative to
;  it.
;
			IF PNT.RASTERS(0).POINTING EQ 1 THEN BEGIN
			    W = WHERE(PNT.RASTERS.POINTING EQ -1, COUNT)
			    IF COUNT GT 0 THEN BEGIN
				INS_X1  = REPLICATE(1,COUNT) #		$
						(PNT.POINTINGS.INS_X)(*) + $
					(PNT.RASTERS.INS_X)(W) #	$
						REPLICATE(1,PNT.N_POINTINGS)
				INS_Y1  = REPLICATE(1,COUNT) #		$
						(PNT.POINTINGS.INS_Y)(*) + $
					(PNT.RASTERS.INS_Y)(W) #	$
						REPLICATE(1,PNT.N_POINTINGS)
				WIDTH1  = (PNT.RASTERS.WIDTH)(W) #	$
					REPLICATE(1,PNT.N_POINTINGS)
				HEIGHT1  = (PNT.RASTERS.HEIGHT)(W) #	$
					REPLICATE(1,PNT.N_POINTINGS)
				INS_X  = [INS_X,  INS_X1(*)]
				INS_Y  = [INS_Y,  INS_Y1(*)]
				WIDTH  = [WIDTH,  WIDTH1(*)]
				HEIGHT = [HEIGHT, HEIGHT1(*)]
				N_POINTINGS = N_POINTINGS +	$
					COUNT * PNT.N_POINTINGS
			    ENDIF
			ENDIF
;
		    ENDIF		;If PNT.N_POINTINGS GT 0
		ENDIF			;IF PNT.N_RASTERS GT 0

	 	IF (N_POINTINGS GT 0) THEN BEGIN
                    CONCAT_PNT, INS_X, INS_Y, WIDTH, HEIGHT, ANGLE, /STRING 
                    PRINT_PNT,UNIT,INS_X,INS_Y,WIDTH,HEIGHT,ANGLE
		ENDIF

                RETURN & END

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

                PRO PRINT_PNT,UNIT,INS_X,INS_Y,WIDTH,HEIGHT,ANGLE
                    
		    FOR J = 0,N_ELEMENTS(INS_X)-1 DO	$
			IF INS_X(J) NE '' THEN PRINTF, UNIT, '	XCEN     = ' + INS_X(J)
		    FOR J = 0,N_ELEMENTS(INS_Y)-1 DO	$
			IF INS_Y(J) NE '' THEN PRINTF, UNIT, '	YCEN     = ' + INS_Y(J)
		    FOR J = 0,N_ELEMENTS(WIDTH)-1 DO	$
			IF WIDTH(J) THEN PRINTF, UNIT, '	IXWIDTH  = ' + WIDTH(J)
		    FOR J = 0,N_ELEMENTS(HEIGHT)-1 DO	$
			IF HEIGHT(J) NE '' THEN PRINTF, UNIT, '	IYWIDTH  = ' + HEIGHT(J)
		    FOR J = 0,N_ELEMENTS(ANGLE)-1 DO	$
			IF ANGLE(J) NE ''  THEN PRINTF, UNIT, '	ANGLE    = ' + ANGLE(J)

                 RETURN & END

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

   FUNCTION WRITE_IAP, OP_DAY, OBSERVER=OBSERVER, COMMENT=COMMENT, $
		ERRMSG=ERRMSG, FILE=FILE, $
                NOTRUNCATE=NOTRUNCATE, NOCONCAT=NOCONCAT

   TRUNCATE=1-KEYWORD_SET(NOTRUNCATE)
   CONCAT=1-KEYWORD_SET(NOCONCAT)

;  Initialize the message to be returned.  Also initialize the RESULT to 0.  If
;  the routine is successful, this parameter will be updated below.
;
	MESSAGE = ''
	RESULT = 0
;
;  Check the input parameters.
;
	IF N_PARAMS() NE 1 THEN BEGIN
		MESSAGE = 'Syntax:  Result = WRITE_IAP( OP_DAY )'
		GOTO, HANDLE_ERROR
	ENDIF
;
;  Parse the operational day into CDS internal format.  Calculate the start
;  time and end time.
;
	START_TIME = ANYTIM2UTC(OP_DAY, ERRMSG=ERRMSG)
	IF N_ELEMENTS(ERRMSG) NE 0 THEN		$
		IF ERRMSG(0) NE '' THEN GOTO, HANDLE_ERROR
	START_TIME.TIME = 0
	END_TIME = START_TIME
	END_TIME.MJD = END_TIME.MJD + 1
;
;  Form the first part of the filename.
;
	DATE = ANYTIM2UTC(START_TIME, /EXTERNAL)
	NAME = 'CDS' + TRIM(DATE.YEAR) +		$
		STRMID(TRIM(100+DATE.MONTH),1,2) +	$
		STRMID(TRIM(100+DATE.DAY),1,2)
;
;  Find all the IAP files with names starting with those characters.  Get the
;  highest version number and add one to it.
;
	FOUND = LOC_FILE(CONCAT_DIR('$CDS_IAP_W', NAME + '*.IAP'), COUNT=COUNT)
	IF COUNT EQ 0 THEN VERSION = 1 ELSE BEGIN
		FOUND = FOUND(SORT([FOUND]))
		BREAK_FILE, FOUND(COUNT-1), DISK, DIR, FILENAME, EXT
		VERSION = FIX(STRMID(FILENAME,11,3)) + 1
	ENDELSE
	NAME = NAME + STRMID(TRIM(1000+VERSION),1,3) + '.IAP'
;
;  Open the output file, and write the header.  Use ".IAP" as the default
;  extension.
;
	FILE = CONCAT_DIR('$CDS_IAP_W', NAME)
	ON_IOERROR, ERROR_POINT
	OPENW, UNIT, FILE, /GET_LUN
	PRINTF, UNIT, 'DATATYPE = INSTRUMENTER INPUT TO THE ACTIVITY PLAN'
	PRINTF, UNIT, 'FILENAME = ' + NAME
	PRINTF, UNIT, 'INSTRUME = CDS'
	HOSTNAME=GET_HOST()
	PRINTF, UNIT, 'ORIG_ID  = ' + GETENV('LOGNAME') + '@' + HOSTNAME
;
;  If OBSERVER was not passed, then use "CDS Staff"
;
	IF N_ELEMENTS(OBSERVER) EQ 0 THEN OBSERVER = 'CDS Staff'
	PRINTF, UNIT, 'OBSERVER = ' + OBSERVER
	GET_UTC, UTC, /ECS, /TRUNCATE
	PRINTF, UNIT, 'DATE_CRE = ' + UTC
	PRINTF, UNIT, 'STARTIME = ' + ANYTIM2UTC(START_TIME, /ECS, /TRUNCATE)
	PRINTF, UNIT, 'ENDTIME  = ' + ANYTIM2UTC(END_TIME,   /ECS, /TRUNCATE)
;
;  If COMMENT was passed, then write out the comments.
;
	FOR I = 0, N_ELEMENTS(COMMENT)-1 DO	$
		PRINTF, UNIT, 'COMMENT  = ' + COMMENT(I)
	PRINTF, UNIT, 'END'
;
;  Convert the input times to TAI.
;
	IF DATATYPE(START_TIME,1) EQ 'Double' THEN TAI_START = START_TIME $
		ELSE TAI_START = UTC2TAI(START_TIME)
	IF DATATYPE(END_TIME,1) EQ 'Double' THEN TAI_END = END_TIME ELSE $
		TAI_END = UTC2TAI(END_TIME)
;
;  Retrieve the information from the sci_plan database.
;
	LIST_PLAN, START_TIME, END_TIME, PLAN, N, INSTRUMENT='CDS'
;
;  For each entry, write out the data to the file.
;
	FOR I = 0, N-1 DO BEGIN
;
;  Ignore it if it starts before the operational day, or just at the end of the
;  operational day.
;
	    IF (TAI_START LE PLAN(I).START_TIME) AND	$
			(TAI_END GT PLAN(I).START_TIME) THEN BEGIN
;
;  Form the header from the scientific objective.  Use no more than 10
;  characters.  Replace any nonalphanumeric characters with underscores.
;  Changed to remove double underscores since they crash ECS (Zarro, 28-July-97)
;  Prepend "X" if the first character is a number (Thompson, 28-May-1998)
;
		B = BYTE( STRMID( STRTRIM( PLAN(I).SCI_OBJ, 2), 0, 10))
		IF (B(0) GE 48B) AND (B(0) LE 57B) THEN B = [BYTE('X'), B(0:8)]
		W = WHERE((B LT 48B) OR			$
			((B GT 57B) AND (B LT 65B)) OR	$
			((B GT 90B) AND (B LT 97B)) OR	$
			(B GT 122B), COUNT)
		IF COUNT GT 0 THEN B(W) = 95B

		PRINTF, UNIT, ''
                TEMP=REM_SEQ(BYTE('SCIPLAN_' + STRING(B)),95B)
		PRINTF, UNIT, STRING(TEMP)
;
;  Write out the start and end times.
;
		PRINTF, UNIT, '	STARTIME = ' +	$
			TAI2UTC(PLAN(I).START_TIME, /ECS, TRUNCATE=TRUNCATE)
		PRINTF, UNIT, '	ENDTIME  = ' +	$
			TAI2UTC(PLAN(I).END_TIME,   /ECS, TRUNCATE=TRUNCATE)
;
;  Add the other keywords.
;
		PRINTF, UNIT, '	INSTRUME = CDS'
;
		PRINTF, UNIT, '	SCI_OBJ  = ' + TRIM(PLAN(I).SCI_OBJ)
;
		TEST = TRIM(PLAN(I).SCI_SPEC)
		IF TEST NE '' THEN PRINTF, UNIT, '	SCI_SPEC = ' + TEST
;
		PRINTF, UNIT, '	OBJECT   = ' + TRIM(PLAN(I).OBJECT)
;
		TEST = TRIM(PLAN(I).OBJ_ID)
		IF TEST NE '' THEN PRINTF, UNIT, '	OBJ_ID   = ' + TEST
;
		TEST = TRIM(PLAN(I).XCEN)
		IF TEST NE '' THEN PRINTF, UNIT, '	XCEN     = ' + TEST
;
		TEST = TRIM(PLAN(I).YCEN)
		IF TEST NE '' THEN PRINTF, UNIT, '	YCEN     = ' + TEST
;
		TEST = TRIM(PLAN(I).NOTES)
		IF TEST NE '' THEN PRINTF, UNIT, '	NOTES    = ' + TEST
;
		IF PLAN(I).PROG_ID GT 0 THEN		$
			PRINTF, UNIT, '	PROG_ID  = ' + TRIM(PLAN(I).PROG_ID)
;
		IF PLAN(I).CMP_NO GE 0 THEN		$
			PRINTF, UNIT, '	CMP_NO   = ' + TRIM(PLAN(I).CMP_NO)
;
		TEST = TRIM(PLAN(I).DISTURBANCES)
		IF TEST NE '' THEN PRINTF, UNIT, '	DISTURB  = ' + TEST
;
	    ENDIF
	ENDFOR
;
;  Retrieve the information from the sci_details database.
;
	LIST_DETAIL, START_TIME, END_TIME, PLAN, N
;
;  For each entry, write out the data to the file.
;
	FOR I = 0, N-1 DO BEGIN
;
;  Ignore it if it starts before the operational day, or just at the end of the
;  operational day.
;
	    IF (TAI_START LE PLAN(I).DATE_OBS) AND	$
			(TAI_END GT PLAN(I).DATE_OBS) THEN BEGIN
;
;  Form the header from the scientific objective.  Use no more than 10
;  characters.  Replace any nonalphanumeric characters with underscores.
;  Changed to remove double underscores since they crash ECS (Zarro, 28-July-97)
;
		B = BYTE( STRMID( STRTRIM( PLAN(I).SCI_OBJ, 2), 0, 10))
		W = WHERE((B LT 48B) OR			$
			((B GT 57B) AND (B LT 65B)) OR	$
			((B GT 90B) AND (B LT 97B)) OR	$
			(B GT 122B), COUNT)
		IF COUNT GT 0 THEN B(W) = 95B
		PRINTF, UNIT, ''
                TEMP=REM_SEQ(BYTE('PROGRAM_' + STRING(B)),95B)
		PRINTF, UNIT, STRING(TEMP)

;
;  Write out the start and end times.
;
		PRINTF, UNIT, '	STARTIME = ' +	$
			TAI2UTC(PLAN(I).DATE_OBS, /ECS, TRUNCATE=TRUNCATE)
		PRINTF, UNIT, '	ENDTIME  = ' +	$
			TAI2UTC(PLAN(I).DATE_END, /ECS, TRUNCATE=TRUNCATE)
;
;  Add the other keywords.
;
		PRINTF, UNIT, '	INSTRUME = CDS'
;
;  From the study ID, get the study name.
;
;		GET_STUDY,PLAN(I).STUDY_ID, PLAN(I).STUDYVAR,STUDY
                STUDY=GET_CDS_STUDY(PLAN(I).STUDY_ID, PLAN(I).STUDYVAR)
		PRINTF, UNIT, '	OBS_PROG = ' + TRIM(STUDY.OBS_PROG)
;
		PRINTF, UNIT, '	SCI_OBJ  = ' + TRIM(PLAN(I).SCI_OBJ)
;
		TEST = TRIM(PLAN(I).SCI_SPEC)
		IF TEST NE '' THEN PRINTF, UNIT, '	SCI_SPEC = ' + TEST
;
		PRINTF, UNIT, '	OBJECT   = ' + TRIM(PLAN(I).OBJECT)
;
		TEST = TRIM(PLAN(I).OBJ_ID)
		IF TEST NE '' THEN PRINTF, UNIT, '	OBJ_ID   = ' + TEST
;
		IF PLAN(I).PROG_ID GT 0 THEN		$
			PRINTF, UNIT, '	PROG_ID  = ' + TRIM(PLAN(I).PROG_ID)
;
		IF PLAN(I).CMP_NO GE 0 THEN		$
			PRINTF, UNIT, '	CMP_NO   = ' + TRIM(PLAN(I).CMP_NO)
;
;  Get the pointings.
;
		GET_DETAIL, PLAN(I).DATE_OBS, DET,KEEP_OPEN=(I LT (N-1))

;
;  If any pointings were found, then concatenate and write out the pointings.
;
                IF CONCAT THEN CONCAT_IAP,DET,UNIT ELSE BEGIN
                 get_cds_xy,det,ins_x,ins_y,study=study,/string
                 get_cds_fov,det,width,height,study=study,/string
                 print_pnt,unit,ins_x,ins_y,width,height
                endelse


;  If FLAG_MASTER is positive, then write out a INST_IIE_MASTER entry as well.
;
		IF PLAN(I).FLAG_MASTER GT 0 THEN BEGIN
		    PRINTF, UNIT, 'INST_IIE_MASTER'
		    PRINTF, UNIT, '	INSTRUME = CDS'
		    PRINTF, UNIT, '	MSTR_START = ' +	$
			    TAI2UTC(PLAN(I).DATE_OBS, /ECS, TRUNCATE=TRUNCATE)
		    PRINTF, UNIT, '	MSTR_STOP = ' +		$
			    TAI2UTC(PLAN(I).DATE_END, /ECS, TRUNCATE=TRUNCATE)
		ENDIF
;
	    ENDIF			;If <within operational day>
	ENDFOR
;
;  Retrieve the information from the science flag database.
;
	LIST_FLAG, START_TIME, END_TIME, PLAN, N
;
;  For each entry, write out a flag receiver entry to the file.
;
	FOR I = 0, N-1 DO BEGIN
;
;  Ignore it if it starts before the operational day, or just at the end of the
;  operational day.  Also ignore it if CDS is generating a flag at the same
;  time--this means that CDS is simply responding to it's own flag.
;
	    IF (TAI_START LE PLAN(I).RCVR_START) AND	$
			(TAI_END GT PLAN(I).RCVR_START) THEN BEGIN
                ERR=''
		GET_DETAIL, PLAN(I).RCVR_START, TEMP,ERR=ERR

;
; check for accompanying FLAG entries
;
                IF ERR EQ '' THEN BEGIN                     
                 IF TEMP.FLAG_MASTER EQ 0 THEN BEGIN
		    PRINTF, UNIT, 'INST_IIE_RECEIVER'
		    PRINTF, UNIT, '	INSTRUME = CDS'
;
;  Write out the start and end times.
;
		    PRINTF, UNIT, '	RCVR_START = ' +	$
			    TAI2UTC(PLAN(I).RCVR_START, /ECS, TRUNCATE=TRUNCATE)
		    PRINTF, UNIT, '	RCVR_STOP  = ' +	$
			    TAI2UTC(PLAN(I).RCVR_STOP, /ECS, TRUNCATE=TRUNCATE)
		 ENDIF
                ENDIF ELSE MESSAGE,'Flag Entry Without Accompanying Details Entry',/cont
	    ENDIF
	ENDFOR
;
;  Print out a message stating that the file was written.
;
	FILE_STATUS = FSTAT(UNIT)
	MESSAGE = 'Wrote file ' + FILE_STATUS.NAME
	IF N_ELEMENTS(ERRMSG) EQ 0 THEN PRINT, MESSAGE
	RESULT = 1
	GOTO, EXIT_POINT
;
;  If you reach this point, you've hit an error.
;
ERROR_POINT:
	ON_IOERROR, NULL
	MESSAGE = 'Error writing file ' + FILE
;
;  This is the error handling point, where the message is either printed
;  immediately, or returned as a keyword.
;
HANDLE_ERROR:
	IF N_ELEMENTS(ERRMSG) EQ 0 THEN MESSAGE, MESSAGE, /CONTINUE
;
;  Whether you hit an error or not, you will reach this point.  Close the file
;  and return.
;
EXIT_POINT:
	IF N_ELEMENTS(UNIT) NE 0 THEN FREE_LUN, UNIT
	IF N_ELEMENTS(ERRMSG) NE 0 THEN ERRMSG = MESSAGE
	RETURN, RESULT
	END
