#####################################################################
#####################################################################
## 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                                 ##
#####################################################################
#####################################################################

####################################
cvsRevision = "$Revision: 1.3 $" ##
####################################


import sys


#######################################
## proxyIdSet PC implementation ##
#######################################

## These functions are useful as implementations of SIPs or OPs whose
## values are lists of references to proxies.  Obviously, the name
## "proxyIdSet" only applies to these (library) functions; TMA
## designers can use any name(s) for such properties.

#######################################################
def Add_proxyIdSet_PropToOverheadDict( vsv, propertyInstance, overheadDict):

    workDict = {}
    for proxyId in propertyInstance._value:
        workDict[ proxyId] = None
    propertyInstance.listOfIdsOfReferencedProxies = propertyInstance._value = workDict.keys()

    hashablePropertyValue = propertyInstance.hashablePropertyValue = frozenset( propertyInstance._value)

    if overheadDict.has_key( hashablePropertyValue):
        if overheadDict[ hashablePropertyValue].has_key( propertyInstance.proxyId):
            vsv.errMsg( 'ProxyId %s is already listed in the overheadDict of property class for the value (%s)' % (
                propertyInstance.proxyId, propertyInstance._value))
            sys.exit( 1)
        overheadDict[ hashablePropertyValue][ propertyInstance.proxyId] = None
    else:
        overheadDict[ hashablePropertyValue] = { propertyInstance.proxyId: None}

    vsv.addNewProxyReferencesToReferencedProxiesDict( propertyInstance)

#######################################################
def Remove_proxyIdSet_PropFromOverheadDict( vsv, propertyInstance, overheadDict):
    hashablePropertyValue = propertyInstance.hashablePropertyValue
    if not overheadDict.has_key( hashablePropertyValue):
        vsv.errMsg( 'No entry in overheadDict of property class for the value (%s) of property %s' % (
            propertyInstance._value,
            vsv.catKey( propertyInstance.topicMap.topicMapName, propertyInstance.propertyInstanceKey)))
        sys.exit( 1)
    if propertyInstance.proxyId not in overheadDict[ hashablePropertyValue]:
        vsv.errMsg( 'ProxyId %s not found in the overheadDict of property class for the value (%s) of property %s' % (
            propertyInstance.proxyId,
            propertyInstance._value,
            vsv.catKey( propertyInstance.topicMap.topicMapName, propertyInstance.propertyInstanceKey)))
        sys.exit( 1)

    del overheadDict[ hashablePropertyValue][ propertyInstance.proxyId]
    if not len( overheadDict[ hashablePropertyValue]):
        del overheadDict[ hashablePropertyValue]

    vsv.removeOldProxyReferencesFromReferencedProxiesDict( propertyInstance)

#######################################################
def ValueIsInvalidFor_proxyIdSet_Property( vsv, propertyValue, propertyClass, propertyInstance = None):
    if propertyInstance:
        topicMap = propertyInstance.topicMap
    else:
        topicMap = None

    for proxyId in propertyValue:
        proxy = vsv.isProxyId( proxyId, topicMap)
        if not proxy:
            return True
        if proxy.forwardTo:  ## only living proxies are valid
            return True

    return False

#######################################################
def Merge_proxyIdSet_PropertyValues( vsv, value1, value2):
    newProxyIdSet = {}
    for proxyId in value1:
        newProxyIdSet[ proxyId] = None
    for proxyId in value2:
        newProxyIdSet[ proxyId] = None
    return newProxyIdSet.keys()

#######################################################
def ValuesOf_proxyIdSet_PropertyInstancesAreSignificantlyDifferent( vsv, value1, value2):
    if frozenset( value1) != frozenset( value2):  ## ignore differences in sequence and ignore redundant entries
        return True
    return False

#######################################################
def MergeProxiesBecause_proxyIdSet_PropertyInstancesSpecifySameSubject( vsv, propertyClass):
    for key in propertyClass.overheadDict:
        if len( propertyClass.overheadDict[ key]) > 1:
            vsv.mergeListOfProxies( propertyClass, propertyClass.overheadDict[ key].keys())

#######################################################
def ProxiesOfSubjectIdentifiedBy_proxyIdSet_Value( vsv, propertyClass, value):
    hashablePropertyValue = frozenset( value)
    if propertyClass.overheadDict.has_key( hashablePropertyValue):
        return propertyClass.overheadDict[ hashablePropertyValue].keys()
    else:
        return []  ## empty list -- no match

#######################################################
def UpdateProxyReferencesIn_proxyIdSet_Value( vsv, propertyInstance, proxyIdToReplace, replacementProxyId):
    value = propertyInstance._value
    if proxyIdToReplace not in value:
        vsv.errMsg( 'proxyIdToReplace "%s" not found in the value of %s' % (
            proxyIdToReplace,
            vsv.catKey( propertyInstance.topicMap.topicMapName, propertyInstance.propertyInstanceKey)))
        sys.exit( 1)

    propertyClass = propertyInstance.propertyClass
    

    ## Remove old value from the "overhead" data for this property class
    if propertyClass.Remove__PropFromOverheadDictFArgString:
        execStr = 'propertyClass.Remove__PropFromOverheadDictF( vsv, propertyInstance, propertyClass.overheadDict, %s)' % (
            propertyClass.Remove__PropFromOverheadDictFArgString)
        exec execStr
    else:
        propertyClass.Remove__PropFromOverheadDictF( vsv, propertyInstance, propertyClass.overheadDict)

    ## Replace the proxyIdToReplace with the replacementProxyId
    oldValue = value[:]
    del value[:]
    for proxyId in oldValue:
        if proxyId == proxyIdToReplace:
            proxyId = replacementProxyId
        if proxyId not in value:
            value.append( proxyId)
        
    ## Expose the list of proxy references that appear in the value as a list of proxyIds
    propertyInstance.listOfIdsOfReferencedProxies = value
        ## happens to be a list, so use the same list


    ## Add new value to the "overhead" data for this property class
    if propertyClass.Add__PropToOverheadDictFArgString:
        execStr = 'propertyClass.Add__PropToOverheadDictF( vsv, propertyInstance, propertyClass.overheadDict, %s)' % (
            propertyClass.Add__PropToOverheadDictFArgString)
        exec execStr
    else:
        propertyClass.Add__PropToOverheadDictF( vsv, propertyInstance, propertyClass.overheadDict)

