from db.entities.connected_node import NodeC
from db.entities.connected_cluster import ClusterC
from db.entities.connected_layer import LayerC
from typing import Dict

def sortFunctByNode(node):
    try :
        return node.uniqueID
    except:
        print(node.cluster_label)
        print(node.node_layer)
        print(node.uniqueID)

def calculateWeights(inputLayerDict) -> Dict[str,LayerC]: 

    ''' Calculates the nr of connections/weights between the clusters contained in the "inputLayerDict". Connections are made between clusters from DIFFERENT layers.

    :param Dict{string: LayerC} inputLayerDict: Contains the associated LayerC and ConnClusters objects. The dictonary KEY is layername, the Value is a Layer Object. The Layer object has an attribute cluster_Dict which stores the clusters in the LayerC.


    :returns: Dict{layername: LayerC}. Returns the inputLayerDict with the added connections in the attributes cluster_connClustDict and cluster_connNodesDict
    
    :rtype: Dict{string: LayerC}
    '''    


    #the input dictates which cluster is updated; 
    # #however it will update all the included clusters
    # if i only want to update a single cluster without considering the rest i should create a new method?
    #
    #
    #
    #
    print("Entered calculateWeights")
    nodeList = []
    for curLayer in inputLayerDict.values():
        for curCluster in curLayer.cluster_Dict.values():
            for curNode in curCluster.cluster_containedNodesDict.values():
                nodeList.append(curNode)
                #if curNode != None:
                    #if(curNode.uniqueID!= None):
                        

    #print("  Nr. of nodes: " + str(len(nodeList)))

    nodeList.sort(key=sortFunctByNode)

    i=0
    while( i < len(nodeList) ):
        iNode = nodeList[i]
        j=i+1
        while ( j<len(nodeList)):
            jNode = nodeList[j]
            #if there is a connection
            #Compute a connection 

            if (iNode.node_layer != jNode.node_layer) and (iNode.uniqueID == jNode.uniqueID):
                iOldTuple = (iNode.uniqueID,iNode.cluster_label)
                jOldTuple= (jNode.uniqueID,jNode.cluster_label)
                iOldKey = frozenset(iOldTuple)
                jOldKey = frozenset(jOldTuple)
                #iForeignKey =
                #jForeignKey =
                #Check if old node dicts has this node: if not add to ConnDictionary and to OldNodesDict
                #              Layer                .             Cluster             .    OldNodesDict    .    Does not contain the OTHER node
                
                if (inputLayerDict[iNode.node_layer].cluster_Dict[iNode.cluster_label].cluster_connNodesDict.__contains__(jOldKey) == False):
                    #add node j at cluster i
                    if (inputLayerDict[iNode.node_layer].cluster_Dict[iNode.cluster_label].cluster_connClustDict.__contains__(jNode.cluster_label)):
                        inputLayerDict[iNode.node_layer].cluster_Dict[iNode.cluster_label].cluster_connClustDict[jNode.cluster_label]+=1
                    else:
                        inputLayerDict[iNode.node_layer].cluster_Dict[iNode.cluster_label].cluster_connClustDict[jNode.cluster_label]=1
                    #add node to old nodes
                    inputLayerDict[iNode.node_layer].cluster_Dict[iNode.cluster_label].cluster_connNodesDict[jOldKey]=jNode
                    

                    
                
                if (inputLayerDict[jNode.node_layer].cluster_Dict[jNode.cluster_label].cluster_connNodesDict.__contains__(iOldKey) == False):
                    #add node i at cluster j
                    if (inputLayerDict[jNode.node_layer].cluster_Dict[jNode.cluster_label].cluster_connClustDict.__contains__(iNode.cluster_label)):
                        inputLayerDict[jNode.node_layer].cluster_Dict[jNode.cluster_label].cluster_connClustDict[iNode.cluster_label]+=1
                    else:
                        inputLayerDict[jNode.node_layer].cluster_Dict[jNode.cluster_label].cluster_connClustDict[iNode.cluster_label]=1
                    #add node to old nodes
                    inputLayerDict[jNode.node_layer].cluster_Dict[jNode.cluster_label].cluster_connNodesDict[iOldKey]=iNode

            j+=1   
        i+=1

    print("Finished calculateWeights")

    #store weights in database?
    

    return inputLayerDict

