SET PROCEDURE TO wwDynamic ADDITIVE
DO wwCollections

*************************************************************
DEFINE CLASS wwDynamic AS RELATION
*************************************************************
*: original Author: Marco Plaza, 2018 @vfp2nfox
*:     modified by: Rick Strahl
*************************************************************

HIDDEN __Collection
__Collection = NULL
__Reference = NULL
__PropertyNameOverrides = ""

HIDDEN Tag, Parent, ClassLibrary, Name, AddProperty, BaseClass, ChildAlias, ChildOrder, ;
       Comment, ParentClass, ParentAlias, OneToMany, WriteExpression, WriteMethod, SaveAsClass,;
       RelationalExpr, ReadMethod, ReadExpression


************************************************************************
*  THIS_Access
****************************************
***  Function: Handles type forwarding to the __Reference instance
***    Assume: Watch out for FoxPro Reserved Property Names
***            - Name, Class, Tag, ClassLibrary, etc.
***            - Use .AddProp() to add
***      Pass: 
***    Return:
************************************************************************
*** Intercept access to unknown properties and create
FUNCTION THIS_Access(lcProperty)
LOCAL lvItem

llSpecial = INLIST(lcProperty,"name","tag","classlibrary","parent","baseclass","parentclass","comment","__collection","__reference","__propertynameoverrides")
IF (llSpecial)
   RETURN THIS
ENDIF
   
llNative = PEMSTATUS(this,lcProperty,5)

*** Make sure we can assign to __reference before it's set
IF llNative
   RETURN THIS
ENDIF   

lvItem = this.__Collection.Find(lcProperty)
IF !ISNULL(lvItem)
    RETURN THIS.__Reference
ENDIF	

AddProperty(this.__Reference,lcProperty,CREATEOBJECT('wwDynamic'))
this.__Collection.Add(lcProperty)

RETURN THIS.__Reference
ENDFUNC


************************************************************************
*  Init
****************************************
***  Function:
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION Init(loBaseType)
LOCAL lnX, lnMembers
LOCAL ARRAY laMembers[1]

THIS.__Collection = CREATEOBJECT("wwCollection")

IF VARTYPE(loBaseType) # "O"
   this.__Reference = CREATEOBJECT("EMPTY")
ELSE 
   this.__Reference = loBaseType
   
   *** Add existing members
   lnMembers = AMEMBERS(laMembers, loBaseType)
   FOR lnX = 1 TO lnMembers
      lcProperty = laMembers[lnX]
      ADDPROPERTY(this.__Reference,lcProperty, EVALUATE("THIS.__Reference." + lcProperty))   
   ENDFOR   
ENDIF   

ENDFUNC
*   Init

************************************************************************
*  AddProperty
****************************************
***  Function: Adds a property to the type
***      Pass: lcProperty - Name of hte property
***            lvValue    - Value to add
***    Return:
************************************************************************
FUNCTION AddProp(lcProperty, lvValue)
IF PCOUNT() < 2
   lvValue = CREATEOBJECT("wwDynamic")
ENDIF   
ADDPROPERTY(this.__Reference,lcProperty,lvValue)
THIS.__Collection.Add(LOWER(lcProperty))

*** Add property if it's not all lower case
IF(!(lcProperty == LOWER(lcProperty)))
	this.__PropertyNameOverrides = this.__PropertyNameOverrides + lcProperty + ","
ENDIF

ENDFUNC
*   AddProperty


************************************************************************
*  GetProp
****************************************
***  Function: 
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION GetProp(lcProperty)
RETURN EVALUATE("THIS.__Reference." + lcProperty)
ENDFUNC
*   GetProp

************************************************************************
*  GetClassProp
****************************************
***  Function: Special method to return a property named 'Class'
***            Class is special because it has to be returned for
***            FoxPro internal purposes and serialization so it cannot
***            be accessed by `loObj.Class` but instead should use
***            `loObj.GetClassProp()`
***    Assume:
***      Pass:
***    Return:
************************************************************************
FUNCTION GetClassProp()
RETURN THIS.__Reference.Class
ENDFUNC
*   GetClassProp

ENDDEFINE

*!*	*************************************************************
*!*	DEFINE CLASS wwDynamic AS RELATION
*!*	*************************************************************
*!*	*: original Author: Marco Plaza, 2018 @vfp2nfox
*!*	*:     modified by: Rick Strahl
*!*	*************************************************************

*!*	__Reference = null
*!*	__PropertyNameOverrides = ""

*!*	*** Intercept access to unknown properties and create
*!*	FUNCTION THIS_Access(lcProperty)
*!*	LOCAL llNativeProp, llAddProp



*!*	*** Make sure we can assign to __reference before it's set
*!*	IF (lcProperty == "__reference")
*!*	   RETURN THIS
*!*	ENDIF   

*!*	*** Prefer returning 'dynamic values over native ones'
*!*	*** so we can override FoxPro reserved properties: name, class, classlibrary,baseclass etc.
*!*	llNativeProp = Pemstatus(this,lcProperty,5)
*!*	llAddProp = Pemstatus(this.__Reference,lcProperty,5)  


*!*	If !llNativeProp AND !llAddProp
*!*	   AddProperty(this.__Reference,lcProperty,CREATEOBJECT('wwDynamic'))
*!*	ENDIF

*!*	IF !llNativeProp
*!*	   RETURN this.__Reference
*!*	ENDIF	
*!*		
*!*	RETURN this
*!*		

*!*	ENDFUNC



*!*	************************************************************************
*!*	*  Init
*!*	****************************************
*!*	***  Function:
*!*	***    Assume:
*!*	***      Pass:
*!*	***    Return:
*!*	************************************************************************
*!*	FUNCTION Init(loBaseType)

*!*	IF !VARTYPE(loBaseType) = "O"
*!*	   this.__Reference = CREATEOBJECT("Empty")
*!*	ELSE 
*!*	   this.__Reference = loBaseType
*!*	ENDIF   

*!*	ENDFUNC
*!*	*   Init



*!*	************************************************************************
*!*	*  AddProperty
*!*	****************************************
*!*	***  Function: Adds a property to the type
*!*	***    Assume:
*!*	***      Pass: lcProperty - Name of hte property
*!*	***            lvValue    - Value to add
*!*	***    Return:
*!*	************************************************************************
*!*	FUNCTION AddProperty(lcProperty, lvValue)
*!*	IF PCOUNT() < 2
*!*	   lvValue = CREATEOBJECT("wwDynamic")
*!*	ENDIF   
*!*	ADDPROPERTY(this.__Reference,lcProperty,lvValue)
*!*	this.__PropertyNameOverrides = this.__PropertyNameOverrides + lcProperty + ","
*!*	ENDFUNC
*!*	*   AddProperty

*!*	ENDDEFINE
*!*	*EOC wwDynamic 

