#####################################################################
#####################################################################
## Copyright 2005 Steven R. Newcomb                                ##
##                                                                 ##
## This software is licensed under the Apache License, Version 2.0 ##
## (the "License"); you may not use this file except in compliance ##
## with the License.  Copies of the License are available at       ##
##        http://www.apache.org/licenses/LICENSE-2.0               ##
##                                                                 ##
## Unless required by applicable law or agreed to in writing,      ##
## software distributed under the License is distributed on an "AS ##
## IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either ##
## express or implied.  See the License for the specific language  ##
## governing permissions and limitations under the License.        ##
##                                                                 ##
## Copies of the source code and the license are available at      ##
##        http://www.versavant.org                                 ##
#####################################################################
#####################################################################


#####################################################################
## Implementation of the conferral rule
## "infer_U_assert_properties_from_U_assert_properties"
## in Topic Map Application "U_assert".
#####################################################################

####################################
cvsRevision = "$Revision: 1.2 $" ##
####################################

import re, copy

propNameParseREString = '(^x_)([RL]r[np])([RL]r[np])([RL]r[np]$)'
propNameParseRE = re.compile( propNameParseREString)


## globals
localRoleName = None     ## name of role played by subject of local proxy
localRolePlayerProxyId = None   ## proxyId of local proxy
remoteRoleName = None    ## name of role played by subject of remote proxy
remoteRolePlayerProxyId = None  ## proxyId of remote proxy
currentProxyId2NewProxyMap = {}  ## map of proxies that are good to add
                                 ## properties to within the same ProcOp
levelDict = {                    ## level at which roleplayer's proxyId appears
    'x_LrnRrnRrp': 'third',
    'x_LrnRrpRrn': 'second',
    'x_RrnRrpLrn': 'second',
    'x_RrnLrnRrp': 'third',
    'x_RrpLrnRrn': 'first',
    'x_RrpRrnLrn': 'first'
}




def infer_U_assert_properties_from_U_assert_properties( vsv, conferralRule, **args):

    global localRoleName, localRolePlayerProxyId, remoteRoleName, remoteRolePlayerProxyId, currentProxyId2NewProxyMap


    topicMap = conferralRule.topicMap  ## make the below code less verbose (and maybe run slightly faster)
    TMA = conferralRule.TMA  ## this is the TMA that defines this conferral rule

    U_assert_propertyClassNameList = [ 'x_LrnRrnRrp',
                                  'x_LrnRrpRrn',
                                  'x_RrnRrpLrn',
                                  'x_RrnLrnRrp',
                                  'x_RrpLrnRrn',
                                  'x_RrpRrnLrn']

    for currentTriggeringPropertyClassName in U_assert_propertyClassNameList:
        matchObj = propNameParseRE.match( currentTriggeringPropertyClassName)
        dict1Code = matchObj.group(2)       ## 'Lrn', 'Rrn', or 'Rrp'
        dict2Code = matchObj.group(3)       ## 'Lrn', 'Rrn', or 'Rrp'
        stringListCode = matchObj.group(4)  ## 'Lrn', 'Rrn', or 'Rrp'


        currentPropertyInProxyKey = vsv.catKey( TMA.TMAName, currentTriggeringPropertyClassName)

        currentProxyIdList = TMA.propertyClasses[ currentTriggeringPropertyClassName].overheadDict[ 'proxyIds'].keys()
        for currentProxyId in currentProxyIdList:
            currentProxy = topicMap.proxies[ currentProxyId]
            currentTriggeringPropertyInstance = currentProxy.propertyInstances[ currentPropertyInProxyKey]
            
            ## Don't be triggered by any propertyInstance that was
            ## output by an operation of this rule, and don't be
            ## triggered by a propertyInstance more than once.
            conferralRuleTriggerRoleId = vsv.catKey( conferralRule.conferralRuleKey, 'A')
            if currentTriggeringPropertyInstance.conferralTriggerAncestry.has_key( conferralRuleTriggerRoleId) or \
                currentTriggeringPropertyInstance.conferralsTriggered.has_key( conferralRuleTriggerRoleId):
                continue

            triggers = {}  ## new dictionary to work in
            triggers[ 'A'] = currentTriggeringPropertyInstance.propertyInstanceKey
            conferredValueSources = {}  ## new dictionary to work in
            conferredValueSources[ 'A'] = currentTriggeringPropertyInstance.propertyInstanceKey

            if not vsv.conferralMayBeSignificant( conferralRule, triggers, conferredValueSources):
                continue

            currentProxyId2NewProxyMap.clear()

            xLocalRolePlayerProxyId = currentTriggeringPropertyInstance.proxyId
            dict1 = currentTriggeringPropertyInstance._value
            for dict1Key in dict1:
                dict2 = dict1[ dict1Key]
                if dict1Code == 'Lrn':
                    xLocalRoleName = dict1Key
                elif dict1Code == 'Rrn':
                    xRemoteRoleName = dict1Key
                else: ## dict1Code == 'Rrp':
                    xRemoteRolePlayerProxyId = dict1Key
                for dict2Key in dict2:
                    stringList = dict2[ dict2Key]
                    if dict2Code == 'Lrn':
                        xLocalRoleName = dict2Key
                    elif dict2Code == 'Rrn':
                        xRemoteRoleName = dict2Key
                    else: ## dict2Code == 'Rrp':
                        xRemoteRolePlayerProxyId = dict2Key
                    for string in stringList:
                        if stringListCode == 'Lrn':
                            xLocalRoleName = string
                        elif stringListCode == 'Rrn':
                            xRemoteRoleName = string
                        else: ## stringListCode == 'Rrp':
                            xRemoteRolePlayerProxyId = string

                        ## Now, the question is: does this proxy have
                        ## the other properties that it needs to have,
                        ## and do those other properties have the
                        ## values they need to have, in order to
                        ## correspond to this one's value(s)?

                        ## confer on a proxy for the local
                        ## role-playing subject, if necessary.
                        ## set globals:
                        localRoleName    = xLocalRoleName
                        localRolePlayerProxyId  = xLocalRolePlayerProxyId
                        remoteRoleName   = xRemoteRoleName
                        remoteRolePlayerProxyId = xRemoteRolePlayerProxyId
                        conferUAssertPropertiesInProxy( vsv, triggers, conferredValueSources, topicMap, TMA)

                        ## confer on a proxy for the remote
                        ## role-playing subject, if necessary (reverse
                        ## local and remote).
                        ## set globals:
                        localRoleName    = xRemoteRoleName
                        localRolePlayerProxyId  = xRemoteRolePlayerProxyId
                        remoteRoleName   = xLocalRoleName
                        remoteRolePlayerProxyId = xLocalRolePlayerProxyId
                        conferUAssertPropertiesInProxy( vsv, triggers, conferredValueSources, topicMap, TMA)


#######################################################
def conferUAssertPropertiesInProxy( vsv, triggers, conferredValueSources, topicMap, TMA):
    
    global localRoleName, localRolePlayerProxyId, remoteRoleName, remoteRolePlayerProxyId, currentProxyId2NewProxyMap

    uaExistingPropDict = {
        'x_LrnRrnRrp': None,
        'x_LrnRrpRrn': None,
        'x_RrnRrpLrn': None,
        'x_RrnLrnRrp': None,
        'x_RrpLrnRrn': None,
        'x_RrpRrnLrn': None
    }
    localProxy = topicMap.proxies[ localRolePlayerProxyId]
    for xPropertyInstanceKey in localProxy.propertyInstances:
        xPropertyInstance = localProxy.propertyInstances[ xPropertyInstanceKey]
        xPropertyClassName = xPropertyInstance.propertyClass.propertyClassName
        if xPropertyClassName in uaExistingPropDict:
            uaExistingPropDict[ xPropertyClassName] = xPropertyInstance

    uaPotentialNewPropDict = {
        'x_LrnRrnRrp': [ localRoleName, remoteRoleName, remoteRolePlayerProxyId],
        'x_LrnRrpRrn': [ localRoleName, remoteRolePlayerProxyId, remoteRoleName],
        'x_RrnRrpLrn': [ remoteRoleName, remoteRolePlayerProxyId, localRoleName],
        'x_RrnLrnRrp': [ remoteRoleName, localRoleName, remoteRolePlayerProxyId],
        'x_RrpLrnRrn': [ remoteRolePlayerProxyId, localRoleName, remoteRoleName],
        'x_RrpRrnLrn': [ remoteRolePlayerProxyId, remoteRoleName, localRoleName]
    }

    for uaPropName in uaExistingPropDict:
        

        uaPropertyInstance = uaExistingPropDict[ uaPropName]
        if not uaPropertyInstance:
            setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)

        else:
            uaPropVal = uaPropertyInstance._value                        
            if uaPropName == 'x_LrnRrnRrp':
                if localRoleName not in uaPropVal:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRoleName not in uaPropVal[ localRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRolePlayerProxyId not in uaPropVal[ localRoleName][ remoteRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)

            elif uaPropName == 'x_LrnRrpRrn':
                if localRoleName not in uaPropVal:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRolePlayerProxyId not in uaPropVal[ localRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRoleName not in uaPropVal[ localRoleName][ remoteRolePlayerProxyId]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)

            elif uaPropName == 'x_RrnRrpLrn':
                if remoteRoleName not in uaPropVal:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRolePlayerProxyId not in uaPropVal[ remoteRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif localRoleName not in uaPropVal[ remoteRoleName][ remoteRolePlayerProxyId]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)

            elif uaPropName == 'x_RrnLrnRrp':
                if remoteRoleName not in uaPropVal:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif localRoleName not in uaPropVal[ remoteRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRolePlayerProxyId not in uaPropVal[ remoteRoleName][ localRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)

            elif uaPropName == 'x_RrpLrnRrn':
                if remoteRolePlayerProxyId not in uaPropVal:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif localRoleName not in uaPropVal[ remoteRolePlayerProxyId]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRoleName not in uaPropVal[ remoteRolePlayerProxyId][ localRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)

            else: ## uaPropName == 'x_RrpRrnLrn'
                if remoteRolePlayerProxyId not in uaPropVal:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif remoteRoleName not in uaPropVal[ remoteRolePlayerProxyId]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)
                elif localRoleName not in uaPropVal[ remoteRolePlayerProxyId][ remoteRoleName]:
                    setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict)


#######################################################
def setOrTweakUAssertProperty( vsv, topicMap, TMA, uaPropName, triggers, conferredValueSources, uaPotentialNewPropDict):
    
    global localRoleName, localRolePlayerProxyId, remoteRoleName, remoteRolePlayerProxyId, currentProxyId2NewProxyMap, levelDict

    dict1Key, dict2Key, string = uaPotentialNewPropDict[ uaPropName]

    nowLivingLocalRolePlayerProxy = vsv.liveProxy(  vsv.isProxyId( localRolePlayerProxyId))

    if nowLivingLocalRolePlayerProxy.proxyId in currentProxyId2NewProxyMap:
        newProxy = currentProxyId2NewProxyMap[ nowLivingLocalRolePlayerProxy.proxyId]
    else:
        newProxy = currentProxyId2NewProxyMap[ nowLivingLocalRolePlayerProxy.proxyId] = vsv.newProxyObject( topicMap)
        nowLivingLocalRolePlayerProxySIP = vsv.SIPOfProxy( nowLivingLocalRolePlayerProxy)
        vsv.newPropertyInstance( newProxy,
                                 nowLivingLocalRolePlayerProxySIP.TMAName,
                                 nowLivingLocalRolePlayerProxySIP.propertyClass.propertyClassName,
                                 vsv.versaCopy( nowLivingLocalRolePlayerProxySIP._value),  ## must copy! can't refer!
                                 triggers,
                                 conferredValueSources)
    uaPropertyInProxyKey = vsv.catKey( TMA.TMAName, uaPropName)
    if uaPropertyInProxyKey in newProxy.propertyInstances:
        uaPropertyInstance = newProxy.propertyInstances[ uaPropertyInProxyKey]
        propertyClass = uaPropertyInstance.propertyClass
                ## Remove old value from the "overhead" data for this property class
        if propertyClass.Remove__PropFromOverheadDictFArgString:
            execStr = 'propertyClass.Remove__PropFromOverheadDictF( vsv, uaPropertyInstance, propertyClass.overheadDict, %s)' % (
                propertyClass.Remove__PropFromOverheadDictFArgString)
            exec execStr
        else:
            propertyClass.Remove__PropFromOverheadDictF( vsv, uaPropertyInstance, propertyClass.overheadDict)

            ## add the new stuff to the value
        dict1 = uaPropertyInstance._value
        if dict1Key not in dict1:
            dict1[ dict1Key] = { dict2Key: [ string]}
        else:
            dict2 = dict1[ dict1Key]
            if dict2Key not in dict2:
                dict2[ dict2Key] = [ string]
            else:
                stringList = dict2[ dict2Key]
                if string not in stringList:
                    stringList.append( string)

            ## Expose the list of proxy references that appear in the value as a list of proxyIds in the value of uaPropertyInstance.listOfIdsOfReferencedProxies
        workDict = {}
        levelAtWhichProxyReferenceAppears = levelDict[ uaPropName]
        for dict1Key in dict1:
            if levelAtWhichProxyReferenceAppears == 'first':
                workDict[ dict1Key] = None
                continue
            dict2 = dict1[ dict1Key]
            for dict2Key in dict2:
                if levelAtWhichProxyReferenceAppears == 'second':
                    workDict[ dict2Key] = None
                    continue
                stringList = dict2[ dict2Key]
                for string in stringList:
                    workDict[ string] = None  ## levelAtWhichProxyReferenceAppears == 'third'
        uaPropertyInstance.listOfIdsOfReferencedProxies = workDict.keys()
            
                ## Add new value to the "overhead" data for this property class  (This will set uaPropertyInstance.hashableValue, too!)
        if propertyClass.Add__PropToOverheadDictFArgString:
            execStr = 'propertyClass.Add__PropToOverheadDictF( vsv, uaPropertyInstance, propertyClass.overheadDict, %s)' % (
                propertyClass.Add__PropToOverheadDictFArgString)
            exec execStr
        else:
            propertyClass.Add__PropToOverheadDictF( vsv, uaPropertyInstance, propertyClass.overheadDict)


    else:  ## uaProperty not already present in newProxy
        vsv.newPropertyInstance( newProxy,
                                 TMA,
                                 uaPropName,
                                 { dict1Key: { dict2Key: [ string]}},
                                 triggers,
                                 conferredValueSources)




def bridgeFrom_a_sip_modelTo_U_assert( vsv, conferralRule, **args):
    ## from bridgeFromTMAName,,x_LrnRrnRrp properties, infer a_sip
    ## properties in the conferralRule's TMA.  (With all that that
    ## entails.)

    bridgeFromTMAName = args[ 'bridgeFromTMAName']
    a_sipPropertyInstanceInProxyKey = vsv.catKey( bridgeFromTMAName, 'a_sip')
    assertionModel = args[ 'assertionModel']

    rolesTMAName = args[ 'rolesTMAName']
    roleNamePropertyClassName = args[ 'roleNamePropertyClassName']
    roleNamePropertyInstanceInProxyKey = vsv.catKey( rolesTMAName, roleNamePropertyClassName)

    topicMap = conferralRule.topicMap
    TMA = conferralRule.TMA  ## this is the TMA that defines this conferral rule
    rolesTMA = topicMap.TMAs[ rolesTMAName]

    existingRoleDict = rolesTMA.propertyClasses[ 'role name'].overheadDict

    bridgeFromTMA = topicMap.TMAs[ bridgeFromTMAName]
    hashableValueDict = bridgeFromTMA.propertyClasses[ 'a_sip'].overheadDict
    hashableValueList = hashableValueDict.keys()

    for hashableValue in hashableValueList:
        proxyIdList = hashableValueDict[ hashableValue]
        for proxyId in proxyIdList:
            proxy = topicMap.proxies[ proxyId]
            a_sipProperty = proxy.propertyInstances[ a_sipPropertyInstanceInProxyKey]

            ## Don't be triggered by a u_assert property more than once
            conferralRuleTriggerRoleId = vsv.catKey( conferralRule.conferralRuleKey, 'A')
            if a_sipProperty.conferralTriggerAncestry.has_key( conferralRuleTriggerRoleId) or \
                   a_sipProperty.conferralsTriggered.has_key( conferralRuleTriggerRoleId):
                continue

            triggers = {}  ## new dictionary to work in
            triggers[ 'A'] = a_sipProperty.propertyInstanceKey
            conferredValueSources = {}  ## new dictionary to work in
            conferredValueSources[ 'A'] = a_sipProperty.propertyInstanceKey

            if vsv.conferralMayBeSignificant( conferralRule, triggers, conferredValueSources):

                a_sipValue = a_sipProperty._value
                for outerLoopCounter in range( 0, len( a_sipValue) - 1):
                    for innerLoopCounter in range( outerLoopCounter + 1, len( a_sipValue)):
                        thisOne = a_sipValue[ outerLoopCounter]
                        thatOne = a_sipValue[ innerLoopCounter]
                        if assertionModel == 'BigAssert' or assertionModel == 'TRA_assert':
                            thisRoleProxyId = existingRoleDict[ thisOne[ 0]][0]
                            thisRoleProxy = vsv.isProxyId[ thisRoleProxyId, topicMap]
                            thisRoleName = thisRoleProxy.propertyInstances[ roleNamePropertyInstanceInProxyKey]

                            thatRoleProxyId = existingRoleDict[ thatOne[ 0]][0]
                            thatRoleProxy = vsv.isProxyId[ thatRoleProxyId, topicMap]
                            thatRoleName = thatRoleProxy.propertyInstances[ roleNamePropertyInstanceInProxyKey]

                        else:  ## assertionModel == 'A_assert'
                            thisRoleName = thisOne[ 0]
                            thatRoleName = thatOne[ 0]

                        thisRolePlayerProxyId = thisOne[ 1]
                        thisRolePlayerProxy = vsv.isProxyId( thisRolePlayerProxyId, topicMap)
                        thisRolePlayerProxySIP = vsv.SIPOfProxy( thisRolePlayerProxy)
                        thisNewRolePlayerProxy = vsv.newProxyObject( topicMap)
                        vsv.newPropertyInstance( thisNewRolePlayerProxy,
                                                 thisRolePlayerProxySIP.propertyClass.TMA.TMAName,
                                                 thisRolePlayerProxySIP.propertyClass.propertyClassName,
                                                 vsv.versaCopy( thisRolePlayerProxySIP._value),
                                                 triggers,
                                                 conferredValueSources)

                        thatRolePlayerProxyId = thatOne[ 1]
                        vsv.newPropertyInstance( thisNewRolePlayerProxy,
                                                 TMA.TMAName,
                                                 'x_LrnRrnRrp',
                                                 { thisRoleName: { thatRoleName: [ thatRolePlayerProxyId]}},
                                                 triggers,
                                                 conferredValueSources)

                        
