#####################################################################
#####################################################################
## 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.2 $" ##
####################################


import sys


###################################
## setOfString_ProxyRefTuples PC implementation ##
###################################

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

    value = propertyInstance._value

    hashablePropertyValue = propertyInstance.hashablePropertyValue = frozenset( value)
    if overheadDict.has_key( hashablePropertyValue):
        if propertyInstance.proxyId not in overheadDict[ hashablePropertyValue]:
            overheadDict[ hashablePropertyValue].append( propertyInstance.proxyId)
    else:
        overheadDict[ hashablePropertyValue] = [ propertyInstance.proxyId]

    proxyRefSet = {}
    for tuple in value:
        proxyRefSet[ tuple[ 1]] = None
    propertyInstance.listOfIdsOfReferencedProxies = proxyRefSet.keys()
    vsv.addNewProxyReferencesToReferencedProxiesDict( propertyInstance)

#######################################################
def Remove_setOfString_ProxyRefTuples_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)

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

    vsv.removeOldProxyReferencesFromReferencedProxiesDict( propertyInstance)

#######################################################
def Merge_setOfString_ProxyRefTuples_PropertyValues( vsv, value1, value2):
    newValue = {}
    for thisTuple in value1:
        newValue[ thisTuple] = None
    for thisTuple in value2:
        newValue[ thisTuple] = None
    return newValue.keys()

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

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

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

#######################################################
def UpdateProxyReferencesIn_setOfString_ProxyRefTuples_Value( vsv, propertyInstance, proxyIdToReplace, replacementProxyId):
    oldValue = propertyInstance._value
    newValueSet = {}  ## if it turns out that two tuples wind up being the same,
                   ## this method will make sure that only one of them
                   ## remains.
    proxyRefSet = {}  
##     foundProxyIdToReplace = False
    for oldTuple in oldValue:
        newTupleList = [ oldTuple[ 0]]
        if oldTuple[ 1] == proxyIdToReplace:
            newTupleList.append( replacementProxyId)
            proxyRefSet[ replacementProxyId] = None
##                 foundProxyIdToReplace = True
        else:
            newTupleList.append( oldTuple[ 1])
            proxyRefSet[ oldTuple[ 1]] = None
        newValueSet[ tuple( newTupleList)] = None

##     CANNOT DO THIS CHECK because sometimes a proxy reference is updated multiple times in the same merge cycle.
##     if not foundProxyIdToReplace:
##         vsv.errMsg( 'Did not find reference to proxy %s in propertyInstance %s.' % ( proxyIdToReplace, propertyInstance.propertyInstanceKey))
## ###
##         vsv.inspect( proxyId=propertyInstance.proxy.proxyId)
## ###        
##         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 old value with the new one
    del oldValue[:]
    oldValue.extend( newValueSet.keys())
        
    ## Expose the list of proxy references that appear in the value as a list of proxyIds
    propertyInstance.listOfIdsOfReferencedProxies = proxyRefSet.keys()

    ## Add new value to the "overhead" data for this property class  (this sets propertyInstance.hashablevalue)
    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)



