; $Id: myproperties__define.pro,v 1.9 2006/02/15 15:28:14 kneller Exp $
;###############################################################################
;
;CLASS NAME:
;        myproperties__define
;
;PURPOSE:
;       THIS IS A GENERAL PROPERTIES CLASS WHICH CAN BE INHERITED
;       BY ANY CLASS.  IT PROVIDES GENERAL setProperty AND
;       getProperty METHODS FOR THE SUBCLASS.  IT IS NOT MEANT
;       TO BE INSTANTIATED.
;
;       NOTE:   THIS CLASS IS DESIGNED FOR EASE OF USE, BUT IT DOES
;               NOT FOLLOW THE MORE TRADITIONAL SYSTEM OF PASSING
;               getProperty PROPERTIES VIA KEYWORDS.
;CATEGORY:
;       General object-oriented programming utility.
;SUPERCLASSES:
;       none
;METHODS:
;    myproperties::getProperty
;    myProperties::setProperty
;    myproperties::init
;    myproperties__define
;
;
; AUTHOR:
; Larry Kneller
; NIST Center for Neutron Research
; 100 Bureau Drive, Gaithersburg, MD 20899
; United States
; kneller@nist.gov  301-975-8839
; Jan 24,2005
;
; LICENSE:
; The software in this file is written by an employee of
; National Institute of Standards and Technology
; as part of the DAVE software project.
;
; The DAVE software package is not subject to copyright protection
; and is in the public domain. It should be considered as an
; experimental neutron scattering data reduction, visualization, and
; analysis system. As such, the authors assume no responsibility
; whatsoever for its use, and make no guarantees, expressed or
; implied, about its quality, reliability, or any other
; characteristic. The use of certain trade names or commercial
; products does not imply any endorsement of a particular product,
; nor does it imply that the named product is necessarily the best
; product for the stated purpose. We would appreciate acknowledgment
; if the DAVE software is used of if the code in this file is
; included in another product.
;
;###############################################################################
;;
;
;   Title
;           myproperties.pro
;
;   Author
;           Larry Kneller
;
;   Purpose
;           GENERIC MYPROPERTIES CLASS THAT CAN BE INHERITED BY
;           ANY OTHER CLASS AND PROVIDE setProperty AND getProperty
;           METHODS GENERALLY.
;
;
;   Usage Notes
;
;           The class that inherits this class must include a
;           class argument to the define method.
;
;           e.g.
;
;               pro myclass__define,class
;                   class = {myclass,$
;                               var1:0L,$
;                               var2:0L,$
;                               inherits myproperties $
;                               }
;
;
;               x = myclassInstance->getProperty(/var1)
;
;               myclassInstance->setProperty(var2 = 10)
;
;;;

function myproperties::getProperty,_Extra=extraKeyword
;
;NAME:
;        myproperties::getProperty
;
;PURPOSE:
;       General getProperty method.
;PARAMETERS:
;       none
;KEYWORDS:
;       none
;_EXTRA - is used to pass keywords of properties to retrieve.

;RETURN VALUE:
;       THE VALUE OF THE SELECTED PROPERTY.





    ; Error handling.
    catch, theError
    if theError ne 0 then begin
        catch, /Cancel
        ;090904
        ;print,(Tag_Names(extraKeyword))[0]
        if self.dummy eq 0 then begin
;            ok = dialog_message('before message')
;            ok = dialog_message(!Error_State.MSG)
;            ok = dialog_message("after message")

            voidclass = obj_class(self)
            void = dialog_message('YOU APPEAR TO HAVE CHANGED THE CLASS DEFINITION FOR CLASS '+voidclass,/error)
            void = dialog_message('CHECK THIS NOW!!!!!! - SINCE FURTHER PROBLEMS WITH '+voidclass+' WILL BE IGNORED!!!!!!!!!',/error)

        endif
        ;SET dummy FLAG TO AVOID MULTIPLE INSTANCES OF SAME MESSAGE
        self.dummy = 1


        return, 0;''
    endif



    ; Only one property at a time can be returned.
    if n_elements(extraKeyword) eq 0 then begin
        void = dialog_message('Must indicate which property to return.')
    endif

    if n_tags(extraKeyword) gt 1 then begin
        void = dialog_message('Only one property at a time can be returned.')
    endif


    ; Pull keyword out of extra structure. It will be in
    ;UPPERCASE characters.
    keyword = strupcase((Tag_Names(extraKeyword))[0])

    ; Obtain a structure definition of the object class.
    call_procedure , obj_class(self)+'__define', struct

;020405
;UPDATING THIS TO RETURN JUST ONE UNIQUE MATCH.
;    ;GET INDICES AND NUMBER OF MATCHES
;    index = where(strpos(tag_names(struct), keyword) eq 0, count)
    index = where(strcmp(strupcase(tag_names(struct)),keyword))
    if index[0] ne -1 then begin
        count = n_elements(index)
    endif else begin
        count = 0
    endelse



    index = index[0]

    ;FREE ANY POINTERS CREATED FOR STRUCT
    for n=0,n_elements(tag_names(struct))-1 do begin
        ;THE NEXT help/if STATEMENT PREVENTS EXCEPTION ON ARRAYS.
        help,struct.(n),output=out
        if not stregex(out,'array',/fold_case,/boolean) then begin
            if (ptr_valid(struct.(n)) gt 0) then begin
                ptr_free,struct.(n)
            endif
        endif
    endfor


    if (count gt 1) then Message,$
        "Ambiguous keyword. Use more characters in its specification."
    if (count eq 0) then Message, 'Keyword not found.'



    ;RETURN SELECTED TAG
    return, self.(index)

end;getProperty


pro myProperties::setProperty, _Extra=extraProperties
;
;NAME:
;           myProperties::setProperty
;
;PURPOSE:
;           Generic setProperty method.
;PARAMETERS:
;           none
;KEYWORDS:
;           none
;_EXTRA -   is used to pass keywords to set along with
;           value to set them to.

    catch, theError
    if theError ne 0 then begin
        catch, /Cancel
        ;print,'IS THIS IT?'
        ;print,(Tag_Names(extraProperties))[0]
        ok = dialog_message(!Error_State.MSG)
        return
    endif

    if (n_elements(extraProperties) eq 0) then Message,$
     'Must indicate which property to set.'
    properties = tag_names(extraProperties)

    ; Obtain a structure definition of the object class.
    call_procedure , obj_class(self)+'__define', struct  ;MAKE CALL TO
                                                         ;DEFINE TO CREATE
                                                         ;STRUCTURE

    ;FREE ANY POINTERS CREATED FOR STRUCT
    for n=0,n_elements(tag_names(struct))-1 do begin
        ;THE NEXT help/if STATEMENT PREVENTS EXCEPTION ON ARRAYS.
        help,struct.(n),output=out
        if not stregex(out,'array',/fold_case,/boolean) then begin
            if (ptr_valid(struct.(n)) gt 0) then begin
                ptr_free,struct.(n)
            endif
        endif
    endfor


    ; Loop through the various properties and their values.
    for j=0L,n_tags(extraProperties)-1 DO BEGIN

        theProperty = properties[j]

        ;020405
        ;UPDATING THIS TO RETURN JUST ONE UNIQUE MATCH PER PASS.
;        index = where(strpos(tag_names(struct), theProperty ) eq 0, count)
        index = where(strcmp(strupcase(tag_names(struct)),theProperty))
        if index[0] ne -1 then begin
            count = n_elements(index)
        endif else begin
            count = 0
        endelse
        index = index[0]



        if (count gt 1) then Message, "Ambiguous keyword: " +$
                                    theProperty +$
                                    ". Use more characters in it's specification."
        if (count eq 0) then Message, 'Keyword not found.'
        help,struct.(index),output=out


        if not stregex(out,'array',/fold_case,/boolean) then begin
            if (ptr_valid(self.(index)) gt 0) then begin
                ;print,'SETTING POINTER VALUE'
                ;ptr_free,struct.(index);free any pointers in struct
                ptr_free,self.(index)
                self.(index) = ptr_new(extraProperties.(j))
            endif else begin

                ;print,'SETTING VARIABLE VALUE'
                self.(index) = extraProperties.(j)

            endelse

            ;print,self.(index)
        endif else begin

            self.(index) = extraProperties.(j)
        endelse
    endfor
end;setProperty


function myproperties::init
;
;NAME:
;        myproperties::init
;
;PURPOSE:
;           init method for this superclass.
;PARAMETERS:
;           none
;KEYWORDS:
;           none
;RETURN VALUE:
;           1 for success.
    self.dummy = 0
    return,1
end

pro myproperties__define,class
;
;NAME:
;        myproperties__define
;
;PURPOSE:
;       Generic class definition to provide dummy data.
;PARAMETERS:
;       none.
;KEYWORDS:
;       none.

    class = {myproperties,dummy:0}
end
