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.node_cluster)
        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):
                iNodeTuple = (iNode.uniqueID,iNode.node_cluster,iNode.node_layer)
                jNodeTuple= (jNode.uniqueID,jNode.node_cluster,jNode.node_layer)
                iNodeKey = frozenset(iNodeTuple)
                jNodeKey = frozenset(jNodeTuple)
                iClusterTuple = (iNode.node_cluster,iNode.node_layer)
                jClusterTuple = (jNode.node_cluster,jNode.node_layer)
                #iClusterKey = frozenset(iClusterTuple)
                #jClusterKey = frozenset(jClusterTuple)
                #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.node_cluster].cluster_connNodesDict.__contains__(jNodeKey) == False):
                    #add node j at cluster i
                    if (inputLayerDict[iNode.node_layer].cluster_Dict[iNode.node_cluster].cluster_connClustDict.__contains__(jClusterTuple)):
                        inputLayerDict[iNode.node_layer].cluster_Dict[iNode.node_cluster].cluster_connClustDict[jClusterTuple]+=1
                    else:
                        inputLayerDict[iNode.node_layer].cluster_Dict[iNode.node_cluster].cluster_connClustDict[jClusterTuple]=1
                    #add node to old nodes
                    inputLayerDict[iNode.node_layer].cluster_Dict[iNode.node_cluster].cluster_connNodesDict[jNodeKey]=jNode
                    

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

            j+=1   
        i+=1

    print("Finished calculateWeights")

    #store weights in database?
    

    return inputLayerDict

