# 30.1.2018 9:15
import bpy
bpy.app.debug = True
import re
import sys

force_multiplier = 1000


part_name = 'Specimen'
filename = "model_apdl_custom.txt"

DEF_V = 0
DEF_H = 1
counter = 0

e = 2   # number of nodes that an edge connects
nodes = []
loose_edges = []
buf = []    # buffer for membership indices of investigated substructures and supports
forces = 0
index_buf = 0
xcor = 0.0
ycor = 0.0
findex = 0

a = open(filename, "w")

a.write("! " + str(filename) + " generated from Blender 2.76\n")
a.write("! " + bpy.path.basename(bpy.context.blend_data.filepath) + "\n\n")

for i in range(len(bpy.data.objects[str(part_name)].data.edges)):   # goes through all the edges
    if bpy.data.objects[str(part_name)].data.edges[i].is_loose: # if it finds a loose one
        loose_edges.append(i)   # it adds it to a list
    else:   # if the edge is a connected one
        if bpy.data.objects[str(part_name)].data.edges[i].vertices[0] not in nodes:
            nodes.append(bpy.data.objects[str(part_name)].data.edges[i].vertices[0])
        if bpy.data.objects[str(part_name)].data.edges[i].vertices[1] not in nodes:
            nodes.append(bpy.data.objects[str(part_name)].data.edges[i].vertices[1])
nodes.sort()

'''
a.write("! number of nodes = " + str(len(nodes)) + "\n")

po = bpy.data.objects[str(part_name)].data  # making the "path" shorter

for i in range(len(nodes)):    # goes through all the nodes
    xcor = po.vertices[nodes[i]].co.x
    ycor = po.vertices[nodes[i]].co.y
    f.write(".{0:d}=".format(i))
    f.write("{")
    f.write("{0:.6f};{1:.6f}".format(xcor, ycor))  # prints x and y coordinates of given node
    f.write("}\n")
    a.write("N,{0:d},{1:.6f},{2:.6f},0,0,0,0\n".format(i, xcor, ycor))
f.write(".!\n\n")   # symbol for the end of nodes
a.write("\n")

f.write("#<number_of_elements>={" + str(len(bpy.data.objects[str(part_name)].data.polygons)) + "}\n")  # total number of elements
a.write("! number of elements = " + str(len(bpy.data.objects[str(part_name)].data.polygons)) + "\n")
'''

'''
for i in range(len(bpy.data.objects[str(part_name)].data.polygons)):    # goes through all the elements 
    a.write("E")
    for j in range(len(bpy.data.objects[str(part_name)].data.polygons[i].vertices)):    # goes through all nodes of a given element
        for k in range(len(nodes)):
            if str(bpy.data.objects[str(part_name)].data.polygons[i].vertices[j]) == str(nodes[k]): # error
                a.write("," + str(k))
    a.write("\n")
a.write("\n")
'''

''' begin { working } '''
super_nodes = [[] for x in range(len(bpy.data.objects[str(part_name)].data.materials))]

for i in range(len(bpy.data.objects[str(part_name)].data.materials)):   # goes through all substructures
    del buf[:]
    for j in range(len(bpy.data.objects[str(part_name)].data.polygons)): # digs through all the elements
        if i == bpy.data.objects[str(part_name)].data.polygons[j].material_index:   # and if the element belongs to the currently investigated substructure
            buf.append(j)    # it stores the element index
    a.write("\n! superelement " + str(i + 1) + " elements: " + str(len(buf)) + "\n")
    for j in range(len(buf)):
        #f.write("_" + str(i) + "={" + str(buf[j]) + "}")
        a.write("E")
        for k in range(len(bpy.data.objects[str(part_name)].data.polygons[buf[j]].vertices)):    # goes through all nodes of a given element
            for l in range(len(nodes)):
                if str(bpy.data.objects[str(part_name)].data.polygons[buf[j]].vertices[k]) == str(nodes[l]): # error
                    a.write("," + str(nodes[l] + 1))
                    if nodes[l] not in super_nodes[i]:
                        super_nodes[i].append(nodes[l])
        a.write("\n")
    super_nodes[i].sort()
a.write("\n")
''' end { working } '''

for i in range(len(super_nodes)):
    a.write("! superelement " + str(i + 1) + " nodes = " + str(len(super_nodes[i])) + "\n")
    for j in range(len(super_nodes[i])):
        a.write("N,{0:d},{1:.6f},{2:.6f},0,0,0,0\n".format(super_nodes[i][j] + 1, bpy.data.objects[str(part_name)].data.vertices[super_nodes[i][j]].co.x, bpy.data.objects[str(part_name)].data.vertices[super_nodes[i][j]].co.y))
    a.write("\n")
a.write("\n")

sub_nodes = [[[],[]] for x in range(len(bpy.data.objects[str(part_name)].data.materials))]   # creates a 3D list [substructures] [[V][H]]
for i in range(len(bpy.data.objects[str(part_name)].data.polygons)):    # goes through all the elements
    for j in range(len(bpy.data.objects[str(part_name)].data.polygons[i].vertices)):    # goes through all the nodes of the element
        if bpy.data.objects[str(part_name)].data.polygons[i].vertices[j] not in sub_nodes[bpy.data.objects[str(part_name)].data.polygons[i].material_index][DEF_V]: # if it is not in the list of nodes for the given substructure
            sub_nodes[bpy.data.objects[str(part_name)].data.polygons[i].material_index][DEF_V].append(bpy.data.objects[str(part_name)].data.polygons[i].vertices[j])   # append it to the abovementioned list

#f.write("&<substructure_nodes>={" + str(len(bpy.data.objects[str(part_name)].data.materials)) +"}\n")
for i in range(len(sub_nodes)): # all the substructures
    sub_nodes[i][DEF_V].sort()  # sort it
    print("substructure nodes [" + str(i) + "] = " + str(len(sub_nodes[i][DEF_V])) + "\n")
    #f.write("&<" + str(i) + ">={" + str(len(sub_nodes[i][DEF_V])) + "}\n")
    #for j in range(len(sub_nodes[i][DEF_V])):  # all the nodes in a substructure
        #f.write("&" + str(i) + "={" + str(nodes.index(sub_nodes[i][DEF_V][j])) + "}")
        #if j == len(sub_nodes[i][DEF_V]) - 1:
            #f.write(";")
        #f.write("\n")
#f.write("&;\n\n")
        
        

for s in range(len(sub_nodes)): # all the substructures
    for o in range(len(sub_nodes)): # all the other substructures
        if s != o:  # so that it really is only the other substructures
            counter = 0 # utility variable for keeping the loop inside index bounds
            while counter < len(sub_nodes[s][DEF_V]):   # while inside the list
                if sub_nodes[s][DEF_V][counter] in sub_nodes[o][DEF_V] or sub_nodes[s][DEF_V][counter] in sub_nodes[o][DEF_H]:  # if the node is also in other substructure
                    sub_nodes[s][DEF_H].append(sub_nodes[s][DEF_V].pop(counter))    # move it from DEF_V to DEF_H sublist
                else:   # if the node is not on a boundary between multiple substructures
                    counter = counter + 1   # move on in the sublist

# NOT REALLY SURE ABOUT THIS SECTION'S CORRECTNESS
for i in range(len(loose_edges)):   # all the force representing edges
    if bpy.data.objects[str(part_name)].data.edges[loose_edges[i]].vertices[0] in nodes:    # if the first force edge node is an actual node inside the nodes list
        findex = 0  # set a utility variable as such
    else:
        findex = 1  # or such
    for j in range(len(sub_nodes)):  # all the substructures
        if bpy.data.objects[str(part_name)].data.edges[loose_edges[i]].vertices[findex] in sub_nodes[j][DEF_V]:    # if the node a force is connected to is in the DEF_V sublist of a substructure
            sub_nodes[j][DEF_H].append(sub_nodes[j][DEF_V].pop(sub_nodes[j][DEF_V].index(bpy.data.objects[str(part_name)].data.edges[loose_edges[i]].vertices[findex])))    # move it to the DEF_H sublist


for n in range(len(nodes)): # all the nodes
    for s in range(len(sub_nodes)): # all the substructures
        if len(bpy.data.objects[str(part_name)].data.vertices[nodes[n]].groups) > 0:  # if the node is a support
            if nodes[n] in sub_nodes[s][DEF_V]:  # if it is listed as inside the substructure
                sub_nodes[s][DEF_H].append(sub_nodes[s][DEF_V].pop(sub_nodes[s][DEF_V].index(nodes[n])))

for i in range(len(sub_nodes)): # all the substructures
    for j in range(len(sub_nodes[i])):  # both the DEF_V and DEF_H sublists
        sub_nodes[i][j].sort()  # sort them                                                     MAY CAUSE UNIDENTIFIED BEHAVIOUR

''' begin { working } '''
for i in range(len(sub_nodes)):
    a.write("! substructure " + str(i + 1) + " master nodes " + str(len(sub_nodes[i][DEF_H])) + "\n")
    #f.write("|<" + str(i) + ">=[" + str(len(sub_nodes[i][DEF_V])) + "](" + str(len(sub_nodes[i][DEF_H])) + ")\n")
    #'''for j in range(len(sub_nodes[i])):  # so that it would print both the inner and boundary nodes'''
    for k in range(len(sub_nodes[i][1])):   # and it should only print as many as there are
        a.write("M," + str(nodes.index(sub_nodes[i][1][k]) + 1) + ",ALL\n")
    a.write("\n")
a.write("\n")
''' end { working } '''

sups = len(bpy.data.objects[str(part_name)].vertex_groups)  # number of support types
#f.write("^<number_of_support_types>={" + str(sups) + "}\n") # number of different types of supports used

for i in range(sups):   # goes through the whole list of support type names
    del buf[:]
    for j in range(len(nodes)): # goes through all nodes
        if len(bpy.data.objects[str(part_name)].data.vertices[j].groups) > 0:   # if the node belongs to any group
            for k in range(len(bpy.data.objects[str(part_name)].data.vertices[j].groups)):  # checks all its memberships for the investigated one
                if bpy.data.objects[str(part_name)].data.vertices[j].groups[k].group == i:  # and if there is a match,
                    buf.append(j)
    #f.write("^\"" + str(bpy.data.objects[str(part_name)].vertex_groups[i].name + "\'<" + str(i) + ">={" + str(len(buf)) + "}\n"))
    for j in range(len(buf)):
        #f.write("^" + str(i) + "={" + str(nodes[buf[j]]) + "}") # it gets printed out
        
        a.write("D," + str(nodes[buf[j]] + 1) + ",UX,0,,,,UY\n")
        #if j == len(buf) - 1:   # if it is the last one
            #f.write(";")    # indicate the end
        #f.write("\n")
#f.write("^!\n\n")  # symbol for the end of supports
a.write("\n")

for i in range(len(bpy.data.objects[str(part_name)].data.edges)):   # goes through all the edges
    if bpy.data.objects[str(part_name)].data.edges[i].is_loose:
        forces = forces + 1
#f.write("$<number_of_forces>={" + str(forces) + "}")
a.write("! number of forces = " + str(forces) + "\n")

for i in range(len(bpy.data.objects[str(part_name)].data.edges)):   # goes through all edges
    index_buf = 0   # reset the buffer
    if bpy.data.objects[str(part_name)].data.edges[i].is_loose:
        #f.write("\n")
        if bpy.data.objects[str(part_name)].data.edges[i].vertices[0] in nodes: # if the first edge vertex is a node
            for j in range(len(nodes)): # finds the index of the given node
                if bpy.data.objects[str(part_name)].data.edges[i].vertices[0] == nodes[j]:  # if it finds it
                    index_buf = j   # it stores it in the buffer
            #f.write("$" + str(index_buf) + "={")   # it prints out the vertex index
            xcor = bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[1]].co.x - bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[0]].co.x
            ycor = bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[1]].co.y - bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[0]].co.y
            #f.write("{0:.6f};{1:.6f}".format(xcor, ycor))
            #f.write("}")
            if xcor != 0:
                a.write("F," + str(index_buf + 1) + ",FX,{0:.6f}\n".format(xcor * force_multiplier))
            if ycor != 0:
                a.write("F," + str(index_buf + 1) + ",FY,{0:.6f}\n".format(ycor * force_multiplier))
        elif bpy.data.objects[str(part_name)].data.edges[i].vertices[1] in nodes:   # if the second edge vertex is a node
            for j in range(len(nodes)): # finds the index of the given node
                if bpy.data.objects[str(part_name)].data.edges[i].vertices[1] == nodes[j]:  # if it finds it
                    index_buf = j   # it stores it in the buffer
            #f.write("$" + str(index_buf) + "={")   # it prints out the vertex index
            xcor = bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[0]].co.x - bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[1]].co.x
            ycor = bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[0]].co.y - bpy.data.objects[str(part_name)].data.vertices[bpy.data.objects[str(part_name)].data.edges[i].vertices[1]].co.y
            #f.write("{0:.6f};{1:.6f}".format(xcor, ycor))
            #f.write("}")
            if xcor != 0:
                a.write("F," + str(index_buf + 1) + ",FX,{0:.6f}\n".format(xcor * force_multiplier))
            if ycor != 0:    
                a.write("F," + str(index_buf + 1) + ",FY,{0:.6f}\n".format(ycor * force_multiplier))
#f.write(";\n$!\n\n")   # symbol for the end of forces

#f.write("!*")
#f.close()
a.close()