import networkx as nx

from ctypes import cdll
import genFunctions as genF
import genColorable as genC
import time

cgraph = cdll.LoadLibrary('../gen_c/jmgraph.so')



graphContainer = []
coreContainer = []
canonicContainer = []
canonicCoreCont = []

def generate(size):
    global graphContainer, coreContainer, canonicContainer,canonicCoreCont

    graphContainer = [[] for i in range(size//2)]
    canonicContainer = [[] for i in range(size // 2)]
    coreContainer = [[] for i in range(size // 2)]
    canonicCoreCont = [[] for i in range(size // 2)]


    auxGraphs = genC.generate(size+2)



    g2 = nx.MultiGraph()
    g2.add_edges_from([(1, 2), (1, 1), (2, 2)])


    graphContainer[0].append(g2)


    for i in range((size//2)-1):
        start_time = time.time()
        prev = graphContainer[i]

        for gr in prev:

            for u,v,x  in gr.edges:
                #TODO check colourability

                newGraph1 = genF.addTwoNodesOnEdge(gr, (u, v))
                genF.insertGraph(graphContainer, canonicContainer, newGraph1)

                newGraph2 = genF.addTwoLoopsInsteadEdge(gr, (u, v))
                genF.insertGraph(graphContainer, canonicContainer, newGraph2)

            for n in gr.nodes:

                newGraph3 = genF.addTriangle(gr, n)
                genF.insertGraph(graphContainer, canonicContainer, newGraph3)

        if(i > 0):
            prev2 = graphContainer[i-1]
            for gr in prev2:
                for u1,v1,x in gr.edges:
                    for u2,v2,y in gr.edges:
                        if(x != y):

                            newGraph4 = genF.addSquare(gr, (u1, v1), (u2, v2))
                            genF.insertGraph(graphContainer, canonicContainer, newGraph4)


        for groupSeqNum in range(((i+1)//2)+1):

            smallGraphs = graphContainer[groupSeqNum]
            bigGraphs = graphContainer[i+1- groupSeqNum]

            for small in smallGraphs:
                for big in bigGraphs:
                    for n1 in small.nodes:
                        for n2 in big.nodes:
                            newGraph = genF.joinGraphsOnNodes(small, big, n1, n2)
                            if(newGraph != None):
                                genF.insertGraph(graphContainer, canonicContainer, newGraph)

        for groupSeqNum in range(i):

            normalGraphs = graphContainer[groupSeqNum]
            auxGraphsSet = auxGraphs[i+1- groupSeqNum]

            for small in normalGraphs:
                for big in auxGraphsSet:
                    for n1 in small.nodes:
                        for n2 in big.nodes:
                            newGraph = genF.joinGraphsOnNodes(small, big, n1, n2)
                            if(newGraph != None):
                                genF.insertGraph(graphContainer, canonicContainer, newGraph)

        if(i>0):
            for groupSeqNum in range(0, (i // 2) + 1):

                smallGraphs = graphContainer[groupSeqNum]
                bigGraphs = graphContainer[i- groupSeqNum]

                for small in smallGraphs:
                    for big in bigGraphs:
                        for e1,e2,x1 in small.edges:
                            for f1,f2,x2 in big.edges:

                                newGraph = genF.joinGraphsOnEdges(small, big, (e1, e2), (f1, f2))
                                if (newGraph != None):
                                    genF.insertGraph(graphContainer, canonicContainer, newGraph)

            for groupSeqNum in range(i):
                normalGraphs = graphContainer[groupSeqNum]
                auxGraphsSet = auxGraphs[i - groupSeqNum]

                for small in normalGraphs:
                    for big in auxGraphsSet:
                        for e1, e2, x1 in small.edges:
                            for f1, f2, x2 in big.edges:

                                newGraph = genF.joinGraphsOnEdges(small, big, (e1, e2), (f1, f2))
                                if (newGraph != None):
                                    genF.insertGraph(graphContainer, canonicContainer, newGraph)

        print("Finished generation: {} nodes --- {} seconds".format(2*(i+2), (time.time() - start_time)))


"""
graphContainer = []
coreContainer = []
canonicContainer = []
canonicCoreCont = []
"""

#simple snark generationa and reduction to cores:

generation_starting_time = time.time()

generate(8)
genF.saveGraphContainer(graphContainer, "savedGraphs")
for set in graphContainer:
    print(len(set))

print("Finished generation --- {} seconds ---".format(time.time() - generation_starting_time))

genF.addGraphToCoreContainers(coreContainer, canonicCoreCont, graphContainer)
genF.saveGraphContainer(coreContainer, "savedGraphCores")
print("Finished core addition --- {} seconds ---".format(time.time() - generation_starting_time))
for set in coreContainer:
    print(len(set))



#reading larg snarks from database
"""
snarkContainer = genF.returnSnarks()

#for snark in snarkContainer:
#    print(snark.edges())

snarkCores = [[] for i in range(10)]
snarkCanCore = [[] for i in range(10)]
genF.addGraphToCoreContainers(snarkCores, snarkCanCore, snarkContainer)

#for snark in snarkContainer:
#    snarkCopy = nx.Graph()
#    snarkCopy.add_edges_from(snark.edges)
#    snarkCopy = nx.convert_node_labels_to_integers(snarkCopy, 1)
#    print(snarkCopy.edges())
#    print(genF.returnSimpleCanonic(snarkCopy))


print("Adding first snark")
generation_starting_time = time.time()
#snarkContainer[0] is the Petersens graph
genF.insertGraphCores(snarkCores, snarkCanCores, snarkContainer[0], 0)

print("First snark Fnished --- {} seconds ---".format(time.time() - generation_starting_time))

for set in snarkCores:
    print(len(set))

"""

#test for Petersen graph
"""
petersenCores = [[] for i in range(10)]
petersenCanCore = [[] for i in range(10)]

print("Adding Petersen-graph")
generation_starting_time = time.time()
petersen = nx.Graph()
petersen.add_edges_from([(1,3),(1,4),(2,5),(2,4),(3,5),(1,6),(2,7),(3,8),(4,9),(5,10),(6,7),(7,8),(8,9),(9,10),(10,6)])
genF.saveGraphContainer(petersenCores, "savedPetersenCores")
genF.insertGraphCores(petersenCores, petersenCanCore, petersen, 0)

print("Petersen Fnished --- {} seconds ---".format(time.time() - generation_starting_time))

for set in petersenCores:
    print(len(set))
"""


