;
; NAME:
;	NEW_TAG_FROM_LINE
;
; PURPOSE:
;	This routine creates a new Tag object from a string (presumably
;	read from the RDF header/tail)
;
; CATEGORY:
;	RDF Input/Output
;
; CALLING SEQUENCE:
;	tagPtr = NEW_TAG_FROM_LINE(line, mode)
;
; INPUTS:
;	line: The line to be converted to a Tag object
;
; KEYWORDS:
;	none
;
; OUTPUTS:
;	tagPtr: A pointer to the newly allocated Tag object
;	mode: A string describing the processing that occured.
;		'error' indicates that an error occurred while trying
;		    convert the string to a tag.
;		'blank' indicates that a blank line was found and
;		    no new tag was created.
;		'terminator' indicates that a line with a single '.'
;		    was found, specifying the end of the header/tail.
;		'tag' is used to indicate that a new tag was created.
;
; SIDE EFFECTS:
;	"mode" is set to indicate how the string->Tag conversion went.
;	Memory is allocated for the new Tag.  This should be freed
;	using OBJ_DESTROY and PTR_FREE
;
; RESTRICTIONS:
;	The line should conform to the normal RDF tag specification to
;	avoid any errors.
;
;
; EXAMPLE:
;	READF, lun, inputline
;	tagPtr = NEW_TAG_FROM_LINE(inputline, mode)
;	IF (mode EQ 'error') THEN $
;	    MESSAGE, 'Invalid tag line in RDF: ' + curline
;	
;
; MODIFICATION HISTORY
;	Written, MLT, April 1999
;

FUNCTION new_tag_from_line, line, mode
    IF (line EQ '.') THEN BEGIN
	mode = 'terminator'
	return, PTR_NEW()
    ENDIF

    fieldArr = str_split(line, /trim)

    ;
    ; Ignore blank lines
    ;

    IF (N_ELEMENTS(fieldArr) eq 0) THEN BEGIN
	mode = 'blank'
	return, PTR_NEW()
    ENDIF

;    print, "line = " + line
    if (N_ELEMENTS(fieldArr) eq 1) THEN BEGIN
	IF (STRLEN(fieldarr[0]) EQ 0) THEN BEGIN
	    mode = 'blank'
	ENDIF ELSE IF (fieldArr[0] eq '.') THEN BEGIN
	    mode = 'terminator'
	ENDIF ELSE BEGIN
	    mode = 'error'
	ENDELSE

	return, PTR_NEW()
    ENDIF

    type = fieldArr[0]

    ;
    ; Special processing for comments
    ;

    IF type EQ '#' THEN BEGIN
	name=''
	value = ''
	comment = STRMID(line, 2)
    ENDIF ELSE BEGIN
	IF N_ELEMENTS(fieldarr) LT 3 THEN BEGIN
	    mode = 'error'
	    return, PTR_NEW()
	ENDIF

	name = fieldArr[1]
	value = fieldArr[2]
	comment = ''
    ENDELSE

    IF (type eq 'v') THEN BEGIN
	value = fieldArr[2:*]
    ENDIF

    tagVar = OBJ_NEW('rtag', type, NAME=name, VALUE=value, COMMENT=comment)

    mode = 'tag'

    return, PTR_NEW(tagVar)
END

;
; NAME:
;	READ_RDF
;
; PURPOSE:
;	This routine reads in the next RDF frame from an open
;	"lun".  It is primarily used in READ_ALL_RDF.
;
; CATEGORY:
;	RDF Input/Output
;
; CALLING SEQUENCE:
;	rdfVar = READ_RDF(lun)
;
; INPUTS:
;	lun: A Logical Unit Number that has been opened for reading.
;		See the OPENR help entry for details on this.
;		Ex:  OPENR, lun, 'file.rdf', /GET_LUN
;
; KEYWORDS:
;	none
;
; OUTPUTS:
;	rdfVar: A reference to a RDF object.
;
; SIDE EFFECTS:
;	The routine creates a new RDF object that must be cleaned up
;	using OBJ_DESTROY.  The lun is positioned at the end of the
;	RDF frame that was read, so that the next call to READ_RDF
;	on this lun will return the next RDF frame in the file.
;
; RESTRICTIONS:
;	READ_RDF returns a "reference" to a RDF object.  This is not
;	enough to use with the rest of the RDF processing routines.
;	Use READ_ALL_RDF to get an array of RDFs that you can use with
;	the processing routines.  Or read the IDL help system to learn
;	how to convert these RDF object references into an array of RDF
;	pointers.
;
; EXAMPLE:
;    Open up a new file and read the first RDF
;	OPENR, lun, 'input.rdf', /GET_LUN
;	rdfVar = READ_RDF(lun)
;
;    Read the next RDF in the file:
;	rdfVar2 = READ_RDF(lun)
;
; MODIFICATION HISTORY
;	Written, MLT, April 1999
;

FUNCTION read_rdf, lun

; Read the RDF header

MODE = 'tag_header'

;
; Read the header
;

rVar = OBJ_NEW('rdf')

REPEAT BEGIN
    curline = ''
    IF EOF(lun) THEN BEGIN
	MODE = 'eof'
    ENDIF ELSE BEGIN
	readf, lun, curline
	tagPtr = new_tag_from_line(curline, mode)
	IF PTR_VALID(tagPtr) THEN BEGIN
	    rVar->setval, (*tagPtr)->gettype(), (*tagPtr)->getname(), $
	    		(*tagPtr)->getvalue(), LOCATION='h'
	    obj_destroy, *tagPtr
	    ptr_free, tagPtr
	    mode = 'tag_header'
	ENDIF ELSE BEGIN
	    IF (mode EQ 'blank') THEN BEGIN
		mode = 'tag_header'
	    ENDIF ELSE IF (mode EQ 'error') THEN BEGIN
		MESSAGE, 'Invalid tag line in RDF header: ' + curline
	    ENDIF ELSE BEGIN
;		PRINT, "mode = " + mode
	    ENDELSE
	ENDELSE

    ENDELSE
ENDREP UNTIL MODE NE 'tag_header'

;
; Read the data
;

;print, "reading data"
readu, lun, rVar->getdata()

;
; Read the tail
;

;print, "reading tail"
mode = 'tag_tail'
REPEAT BEGIN
    curline = ''
    IF EOF(lun) THEN BEGIN
	MODE = 'eof'
    ENDIF ELSE BEGIN
	readf, lun, curline
	tagPtr = new_tag_from_line(curline, mode)

	IF PTR_VALID(tagPtr) THEN BEGIN
	    rVar->setval, (*tagPtr)->gettype(), (*tagPtr)->getname(), $
	    		(*tagPtr)->getvalue(), $
			COMMENT=(*tagPtr)->getcomment(), $
			LOCATION='t'
	    obj_destroy, *tagPtr
	    ptr_free, tagPtr
	    mode = 'tag_tail'
	ENDIF ELSE BEGIN
	    IF (mode EQ 'blank') THEN BEGIN
		mode = 'tag_tail'
	    ENDIF ELSE IF (mode EQ 'error') THEN BEGIN
		MESSAGE, 'Invalid tag line in RDF tail: ' + curline
	    ENDIF ELSE BEGIN
;		PRINT, 'Unknown mode returned:  ' + mode
	    ENDELSE
	ENDELSE
    ENDELSE
ENDREP UNTIL MODE NE 'tag_tail'

return, rVar

END