; docformat = 'rst'

;+
; Abstract base class for including a generalized get function
; and set procedure in NRL object-oriented software. Requires IDL
; 8 or above.
;
; :History:
;   (2013-Apr-30) JTM: first working test version.
;-

;+
; Base class has no real instance variables, so nothing to
; initialize. A class that has nothing it wants to do in its intit
; can leave out that function and this one should be found.
;-
function nrl_objutil::init

    return, 1
end

;+
; Nothing to clean up in this class, but this will try to take
; care of freeing data pointers in classes that it has become
; part of if they have no cleanup method. Probably pretty
; dangerous. the classes that inherit this class should clean up
; their own mess.
;-
pro nrl_objutil::cleanup
    compile_opt idl2

    tags = tag_names(self)
    for i = 0, n_elements(tags)-1 do begin
        if datatype(self.(i)) eq 'PTR' then ptr_free, self.(i)
    endfor

    return
end

;+
; Generalized set procedure
;
; :Keywords:
;   _extra:
;     Keyword/value pairs to set.
;-
pro nrl_objutil::set, _extra=extra
    compile_opt idl2

    tags = tag_names(extra)
    all_tags = tag_names(self)
    foreach tag, tags, i do begin
        match = where(tag eq all_tags, nMatches)
        if nMatches eq 1 then begin
            if datatype(self.(match[0])) eq 'PTR' then begin
                if ptr_valid(self.(match[0])) then ptr_free, self.(match[0])
                self.(match[0]) = ptr_new(extra.(i))
            endif else self.(match[0]) = extra.(i)
        endif
    endforeach

return
end

;+
; Generalized get function
;
;  :Returns: A value for one variable or a structure of values if
;    more than one variable is requested.
;
;  :Keywords:
;    _extra:
;      Keywords for variables(s) to retrieve. One keyword returns the
;      variable. More than one returns a structure. No keywords
;      returns a structure with everything.
;-
function nrl_objutil::get, _extra=extra
    compile_opt idl2

    all_tags = tag_names(self)
    if extra ne !null then tags = tag_names(extra) else tags = all_tags
    foreach tag, tags do begin
        match = where(tag eq all_tags, nMatches)
        if nMatches eq 1 then begin
            out_data = self.(match[0])
            if datatype(out_data) eq 'PTR' then begin
                if ptr_valid(out_data) then begin
                    out_data = *out_data
                endif
            endif
            if n_elements(out_struct) eq 0 then begin
                out_struct = create_struct(tag, out_data)
            endif else out_struct = create_struct(out_struct, tag, out_data)
        endif
    endforeach
    if n_tags(out_struct) eq 1 then begin
        out_struct = out_struct.(0)
    endif

    return, out_struct
end

;+
; A quick and dirty way to debug things. Allows the user to look
; into the self structure. Be sure to .continue afterwards.
;-
pro nrl_objutil::debug
    stop

end

;+
; Abstract class contains no true instance variables.
;
;   foo:
;     Provide something for the structure.
;-   
pro nrl_objutil__define
    compile_opt idl2

    void = {nrl_objutil, $
            foo: 0b $
           }
end
