; docformat = 'rst'
;
; NAME:
;   cgContainer
;
; PURPOSE:
;   A modified IDL container with properties needed for Coyote Graphics routines.
;
;******************************************************************************************;
;                                                                                          ;
;  Copyright (c) 2011, by Fanning Software Consulting, Inc. All rights reserved.           ;
;                                                                                          ;
;  Redistribution and use in source and binary forms, with or without                      ;
;  modification, are permitted provided that the following conditions are met:             ;
;                                                                                          ;
;      * Redistributions of source code must retain the above copyright                    ;
;        notice, this list of conditions and the following disclaimer.                     ;
;      * Redistributions in binary form must reproduce the above copyright                 ;
;        notice, this list of conditions and the following disclaimer in the               ;
;        documentation and/or other materials provided with the distribution.              ;
;      * Neither the name of Fanning Software Consulting, Inc. nor the names of its        ;
;        contributors may be used to endorse or promote products derived from this         ;
;        software without specific prior written permission.                               ;
;                                                                                          ;
;  THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY        ;
;  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES    ;
;  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT     ;
;  SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,             ;
;  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED    ;
;  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         ;
;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND             ;
;  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT              ;
;  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS           ;
;  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                            ;
;******************************************************************************************;
;
;+--------------------------------------------------------------------------
;   A modified IDL container with properties needed for Coyote Graphics routines.
;
; :Categories:
;    Obejct Programming, Utility
;    
; :Author:
;       FANNING SOFTWARE CONSULTING::
;        David W. Fanning 
;        1645 Sheely Drive
;        Fort Collins, CO 80526 USA
;        Phone: 970-221-0438
;        E-mail: david@idlcoyote.com
;        Coyote's Guide to IDL Programming: http://www.idlcoyote.com
;
; :History:
;     Change History::
;        Written, by David W. Fanning, 7 November 2011.
;        Modified the SetProperty and GetProperty method to indicate errors if
;           extra keywords reach them. 3 Nov 2012. DWF.
;        
; :Copyright:
;     Copyright (c) 2011, Fanning Software Consulting, Inc.
;---------------------------------------------------------------------------
;
;+--------------------------------------------------------------------------
;   The object initialization method.
;    
; :Keywords:
;      name: in, optional, type=string, default=selected by cgContainer.
;         Use this keyword to name the object. Names are often used to select objects in 
;         program code. 
;      uvalue: in, optional, type=any, default=none
;         A storage space for storing any kind of IDL variable of importance to the user.
;
;---------------------------------------------------------------------------
FUNCTION cgContainer::INIT, $
   NAME=name, $
   UVALUE=uvalue
   
   Compile_Opt idl2
   
   Catch, theError
   IF theError NE 0 THEN BEGIN
      Catch, /CANCEL
      void = cgErrorMsg()
      RETURN, 0
   ENDIF
   
   ; Initialize superclass object.
   IF ~self -> IDL_Container::INIT() THEN RETURN, 0
   
   ; Every object should have a name. If we don't have one
   ; create it from the objects reference number.
   IF N_Elements(name) NE 0 THEN BEGIN
      self._cg_name = name 
   ENDIF ELSE BEGIN
      Help, self, Output=helpString
      parts = StrSplit(helpString, '<(', /Extract)
      objNo = StrMid(parts[1], 10)
      self._cg_name = Obj_Class(self) + '_' + objNo
   ENDELSE
   
   ; Have something to store in the user value?
   IF N_Elements(uvalue) NE 0 THEN self._cg_uvalue = Ptr_New(uvalue)
   
   ; Initialize the trash container.
   self._cg_trash = Obj_New('IDL_Container')

   RETURN, 1
   
END

   
;+--------------------------------------------------------------------------
;   Adds an object to the trash container. Any object add to the trash will
;   be destroyed when this object is destroyed.
;
; :Params:
;    object: in, required, type=object, default=none
;      The object to be added to the trash container.
;---------------------------------------------------------------------------
PRO cgContainer::AddToTrash, object

   FOR j=0,N_Elements(object)-1 DO BEGIN
      IF Obj_Valid(object[j]) THEN self._cg_trash -> Add, object[j]
   ENDFOR

END 

;+--------------------------------------------------------------------------
;   This method returns the positions (indices) of named objects in 
;   the container.
;
; :Params:
;    searchName: in, required, type=string, default=none
;      The name of the object that you wish to locate in the container.
;      
; :Keywords:
;     case_sensitive: in, optional, type=boolean, default=0
;        Set this keyword to 1 to indicate a case sensitive search. By default, the
;        search is case insensitive.
;     count: out, optional, type=integer
;         On exit, this variable will contain the number of positions returned that
;         meet the search criteria.
;     regexp: in, optional, type=boolean, default=0
;         Set this keyword to indicate that searchName is a regular expression.
;     _EXTRA: in, optional
;         Any keywords supported by STREGEX can also be used. Requires REGEXP to be set. 
;---------------------------------------------------------------------------
FUNCTION cgContainer::FindByName, searchName, $
   Case_Sensitive=case_sensitive, $
   Count=count, $
   RegExp=regexp, $
   _Extra=extra
   
   Compile_Opt idl2

   ; Return to caller on error.
   ON_ERROR, 2
   
   ; Assume there are no matches.
   count = 0

   ; Search name must be a scalar.
   IF N_Elements(searchName) NE 1 THEN Message,'Search expression must be a scalar string.'

   ; Get the names of all the child objects, if they have names.
   children = self -> IDL_CONTAINER::Get(/All, Count=numChildren)
   IF numChildren EQ 0 THEN RETURN, -1

   names = StrArr(numChildren)
   FOR childNumber = 0, numChildren-1 DO $
   BEGIN
      thisChild = children[childNumber]
      IF Obj_HasMethod(thischild, 'GetName') THEN BEGIN
        childName = thisChild -> GetName()
        names[childNumber] = childName
      ENDIF ELSE names[childNumber] = ""
   ENDFOR

   ; Does the user want to evaluate a regular expression?
   ; If not, do a simple search for the search name.
   fold_case = Keyword_Set(case_sensitive) EQ 0
   IF Keyword_Set(regexp) THEN BEGIN
      mask = StRegEx(names, searchName, FOLD_CASE=fold_case, /BOOLEAN, _Extra=extra) 
   ENDIF ELSE mask = StrMatch(names, searchName, FOLD_CASE=fold_case)

   ; Transform boolean array to index array. A side effect is that
   ; the count value will be set.
   positions = Where(mask, count)

   RETURN, positions

END

   
;+--------------------------------------------------------------------------
;   Returns the name of the object.
;---------------------------------------------------------------------------
FUNCTION cgContainer::GetName
   RETURN, self._cg_name
END

   
;+--------------------------------------------------------------------------
;   This method allows the user to get various properties of the object. In general,
;   the same keywords that are used for the INIT method can be used here. Superclass
;   values can also be obtained.
;   
; :Keywords:
;      count: out, optional, type=integer
;         Use the keyword to return the number of objects in the container.
;      name: out, optional, type=string
;         Use this keyword to name the object. Names are often used to select objects in 
;         program code. 
;      uvalue: out, optional, type=any
;         Returns the user value, if any.
;      _ref_extra: out, optional
;         Returns the value of any keyword in the superclass object.
;---------------------------------------------------------------------------
PRO cgContainer::GetProperty, NAME=name, COUNT=count, UVALUE=uvalue, _REF_EXTRA=extra

   Compile_Opt idl2
    
   Catch, theError
   IF theError NE 0 THEN BEGIN
      Catch, /CANCEL
      void = cgErrorMsg()
      IF N_Elements(extra) NE 0 THEN Print, '      ' + 'Unhandled keywords: ' + extra
      RETURN
   ENDIF
   
    ; Get this object properties.
    IF Arg_Present(count) THEN count  = self -> IDL_Container::Count()
    IF Arg_Present(name) THEN name = self._cg_name
    IF Arg_Present(uvalue) && Ptr_Valid(self._cg_uvalue) THEN uvalue = *self._cg_uvalue
    
    ; If you get to here with a keyword, it is an error.
    IF N_Elements(extra) NE 0 THEN Message, 'There are unresolved keywords that should not be here.'
    
END

   
;+--------------------------------------------------------------------------
;   This method allows the user to set various properties of the object. In general,
;   the same keywords that are used for the INIT method can be used here. Superclass
;   values can also be set.
;   
; :Keywords:
;      name: in, optional, type=string, default=selected by cgContainer.
;         Use this keyword to name the object. Names are often used to select objects in 
;         program code. 
;      uvalue: in, optional, type=any, default=none
;         A storage space for storing any kind of IDL variable of importance to the user.
;      _ref_extra: in, optional
;         Any superclass keyword can be set here.
;---------------------------------------------------------------------------
PRO cgContainer::SetProperty, NAME=name, UVALUE=uvalue, _REF_EXTRA=extra

   Compile_Opt idl2
    
   Catch, theError
   IF theError NE 0 THEN BEGIN
      Catch, /CANCEL
      void = cgErrorMsg()
      RETURN
   ENDIF
   
   ; Set this object properties.
   IF N_Elements(name) NE 0 THEN self._cg_name = name
   IF N_Elements(uvalue) NE 0 THEN BEGIN
      IF Ptr_Valid(self._cg_uvalue) THEN *self._cg_uvalue = uvalue $
          ELSE self._cg_uvalue = Ptr_New(uvalue)
   ENDIF
   
    ; If you get to here with a keyword, it is an error.
    IF N_Elements(extra) NE 0 THEN Message, 'There are unresolved keywords that should not be here.'

END

   
;+--------------------------------------------------------------------------
;   This is the clean-up routine for the object.
;
;---------------------------------------------------------------------------
PRO cgContainer::CLEANUP

    Ptr_Free, self._cg_uvalue
    Obj_Destroy, self._cg_trash
    self -> IDL_Container::CleanUp

END

   
;+--------------------------------------------------------------------------
;   This is the class definition module. Structures used to manipulate
;   map projection and map datum information are also created here.
;
; :Params:
;    class: out, optional, type=structure
;       Occasionally, it is useful to have an object class definition as
;       a structure variable. Using this output keyword will allow that.
;---------------------------------------------------------------------------
PRO cgContainer__Define, class

   class = { CGCONTAINER, $
             _cg_name: "",          $ ; A name for the container.
             _cg_trash: Obj_New(),  $ ; A trash container for destroying other objects.
             _cg_uvalue: Ptr_New(), $ ; A user value placeholder for the object.
             INHERITS IDL_OBJECT,   $ ; An IDL object for overloading "dot" operator, etc. in IDL 8.x.
             INHERITS IDL_CONTAINER $ ; An IDL container.
            }
            
END