bl_info = {
    "name": "T3D Import",
    "description": "Imports an Unreal Engine 4 T3D file.",
    "author": "Clinton Reese",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "File > Import",
    "support": "COMMUNITY",
    "category": "Import-Export"
    }


import bpy
import bmesh
import os

class ImportState:
    f = ''
    lightfound = False
    locationfound = False
    rotationfound = False
    scalefound = False
    drawscale3dfound = False
    prepivotfound = False
    loctag = []
    rottag = []
    scatag = []
    drawscale = 1.0
    pptag = []
    smtag = []
    staticmeshfound = False
    dopolylist = False
    beginpoly = False
    objectname = ""
    meshname = ""
    volumefound = False
    meshfound = False
    csgsubtract = False
    csgadd = False
    firstCSG = True
    lastCSGNode = 'dummy'
    currentObj = ''
    booleanCount = 0
    allMaterials = []
    filelist = ''
    folder = ''
    
    def resetstate():
        ImportState.lightfound = False
        ImportState.locationfound = False
        ImportState.rotationfound = False
        ImportState.scalefound = False
        ImportState.drawscale3dfound = False
        ImportState.prepivotfound = False
        ImportState.smtag = []
        ImportState.staticmeshfound = False
        ImportState.dopolylist = False
        ImportState.beginpoly = False
        ImportState.volumefound = False
        ImportState.meshfound = False
        ImportState.csgadd = False
        ImportState.csgsubtract = False
        ImportState.drawscale = 1.0
        # ImportState.lastCSGNode = 'dummy'
        # ImportState.currentObj = ''
        # ImportState.booleanCount = 0
        # ImportState.allMaterials = []
        # ImportState.filelist = ''
        # ImportState.folder = ''
        # ImportState.firstCSG = True

def setTheTransform(i_s, scenescale, ue4rotation):
    
    if ue4rotation:
        unreal2deg = 1.0
    else:
        unreal2deg = 360/65536
    
    ppx = 0
    ppy = 0
    ppz = 0
    lx = 0
    ly = 0
    lz = 0
    dsx = 1
    dsy = 1
    dsz = 1
    ds = 1
    
    if i_s.prepivotfound:
        for i in range(len(i_s.pptag)):
            element = i_s.pptag[i].split('=')
            axis = element[0]
            val = float(element[1])
            if axis == 'X':
                ppx = val * scenescale
            if axis == 'Y':
                ppy = -val * scenescale
            if axis == 'Z':
                ppz = val * scenescale

        me = i_s.currentObj.data
        bm = bmesh.new()
        bm.from_mesh(me)
        for v in bm.verts:
            # v.co += 0.1 * v.normal
            v.co.x -= ppx
            v.co.y -= ppy
            v.co.z -= ppz
        bm.to_mesh(me)
        me.update()
    
    if i_s.locationfound:
        for i in range(len(i_s.loctag)):
            element = i_s.loctag[i].split('=')
            axis = element[0]
            val = float(element[1])
            if axis == 'X':
                lx = val * scenescale
            if axis == 'Y':
                ly = -val * scenescale
            if axis == 'Z':
                lz = val * scenescale
    
    if i_s.rotationfound:
        bpy.context.object.rotation_mode = 'ZYX'

        for i in range(len(i_s.rottag)):
            element = i_s.rottag[i].split('=')
            axis = element[0]
            val = float(element[1]) * 3.14159/180.0 * unreal2deg
            if axis == 'Roll':
                bpy.context.object.rotation_euler[0] = val
            if axis == 'Pitch':
                bpy.context.object.rotation_euler[1] = val
            if axis == 'Yaw':
                bpy.context.object.rotation_euler[2] = val
                
    if i_s.drawscale3dfound:
        for i in range(len(i_s.scatag)):
            element = i_s.scatag[i].split('=')
            axis = element[0]
            val = float(element[1])
            if axis == 'X':
                dsx = val
            if axis == 'Y':
                dsy = val
            if axis == 'Z':
                dsz = val
    
    # bpy.context.object.scale[0] = i_s.drawscale * dsx * 1.0001
    # bpy.context.object.scale[1] = i_s.drawscale * dsy * 1.0001
    # bpy.context.object.scale[2] = i_s.drawscale * dsz * 1.0001
    bpy.context.object.scale[0] = i_s.drawscale * dsx
    bpy.context.object.scale[1] = i_s.drawscale * dsy
    bpy.context.object.scale[2] = i_s.drawscale * dsz

    # if i_s.lightfound:
    #     bpy.context.object.rotation_euler[1] = -bpy.context.object.rotation_euler[1] + 270.0*3.14159/180.0
    # bpy.context.object.location = (-ppx+lx, -ppy+ly, -ppz+lz)
    bpy.context.object.location = (lx, ly, lz)

    # bpy.context.object.origin_set(type='ORIGIN_CENTER_OF_MASS')


def readPolyList(fileline, i_s, scenescale):
    #https://blenderartists.org/forum/archive/index.php/t-253200.html
    # Create mesh
    me = bpy.data.meshes.new(i_s.meshname)
    # Create object
    ob = bpy.data.objects.new(i_s.objectname, me)
    i_s.currentObj = ob
    # Link object to scene
    # bpy.context.scene.objects.link(ob)
    bpy.context.scene.collection.objects.link(ob)

    # Get a BMesh representation
    bm = bmesh.new() # create an empty BMesh
    bm.from_mesh(me) # fill it in from a Mesh

    matlist = []
    materialIndex = 0

    dataline = fileline.split()
    while not (dataline[0] == 'End' and dataline[1]=='PolyList'):
        fileline = i_s.f.readline()
        filelinetrim = fileline.strip()
        # print(filelinetrim)
        dataline = filelinetrim.split()
        #print(dataline[0] + " - " + dataline[1])
        if dataline[0] == 'Begin' and dataline[1] == 'Polygon':
            # print('**** BEGIN POLYGON *****')
            # print(len(dataline))
            vertexarray = []
            if len(dataline) > 3:
                polygonMaterialName = ""
                for ti in range(2, len(dataline)):
                    polygonMaterialLabel = dataline[ti].split('=')[0]
                    if polygonMaterialLabel == "Texture":
                        polygonMaterialName = dataline[ti].split('=')[1]
                        if polygonMaterialName not in matlist:
                            matlist.append(polygonMaterialName)
                            materialIndex = len(matlist) - 1
                        else:
                            materialIndex = matlist.index(polygonMaterialName)
                        break
                
                # some code notes for material
                # material_basic = bpy.data.materials.new(name="Basic")
                # material_basic.use_nodes = True
                # bpy.context.object.active_material = material_basic
                # principled_node = material_basic.node_tree.nodes.get('Principled BSDF')
                #set color on the node index reffers to the input connector
                # principled_node.inputs[0].default_value = (0,0,1,1)
                #how assign to specific faces?
                #this needs edit mode to work
                # https://blender.stackexchange.com/questions/27631/assigning-material-to-every-second-face-via-python
                # vertexarray = []
        if dataline[0] == 'Vertex':
            xyz = dataline[1].split(',')
            x = float(xyz[0]) * scenescale
            y = -float(xyz[1]) * scenescale
            z = float(xyz[2]) * scenescale
            vert = ( x, y, z )
            vertexarray.append(bm.verts.new(vert))
        if dataline[0] == 'End' and dataline[1] == 'Polygon':
            # Initialize the index values of this sequence.
            bm.verts.index_update()
            # if i_s.csgadd and not i_s.csgsubtract:
            # if i_s.csgsubtract:
            vertexarray.reverse()
            vertextuple = tuple(vertexarray)
            #print(vertextuple)
            thepoly = bm.faces.new( vertextuple )
            thepoly.material_index = materialIndex
            
            
            # print('END POLYGON')

            #https://blender.stackexchange.com/questions/28589/meshs-material-index-is-an-index-into-what

    # Finish up, write the bmesh back to the mesh
    bm.to_mesh(me)
    
    # bpy.context.scene.objects.active = ob
    bpy.context.view_layer.objects.active = ob

    for matslot in range(len(matlist)):
        # bpy.ops.object.material_slot_add()
        if matlist[matslot] not in i_s.allMaterials:
            i_s.allMaterials.append(matlist[matslot])
            mat = bpy.data.materials.new(name=matlist[matslot])
            mat.use_nodes = True
            mat.use_backface_culling = True

            if not i_s.firstCSG:
                i_s.lastCSGNode.data.materials.append(mat)
            # bpy.ops.image.open(filepath="C:\\Temp\\DeusExTest\\NYC_Bar_01.png", directory="C:\\Temp\\DeusExTest\\", files=[{"name":"NYC_Bar_01.png", "name":"NYC_Bar_01.png"}], show_multiview=False)
            # bpy.data.materials["NYC_Bar_01"].node_tree.nodes["Image Texture"].projection = 'BOX'
            #no command to set vector to geometry position
             #PLAN - check for and load texture files that match material names
    
            for thefile in i_s.filelist:
                # print(thefile)
                splitExt = os.path.splitext(thefile)
                if splitExt[1] == ".png":
                    if splitExt[0] == matlist[matslot]:
                        # print("load texture")
                        # print(thefile)
                        imageFile = os.path.join(i_s.folder, thefile)
                        # bpy.ops.image.open(filepath=imageFile)
                        # bpy.ops.image.open(filepath="C:\\Temp\\DeusExTest\\Uob_Concrete.png", directory="C:\\Temp\\DeusExTest\\", files=[{"name":"Uob_Concrete.png", "name":"Uob_Concrete.png"}], relative_path=True, show_multiview=False)
                        bsdf = mat.node_tree.nodes["Principled BSDF"]
                        texImage = mat.node_tree.nodes.new('ShaderNodeTexImage')
                        # texImage.image = bpy.data.images.load("C:\\Users\\myName\\Downloads\\Textures\\Downloaded\\flooring5.jpg")
                        texImage.image = bpy.data.images.load(imageFile)
                        mat.node_tree.links.new(bsdf.inputs['Base Color'], texImage.outputs['Color'])

        else:
            mat = bpy.data.materials.get(matlist[matslot])
        ob.data.materials.append(mat)
        # mat.use_nodes = True
        # mat.use_backface_culling = True

    # uv
    bpy.ops.object.editmode_toggle()
    bpy.ops.mesh.select_all(action='SELECT')
    bpy.ops.uv.cube_project(cube_size=1)
    bpy.ops.object.editmode_toggle()

    if i_s.volumefound:
        # bpy.context.object.draw_type = 'WIRE'
        bpy.context.object.display_type = 'WIRE'

def read_some_data(context, filepath, ue4rotation, scenescale):
    # print("***********  running read_some_data... ****************")

    i_s = ImportState
    i_s.f = open(filepath, 'r', encoding='utf-8')

    i_s.filelist = os.listdir(os.path.dirname(filepath))
    i_s.folder = os.path.dirname(filepath)
    
    fileline = i_s.f.readline()
    while fileline:
        if fileline == "\n":
            # print("blank line")
            fileline = i_s.f.readline()
            continue
        dataline = fileline.split()
        # if dataline[0] == 'Begin' and dataline[1] == 'Map':
        #     print('map file')
        # if dataline[0] == 'End' and dataline[1] == 'Map':
        #     print('end of map file')
        # if dataline[0] == 'Begin' and dataline[1] == 'Level':
        #     print('level')
        # if dataline[0] == 'End' and dataline[1] == 'Level':
        #     print('end level')
        
        if dataline[0] == 'Begin' and dataline[1] == 'Actor':
            # print('begin actor')
            for data in dataline:
                lbltag = data.split('=')
                if lbltag[0] == 'Class':
                    actor_class = lbltag[1]
                if lbltag[0] == 'Name':
                    name = lbltag[1]
            # print(name + " " + actor_class)
            
            # if actor_class == 'DirectionalLight':
            if actor_class == '/Script/Engine.DirectionalLight':
                # bpy.ops.object.lamp_add(type='SUN')
                bpy.ops.object.light_add(type='SUN')
            elif actor_class == 'SpotLight':
                bpy.ops.object.lamp_add(type='SPOT')
            elif actor_class == 'PointLight' or actor_class == 'Light':
                # bpy.ops.object.lamp_add(type='POINT')
                bpy.ops.object.light_add(type='POINT')
            # if actor_class == 'DirectionalLight' or actor_class == 'SpotLight' or actor_class == 'PointLight' or actor_class == 'Light':
            if actor_class == 'DirectionalLight' or actor_class == '/Script/Engine.DirectionalLight' or actor_class == 'SpotLight' or actor_class == 'PointLight' or actor_class == 'Light':
                bpy.context.object.name = name
                i_s.lightfound = True
            
            # if actor_class == 'StaticMeshActor':
            elif actor_class == '/Script/Engine.StaticMeshActor':
                bpy.ops.object.empty_add(type='CUBE')
                bpy.context.object.name = "ue4proxy_" + name
                i_s.staticmeshfound = True
                
            elif actor_class == 'Brush':
                i_s.objectname = name
                i_s.dopolylist = True

            elif not ue4rotation:
                bpy.ops.object.empty_add(type='PLAIN_AXES')
                bpy.context.object.name = "ue4proxy_" + name
                # add custom attribute
                bpy.context.object['proxy_smname'] = actor_class
                i_s.staticmeshfound = True

            if 'Volume' in actor_class:
                i_s.objectname = name
                i_s.volumefound = True
                i_s.dopolylist = True
                

        if dataline[0] == 'Begin' and dataline[1] == 'Brush':
            for data in dataline:
                lbltag = data.split('=')
                if lbltag[0] == 'Name':
                    i_s.meshname = lbltag[1]
                    print(lbltag[1])
            
        if dataline[0] == 'Begin' and dataline[1] == 'PolyList':
            i_s.beginpoly = True
            
        if i_s.dopolylist and i_s.beginpoly:
            readPolyList(fileline, i_s, scenescale)
            # print('back from polylist read')
            i_s.beginpoly = False
                
        if dataline[0] == 'End' and dataline[1] == 'Actor':
            if i_s.lightfound and (i_s.locationfound or i_s.rotationfound):
                # print("light transform")
                setTheTransform(i_s, scenescale, ue4rotation)
            if i_s.staticmeshfound and (i_s.locationfound or i_s.rotationfound or i_s.scalefound):
                setTheTransform(i_s, scenescale, ue4rotation)
            if i_s.dopolylist and (i_s.locationfound or i_s.rotationfound or i_s.scalefound):
                setTheTransform(i_s, scenescale, ue4rotation)
                # bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')

            # if i_s.csgadd or i_s.csgsubtract:
            # problem: for some reason som objects wont join to the mesh, they just disappear
            # duplicate keeps object visually in wireframe so can see the problem
            # if run more than once get mystery error "ReferenceError: StructRNA of type Object has been removed"
            # conclusion: needs some basic rewrite then maybe will work properly
            # also some transform is wrong - whole level moving at some point
            # Nov 1 2021 giving up - already have a working trueSpace importer, maybe need more blender python experience
            if i_s.csgadd:
                # bpy.ops.object.select_all(action='DESELECT')
                # i_s.currentObj.select_set(True)
                # bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS')
                i_s.currentObj.select_set(True)
                bpy.context.view_layer.objects.active = i_s.currentObj
                bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
                i_s.currentObj.select_set(False)
                bpy.context.object.display_type = 'WIRE'
                # bpy.ops.object.duplicate()
                # i_s.lastCSGNode.select_set(True)
                # bpy.context.view_layer.objects.active = i_s.lastCSGNode
                # selection_names = bpy.context.selected_objects
                # print (selection_names)
                # bpy.ops.object.join()
                bpy.context.view_layer.objects.active = i_s.lastCSGNode
                bpy.ops.object.modifier_add(type='BOOLEAN')
                if i_s.booleanCount == 0:
                    booName = "Boolean"
                else:
                    booName = "Boolean.{:03d}".format(i_s.booleanCount)
                bpy.context.object.modifiers[booName].object = i_s.currentObj
                # bpy.context.object.modifiers[booName].solver = 'FAST'
                # bpy.context.object.modifiers[booName].double_threshold = 0.0001
                bpy.context.object.modifiers[booName].solver = 'EXACT'
                bpy.context.object.modifiers[booName].operation = 'UNION'
                i_s.booleanCount = i_s.booleanCount + 1


            if i_s.csgsubtract:
                # bpy.context.object.hide_set(True)
                # bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS')
                i_s.currentObj.select_set(True)
                bpy.context.view_layer.objects.active = i_s.currentObj
                bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
                #scale here to attempt fix blender booleans - result, it helped, but still minor issues
                #used same techniques and fixes in tS but it did good booleans without any issues
                #tS much slower so this blender script might work better for larger scenes
                bpy.ops.object.transform_apply(location=False, rotation=False, scale=True)
                bpy.context.object.scale[0] = 1.0001
                bpy.context.object.scale[1] = 1.0001
                bpy.context.object.scale[2] = 1.0001
                i_s.currentObj.select_set(False)
                bpy.context.object.display_type = 'WIRE'

                #scale is the key to good booleans - needed some overlap
                #overwriting transform place in xfrom function
                # bpy.context.object.scale[1] = 1.0001
                # bpy.context.object.scale[0] = 1.0001
                # bpy.context.object.scale[2] = 1.0001

                # print(i_s.lastCSGNode)
                bpy.context.view_layer.objects.active = i_s.lastCSGNode
                bpy.ops.object.modifier_add(type='BOOLEAN')
                if i_s.booleanCount == 0:
                    booName = "Boolean"
                else:
                    booName = "Boolean.{:03d}".format(i_s.booleanCount)

                # TESTING APPLY BOOLEAN
                # booName = "Boolean"

                bpy.context.object.modifiers[booName].object = i_s.currentObj

                # bpy.context.object.modifiers[booName].solver = 'FAST'
                # bpy.context.object.modifiers[booName].double_threshold = 0.0001
                bpy.context.object.modifiers[booName].solver = 'EXACT'

                if i_s.csgadd:
                    bpy.context.object.modifiers[booName].operation = 'UNION'

                # TESTING APPLY BOOLEAN
                # bpy.ops.object.modifier_apply(modifier="Boolean")

                i_s.booleanCount = i_s.booleanCount + 1

            i_s.resetstate()
            # bpy.context.view_layer.update()
            # dg = bpy.context.evaluated_depsgraph_get()
            # dg.update()

            # print("end actor " + name)
            
        filelinetrim = fileline.strip()
        
        if filelinetrim == "CsgOper=CSG_Subtract":
            i_s.csgsubtract = True
            if i_s.firstCSG:
                bpy.ops.mesh.primitive_cube_add(size=2621*scenescale*4)

                bpy.context.object.name = "WorldCSG"
                i_s.lastCSGNode = bpy.context.object
                i_s.firstCSG = False


        if filelinetrim == "CsgOper=CSG_Add":
            i_s.csgadd = True
            
        if filelinetrim[0:22] == "StaticMesh=StaticMesh'":
            # print("staticmesh def found")
            # smstring = filelinetrim[22:len(filelinetrim)-1]
            smstring = filelinetrim[22:len(filelinetrim)-2]
            i_s.smtag = smstring.split('.')
            # print(i_s.smtag[1])
            bpy.context.object['proxy_smname'] = i_s.smtag[1]
            
        if filelinetrim[0:18] == 'RelativeLocation=(':
            i_s.locationfound = True
            locstring = filelinetrim[18:len(filelinetrim)-1]
            i_s.loctag = locstring.split(',')
        if filelinetrim[0:10] == 'Location=(':
            i_s.locationfound = True
            locstring = filelinetrim[10:len(filelinetrim)-1]
            i_s.loctag = locstring.split(',')
            
        if filelinetrim[0:10] == 'PrePivot=(':
            i_s.prepivotfound = True
            ppstring = filelinetrim[10:len(filelinetrim)-1]
            i_s.pptag = ppstring.split(',')

        if filelinetrim[0:18] == 'RelativeRotation=(':
            i_s.rotationfound = True
            rotstring = filelinetrim[18:len(filelinetrim)-1]
            i_s.rottag = rotstring.split(',')
        if filelinetrim[0:10] == 'Rotation=(':
            i_s.rotationfound = True
            rotstring = filelinetrim[10:len(filelinetrim)-1]
            i_s.rottag = rotstring.split(',')
            
        if filelinetrim[0:18] == 'PostScale=(Scale=(':
            i_s.drawscale3dfound = True
            scalestring = filelinetrim[18:len(filelinetrim)-1]
            tmpstr = scalestring.split(')')
            i_s.scatag = tmpstr[0].split(',')

        if filelinetrim[0:17] == 'RelativeScale3D=(':
            i_s.drawscale3dfound = True
            scalestring = filelinetrim[17:len(filelinetrim)-1]
            i_s.scatag = scalestring.split(',')
        if filelinetrim[0:13] == 'DrawScale3D=(':
            i_s.drawscale3dfound = True
            scalestring = filelinetrim[13:len(filelinetrim)-1]
            i_s.scatag = scalestring.split(',')
        if filelinetrim[0:10] == 'DrawScale=':
            i_s.drawscalefound = True
            scalestring = filelinetrim[10:len(filelinetrim)-1]
            i_s.drawscale = float(scalestring)
        
            
        
        fileline = i_s.f.readline() #end of main loop
        #print(fileline)

    i_s.f.close()


    return {'FINISHED'}


# ImportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ImportHelper
from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty
from bpy.types import Operator


class ImportT3dData(Operator, ImportHelper):
    """Import an Unreal Engine T3D scene file into Blender"""
    bl_idname = "import_t3d.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Import T3D Data"

    # ImportHelper mixin class uses this
    filename_ext = ".t3d"

    # filter_glob = StringProperty(
    filter_glob: StringProperty(
            default="*.t3d",
            options={'HIDDEN'},
            maxlen=255,  # Max internal buffer length, longer would be clamped.
            )

    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator settings before calling.
    # scenescale = FloatProperty(
    scenescale: FloatProperty(
            name="Import Scale",
            description="scale imported xyz values",
            default=0.01,
            min=0.0001
            )
            
    # ue4rotation = BoolProperty(
    ue4rotation: BoolProperty(
            name="UE4 Map",
            description="read rotations in degress",
            default=False,
            )

    type: EnumProperty(
            name="Example Enum",
            description="Choose between two items",
            items=(('OPT_A', "First Option", "Description one"),
                   ('OPT_B', "Second Option", "Description two")),
            default='OPT_A',
            )

    def execute(self, context):
        return read_some_data(context, self.filepath, self.ue4rotation, self.scenescale)


class ICR_PT_T3DPanel(bpy.types.Panel):
    bl_label = "T3D Utilities"
    bl_idname = "ICR_PT_T3DPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Clintons3D'

    def draw(self, context):
      layout = self.layout
      row = layout.row()

      row.operator('icr.replacestaticmesh', text = 'Replace StaticMesh')

class ICR_OT_ReplaceStaticMeshProxies(bpy.types.Operator):
    """ Replace static mesh proxies with actual meshes """
    bl_idname = 'icr.replacestaticmesh'
    #this is the label that essentially is the text displayed on the button
    bl_label = 'Center To Selection Op'

    def execute(self, context):
        print("start copy")
        for ob in context.scene.objects:
        # for ob in bpy.context.scene.collection.objects:
            #check for proxy_smname custom property
            if "proxy_smname" in ob:
                smname = ob["proxy_smname"]
                src_obj = bpy.data.objects.get(smname)
                if src_obj is None:
                    continue
                print("found object")
                bpy.ops.object.select_all(action='DESELECT')
                bpy.ops.object.select_pattern(pattern=smname)
                # bpy.context.scene.objects.active = bpy.context.selected_objects[0]
                bpy.context.view_layer.objects.active = bpy.context.selected_objects[0]
                #remove ue4proxy_ prefix
                actualname = ob.name[9:len(ob.name)]
                print(ob.name," ",actualname," ", bpy.context.selected_objects[0])
                
                #don't copy if scene mesh name is same as staticmesh name
                if actualname == smname:
                    new_obj = src_obj
                else:
                    new_obj = src_obj.copy()
                    new_obj.data = src_obj.data.copy()
                    new_obj.name = actualname
                    # context.scene.objects.link(new_obj) 
                    bpy.context.scene.collection.objects.link(new_obj)
                
                #copy transforms
                new_obj.location = ob.location
                new_obj.rotation_euler = ob.rotation_euler
                new_obj.scale = ob.scale
                
        print("start delete t3d proxies")
        bpy.ops.object.select_all(action='DESELECT')
        for ob in context.scene.objects:
        # for ob in bpy.context.scene.collection.objects:
            #check for proxy_smname custom property
            if "proxy_smname" in ob:
                smname = ob["proxy_smname"]
                src_obj = bpy.data.objects.get(smname)
                if src_obj is None:
                    continue
                print("found object")
                
                # ob.select = True
                ob.select_set(True)
                # bpy.context.scene.collection.objects[0].select_set(True)
                

        bpy.ops.object.delete()

        #return value that tells blender we finished without failure
        return {'FINISHED'}

#panel draw is run when mouse events - not just at creation time
class ICR_PT_CenterViewPanel(bpy.types.Panel):
   bl_label = "Center To Selection"
   bl_idname = "ICR_PT_CenterToSelectionPanel"
   bl_space_type = 'VIEW_3D'
   bl_region_type = 'UI'
   bl_category = 'Clintons3D'

   def draw(self, context):
      layout = self.layout

      row = layout.row()

      row.operator('icr.centertoselection', text = 'Center')

class ICR_OT_CenterToSelection(bpy.types.Operator):
   """ Cancel the operation """
   bl_idname = 'icr.centertoselection'
   #this is the label that essentially is the text displayed on the button
   bl_label = 'Center To Selection Op'

   def execute(self, context):
      previousCursorMatrix = bpy.context.scene.cursor.matrix
      bpy.ops.view3d.snap_cursor_to_selected()
      bpy.ops.view3d.view_center_cursor()
      bpy.context.scene.cursor.matrix = previousCursorMatrix


      #return value that tells blender we finished without failure
      return {'FINISHED'}


# Only needed if you want to add into a dynamic menu
def menu_func_import(self, context):
    self.layout.operator(ImportT3dData.bl_idname, text="T3D Import Operator")

classes = (
    ImportT3dData,
    ICR_PT_CenterViewPanel,
    ICR_OT_CenterToSelection,
    ICR_PT_T3DPanel,
    ICR_OT_ReplaceStaticMeshProxies,
)

def register():
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)
    bpy.types.TOPBAR_MT_file_import.append(menu_func_import)


def unregister():
    from bpy.utils import unregister_class
    for cls in reversed(classes):
        unregister_class(cls)
    bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)

# def register():
#     bpy.utils.register_class(ImportT3dData)
#     # bpy.types.INFO_MT_file_import.append(menu_func_import)
#     bpy.types.TOPBAR_MT_file_import.append(menu_func_import)


# def unregister():
#     bpy.utils.unregister_class(ImportT3dData)
#     # bpy.types.INFO_MT_file_import.remove(menu_func_import)
#     bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)


if __name__ == "__main__":
    register()

    # test call
    # bpy.ops.import_t3d.some_data('INVOKE_DEFAULT')
