# This third tutorial will cover more on defining functions, analysing code, more on mesh operations, and while statements.

# You will notice when you are working with model coding, references to bpy.ops, and references to bmesh.
# The difference between the two boils down to the level of the code.  By that, I mean, for a real world 
# example, it is like the difference between walking to a destination and flying to a destination, with bpy.ops
# you are taking a slower, less efficent route, because it is part of the 3D view operations, whereas with
# bmesh, it is much faster.  That said, unless you are doing a lot of operations on a large, processor-intense
# model, you probably do not need to concern yourself with the difference.

bpy.context.scene.cursor.location = (0,0,0)   # Cursor to origin

# Let's create a function
# Create a plane, resize and subdivide
def plane(sz, subdiv=4, vlocation=(0, 0, 0)):
    bpy.ops.mesh.primitive_plane_add(size=sz, calc_uvs=True, enter_editmode=True, align='WORLD', location=vlocation, rotation=(0, 0, 0), scale=(0, 0, 0))
    bpy.ops.object.mode_set(mode="EDIT")
    bpy.ops.mesh.subdivide(number_cuts=subdiv)
    bpy.ops.object.mode_set(mode="OBJECT") # This IS line necessary
    bpy.ops.object.mode_set(mode="EDIT")

# This function moves the pivot point of the object to the origin.  
# We should be able to analyse it quite easily.
import bpy
from mathutils import Vector, Matrix

ob = bpy.context.active_object
global_origin=Vector()

def set_origin(ob, global_origin=Vector()):
    mw = ob.matrix_world
    o = mw.inverted() @ Vector(global_origin)  # @ is a symbol for matrix multiplication
    ob.data.transform(Matrix.Translation(-o))
    mw.translation = global_origin

ao = bpy.context.active_object
set_origin(ao)

ao = bpy.context.active_object   # Get active object

bpy.ops.object.select_all(action='DESELECT')   # ('TOGGLE', 'SELECT', 'DESELECT', 'INVERT') all objects

ob = bpy.context.active_object

for ob in bpy.data.objects:
     if(ob.name=='Plane'):
         me = ob.data
         bm = bmesh.from_edit_mesh(me)
         for face in range(36):
             bm.faces[face].select = False
         bmesh.update_edit_mesh(me, True)

ao = bpy.context.active_object
# Using TAB:
ao.data.

# Three interesting results in the list are:
vertices
edges
polygons

# Remember to run this each time you change the object or you will
# be seeing the information from the last object you worked with
ao = bpy.context.active_object  
verts = ao.data.vertices
edges = ao.data.edges
polygons = ao.data.polygons

n = -1  
for v in verts:
    n += 1
    print(n, v.co)
    
for edge in edges:
    for v in edge.vertices:
        print(v, end=' ')
        
for plane in polygons:
    for v in plane.vertices:
        print(v, end=' ')

# To view vertices, edge, face numbers in the 3Dview: /*
Edit > Preferences > Interface > Then under Display, look for "Developer Extras" and check it
Go to the Viewport Overlays, it will be on the right side of the 3D viewport, look for the icon
that has a solid circle with an empty circle overlaying it, and click the drop-down arrow to the right of it.
Under "Developer", find Indices, and check the checkbox.
Create a plane in the 3D viewport, switch to edit mode, and vertex.  
If the colors for the numbers are not visible, go back to Edit > Preferences > Themes > 3D Viewport header
and change the Face Angle Text color, that should make it easier to see.
I have left this note here in case you want to refer to it later, or need to turn it back off.*/

ao = bpy.context.active_object  # Get active object
# get index of currently selected vertex(s) in OBJECT MODE
[i.index for i in ao.data.vertices if i.select]
[5]
# to get a coordinate(s):
[i.co for i in bpy.context.active_object.data.vertices if i.select]

# Using this and some other code we can create functions that 
# select the various types, and print out information about them        
ao = bpy.context.active_object
verts = ao.data.vertices
edges = ao.data.edges
polygons = ao.data.polygons

# Select a vertices n
def getvert(n):
    ao = bpy.context.active_object
    verts = ao.data.vertices
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action="DESELECT")
    bpy.ops.object.mode_set(mode='OBJECT')
    verts[n].select = True
    print(verts[n].co)   # Any print statements can be removed if you do not want them
    bpy.ops.object.mode_set(mode='EDIT')

# Select an edge
def getedge(n):
    ao = bpy.context.active_object
    verts = ao.data.vertices
    edges = ao.data.edges
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action="DESELECT")
    bpy.ops.object.mode_set(mode='OBJECT')
    edges[n].select = True
    print(edges[n].vertices[0], end=' ')
    print(verts[edges[n].vertices[0]].co)
    print(edges[n].vertices[1], end=' ')
    print(verts[edges[n].vertices[1]].co)
    bpy.ops.object.mode_set(mode='EDIT')

# Select a face
def getface(n):
    ao = bpy.context.active_object
    verts = ao.data.vertices
    edges = ao.data.edges
    polygons = ao.data.polygons
    bpy.ops.object.mode_set(mode='EDIT')
    bpy.ops.mesh.select_all(action="DESELECT")
    bpy.ops.object.mode_set(mode='OBJECT')
    polygons[n].select = True
    bpy.ops.object.mode_set(mode='EDIT') # *Needed* likely to store the data
    bpy.ops.object.mode_set(mode='OBJECT')
    vertsel = [i.index for i in ao.data.vertices if i.select]
    print(vertsel[0], verts[vertsel[0]].co)
    print(vertsel[1], verts[vertsel[1]].co)
    print(vertsel[2], verts[vertsel[2]].co)
    print(vertsel[3], verts[vertsel[3]].co)
    bpy.ops.object.mode_set(mode='EDIT')

# Tutorial four will cover more on more on mesh operations, and while statements, how to pull up demo scripts.